├── .eslintrc ├── .github └── workflows │ ├── node-aught.yml │ ├── node-pretest.yml │ ├── node-tens.yml │ ├── rebase.yml │ └── require-allow-edits.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── .nycrc ├── .travis.yml ├── CHANGELOG.md ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── component.json ├── es6-sham.js ├── es6-sham.map ├── es6-sham.min.js ├── es6-shim.js ├── es6-shim.map ├── es6-shim.min.js ├── node_modules ├── chai │ └── chai.js ├── es5-shim │ └── es5-shim.js ├── mocha │ ├── mocha.css │ └── mocha.js └── promises-es6-tests │ └── bundle │ └── promises-es6-tests.js ├── package.json ├── test-sham ├── function.js ├── index.html └── set-prototype-of.js ├── test ├── array.js ├── browser-onload.js ├── browser-setup.js ├── date.js ├── google-translate.html ├── index.html ├── json.js ├── map.js ├── math.js ├── mocha.opts ├── native.html ├── number.js ├── object.js ├── promise.js ├── promise │ ├── all.js │ ├── evil-promises.js │ ├── promises-aplus.js │ ├── promises-es6.js │ ├── race.js │ ├── reject.js │ ├── resolve.js │ ├── simple.js │ └── subclass.js ├── reflect.js ├── regexp.js ├── set.js ├── string.js ├── test_helpers.js ├── worker-runner.workerjs └── worker-test.js └── testling.html /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | 4 | "extends": "@ljharb", 5 | 6 | "ignorePatterns": [ 7 | "Gruntfile.js", 8 | "*.min.js", 9 | ], 10 | 11 | "rules": { 12 | "array-bracket-newline": [0], 13 | "array-element-newline": [0], 14 | "callback-return": [0], 15 | "complexity": [1], 16 | "consistent-return": [1], 17 | "eqeqeq": [2, "allow-null"], 18 | "func-name-matching": [0], 19 | "global-require": [0], 20 | "id-length": [2, { "min": 1, "max": 40 }], 21 | "indent": [2, 2], 22 | "max-depth": [2, 5], 23 | "max-len": 0, 24 | "max-lines": [1], 25 | "max-lines-per-function": [0], 26 | "max-params": [2, 4], 27 | "max-statements": [1, 25], 28 | "max-statements-per-line": [2, { "max": 2 }], 29 | "multiline-comment-style": [0], 30 | "new-cap": [2, { "capIsNewExceptions": ["Call", "Construct", "CreateHTML", "GetIterator", "GetMethod", "IsCallable", "IsConstructor", "IsPromise", "IsRegExp", "IteratorClose", "IteratorComplete", "IteratorNext", "IteratorStep", "Map", "OrigNumber", "RequireObjectCoercible", "SameValue", "SameValueZero", "Set", "SpeciesConstructor", "ToInteger", "ToLength", "ToNumber", "ToObject", "ToString", "ToUint32", "TypeIsObject"] }], 31 | "no-constant-condition": [1], 32 | "no-extend-native": [2, { "exceptions": ["Set"] }], 33 | "no-extra-parens": 0, 34 | "no-implicit-coercion": [2, { 35 | "boolean": false, 36 | "number": false, 37 | "string": true 38 | }], 39 | "no-invalid-this": [0], 40 | "no-loss-of-precision": [1], 41 | "no-native-reassign": [2, { "exceptions": ["Number", "Promise", "RegExp"] }], 42 | "no-negated-condition": [1], 43 | "no-param-reassign": [1], 44 | "no-plusplus": [1], 45 | "no-restricted-syntax": [2, "DebuggerStatement", "LabeledStatement", "WithStatement"], 46 | "no-shadow": [1], 47 | "no-underscore-dangle": [0], 48 | "no-unused-vars": [1, { "vars": "all", "args": "after-used" }], 49 | "no-use-before-define": [1], 50 | "no-useless-call": [0], 51 | "object-curly-newline": [1], 52 | "sort-keys": [0], 53 | "spaced-comment": [0], 54 | "strict": [0] 55 | }, 56 | "overrides": [ 57 | { 58 | "files": "test/**", 59 | "env": { 60 | "browser": true, 61 | "mocha": true, 62 | }, 63 | "globals": { 64 | "assert": false, 65 | "expect": false, 66 | "chai": false, 67 | }, 68 | "rules": { 69 | "array-callback-return": 0, 70 | "func-name-matching": 0, 71 | "max-lines-per-function": 0, 72 | "max-statements-per-line": [2, { "max": 2 }], 73 | "no-restricted-properties": 1, 74 | "symbol-description": 0, 75 | "prefer-promise-reject-errors": 0, 76 | "consistent-return": 0, 77 | }, 78 | }, 79 | { 80 | "files": "test-sham/**", 81 | "env": { 82 | "mocha": true, 83 | }, 84 | "globals": { 85 | "expect": false, 86 | }, 87 | "rules": { 88 | "max-nested-callbacks": [2, 5], 89 | }, 90 | } 91 | ] 92 | } 93 | -------------------------------------------------------------------------------- /.github/workflows/node-aught.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js < 10' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | tests: 7 | uses: ljharb/actions/.github/workflows/node.yml@main 8 | with: 9 | range: '< 10' 10 | type: minors 11 | command: npm run tests-only 12 | 13 | node: 14 | name: 'node < 10' 15 | needs: [tests] 16 | runs-on: ubuntu-latest 17 | steps: 18 | - run: 'echo tests completed' 19 | -------------------------------------------------------------------------------- /.github/workflows/node-pretest.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: pretest/posttest' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | tests: 7 | uses: ljharb/actions/.github/workflows/pretest.yml@main 8 | -------------------------------------------------------------------------------- /.github/workflows/node-tens.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js >= 10' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | tests: 7 | uses: ljharb/actions/.github/workflows/node.yml@main 8 | with: 9 | range: '>= 10' 10 | type: minors 11 | command: NODE_OPTIONS=--unhandled-rejections=none node -pe '' 2>/dev/null && NODE_OPTIONS=--unhandled-rejections=none npm run tests-only || npm run tests-only 12 | 13 | node: 14 | name: 'node >= 10' 15 | needs: [tests] 16 | runs-on: ubuntu-latest 17 | steps: 18 | - run: 'echo tests completed' 19 | -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | name: Automatic Rebase 2 | 3 | on: [pull_request_target] 4 | 5 | jobs: 6 | _: 7 | name: "Automatic Rebase" 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: ljharb/rebase@master 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | -------------------------------------------------------------------------------- /.github/workflows/require-allow-edits.yml: -------------------------------------------------------------------------------- 1 | name: Require “Allow Edits” 2 | 3 | on: [pull_request_target] 4 | 5 | jobs: 6 | _: 7 | name: "Require “Allow Edits”" 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: ljharb/require-allow-edits@main 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | 3 | .DS_Store 4 | node_modules/ 5 | 6 | # Only apps should have lockfiles 7 | npm-shrinkwrap.json 8 | package-lock.json 9 | yarn.lock 10 | 11 | coverage/ 12 | .nyc_output/ 13 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | .travis.yml 4 | testling.html 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "all": true, 3 | "check-coverage": false, 4 | "reporter": ["text-summary", "text", "html", "json"], 5 | "exclude": [ 6 | "Gruntfile.js", 7 | "*.min.js", 8 | "coverage", 9 | "test", 10 | "test-sham" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | os: 3 | - linux 4 | before_install: 5 | - 'if [ -n "${SAUCE-}" ]; then npm install -g grunt-cli; fi' 6 | script: 7 | - 'if [ -n "${SAUCE-}" ]; then npm run sauce; fi' 8 | # NOTE: sauce_connect is disabled, because it applies to every test and we only need it on one of them. 9 | # It's available inside `npm run sauce` 10 | # addons: 11 | # sauce_connect: true 12 | matrix: 13 | fast_finish: true 14 | include: 15 | - node_js: "lts/*" 16 | env: SAUCE=true 17 | allow_failures: 18 | - env: SAUCE=true 19 | env: 20 | global: 21 | - secure: YD4HLTE93NhSxa+64MYHhnbJ2ZkREp/HGiFGE4q+AWShqAiehtqE/K3hQUe7p0+1/2/34avhm2bz31j508ayCobm6SSUhpleJH58IK3v4LI2o9qtM+2N/MPJFOIvbziHqOM6fPluowU0k3OSdEAp4U+6S23wKSuXzcUSK8upAiM= 22 | - secure: k7+PgLcGJL1zyMMxZ8DSRxRrmLr5sb9i4M1kCdUvw2kRGacqoI3UhdvO2AyrAD0TAjIQoRM4dL37WsgJijhTNOu1gTb5lMUXWSQU47T7tFTvpM6OlGvQ54I7iAgv5NABZ/0gDGlQDrVdb9hQPLG1FDrMxsxcdXfgXqzqbhNsv7I= 23 | - SAUCE_HAS_TUNNEL=true 24 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function (grunt) { 4 | var browsers = [ 5 | { browserName: 'firefox', version: '19', platform: 'XP' }, 6 | { browserName: 'firefox', platform: 'linux' }, 7 | { browserName: 'firefox', platform: 'OS X 10.10' }, 8 | { browserName: 'chrome', platform: 'linux' }, 9 | { browserName: 'chrome', platform: 'OS X 10.9' }, 10 | { browserName: 'chrome', platform: 'XP' }, 11 | { browserName: 'internet explorer', platform: 'Windows 8.1', version: '11' }, 12 | { browserName: 'internet explorer', platform: 'WIN8', version: '10' }, 13 | { browserName: 'internet explorer', platform: 'VISTA', version: '9' }, 14 | { browserName: 'safari', platform: 'OS X 10.6' }, 15 | { browserName: 'safari', platform: 'OS X 10.8' }, 16 | { browserName: 'safari', platform: 'OS X 10.9' }, 17 | { browserName: 'safari', platform: 'OS X 10.10' }, 18 | { browserName: 'iphone', platform: 'OS X 10.9', version: '7.1' }, 19 | { browserName: 'android', platform: 'Linux', version: '4.4' }, 20 | ]; 21 | var extraBrowsers = [ 22 | { browserName: 'firefox', platform: 'linux', version: '30' }, 23 | { browserName: 'firefox', platform: 'linux', version: '25' }, 24 | { browserName: 'iphone', platform: 'OS X 10.8', version: '6.1' }, 25 | { browserName: 'iphone', platform: 'OS X 10.8', version: '5.1' }, 26 | { browserName: 'android', platform: 'Linux', version: '4.2' }, 27 | // XXX haven't investigated these: 28 | // { browserName: 'opera', platform: 'Windows 7', version: '12' }, 29 | // { browserName: 'opera', platform: 'Windows 2008', version: '12' } 30 | // { browserName: 'iphone', platform: 'OS X 10.6', version: '4.3' }, 31 | // { browserName: 'android', platform: 'Linux', version: '4.0' }, 32 | ]; 33 | if (grunt.option('extra')) { 34 | browsers = browsers.concat(extraBrowsers); 35 | } 36 | grunt.initConfig({ 37 | connect: { 38 | server: { 39 | options: { 40 | base: '', 41 | port: 9999, 42 | useAvailablePort: true 43 | } 44 | } 45 | }, 46 | 'saucelabs-mocha': { 47 | all: { 48 | options: { 49 | urls: (function () { 50 | var urls = ['http://localhost:9999/test/']; 51 | if (grunt.option('extra')) { 52 | urls.push('http://localhost:9999/test-sham/'); 53 | } 54 | return urls; 55 | }()), 56 | // tunnelTimeout: 5, 57 | build: process.env.TRAVIS_BUILD_NUMBER, 58 | tunneled: !process.env.SAUCE_HAS_TUNNEL, 59 | identifier: process.env.TRAVIS_JOB_NUMBER, 60 | sauceConfig: { 61 | 'tunnel-identifier': process.env.TRAVIS_JOB_NUMBER 62 | }, 63 | // concurrency: 3, 64 | browsers: browsers, 65 | testname: (function () { 66 | var testname = 'mocha'; 67 | if (process.env.TRAVIS_PULL_REQUEST && process.env.TRAVIS_PULL_REQUEST !== 'false') { 68 | testname += ' (PR ' + process.env.TRAVIS_PULL_REQUEST + ')'; 69 | } 70 | if (process.env.TRAVIS_BRANCH && process.env.TRAVIS_BRANCH !== 'false') { 71 | testname += ' (branch ' + process.env.TRAVIS_BRANCH + ')'; 72 | } 73 | return testname; 74 | }()), 75 | tags: (function () { 76 | var tags = []; 77 | if (process.env.TRAVIS_PULL_REQUEST && process.env.TRAVIS_PULL_REQUEST !== 'false') { 78 | tags.push('PR-' + process.env.TRAVIS_PULL_REQUEST); 79 | } 80 | if (process.env.TRAVIS_BRANCH && process.env.TRAVIS_BRANCH !== 'false') { 81 | tags.push(process.env.TRAVIS_BRANCH); 82 | } 83 | return tags; 84 | }()) 85 | } 86 | } 87 | }, 88 | watch: {} 89 | }); 90 | // Loading dependencies 91 | for (var key in grunt.file.readJSON('package.json').devDependencies) { 92 | if (key !== 'grunt' && key.indexOf('grunt') === 0) { 93 | grunt.loadNpmTasks(key); 94 | } 95 | } 96 | grunt.registerTask('dev', ['connect', 'watch']); 97 | grunt.registerTask('sauce', ['connect', 'saucelabs-mocha']); 98 | }; 99 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Paul Miller (https://paulmillr.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 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ES6 Shim [![Version Badge][npm-version-svg]][package-url] 2 | Provides compatibility shims so that legacy JavaScript engines behave as 3 | closely as possible to ECMAScript 6 (Harmony). 4 | 5 | [![github actions][actions-image]][actions-url] 6 | [![coverage][codecov-image]][codecov-url] 7 | [![License][license-image]][license-url] 8 | [![Downloads][downloads-image]][downloads-url] 9 | 10 | [![npm badge][npm-badge-png]][package-url] 11 | 12 | 13 | 14 | 15 | 16 | [HTML version of the final ECMAScript 6 spec][spec-html-url] 17 | 18 | ## Installation 19 | If you want to use it in browser: 20 | 21 | * Just include `es6-shim` before your scripts. 22 | * Include [es5-shim][es5-shim-url] especially if your browser doesn't support ECMAScript 5 - but every JS engine requires the `es5-shim` to correct broken implementations, so it's strongly recommended to always include it. Additionally, `es5-shim` should be loaded before `es6-shim`. 23 | 24 | For `node.js`, `io.js`, or any `npm`-managed workflow (this is the recommended method): 25 | 26 | npm install es6-shim 27 | 28 | Alternative methods: 29 | * `component install paulmillr/es6-shim` if you’re using [component(1)](https://github.com/componentjs/component). 30 | * `bower install es6-shim` if you’re using [Bower](http://bower.io/). 31 | 32 | In both browser and node you may also want to include `unorm`; see the [`String.prototype.normalize`](#stringprototypenormalize) section for details. 33 | 34 | ## Safe shims 35 | 36 | * `Map` (requires ES5 property descriptor support) ([a standalone shim is also available](https://npmjs.com/es-map)) 37 | * `Set` (requires ES5 property descriptor support) ([a standalone shim is also available](https://npmjs.com/es-set)) 38 | * `Promise` 39 | * `String`: 40 | * `fromCodePoint()` ([a standalone shim is also available](https://npmjs.com/string.fromcodepoint)) 41 | * `raw()` ([a stanadlone shim is also available](https://www.npmjs.com/package/string.raw)) 42 | * `String.prototype`: 43 | * `codePointAt()` ([a standalone shim is also available](https://npmjs.com/string.prototype.codepointat)) 44 | * `endsWith()` ([a standalone shim is also available](https://npmjs.com/string.prototype.endswith)) 45 | * `includes()` ([a standalone shim is also available](https://npmjs.com/string.prototype.includes)) 46 | * `repeat()` ([a standalone shim is also available](https://npmjs.com/string.prototype.repeat)) 47 | * `startsWith()` ([a standalone shim is also available](https://npmjs.com/string.prototype.startswith)) 48 | * `RegExp`: 49 | * `new RegExp`, when given a RegExp as the pattern, will no longer throw when given a "flags" string argument. (requires ES5) 50 | * `RegExp.prototype`: 51 | * `flags` (requires ES5) ([a standalone shim is also available](https://npmjs.com/regexp.prototype.flags)) 52 | * `[Symbol.match]` (requires native `Symbol`s) 53 | * `[Symbol.replace]` (requires native `Symbol`s) 54 | * `[Symbol.search]` (requires native `Symbol`s) 55 | * `[Symbol.split]` (requires native `Symbol`s) 56 | * `toString` 57 | * `Number`: 58 | * binary and octal literals: `Number('0b1')` and `Number('0o7')` 59 | * `EPSILON` ([a standalone shim is also available](https://www.npmjs.com/package/es-constants)) 60 | * `MAX_SAFE_INTEGER` ([a standalone shim is also available](https://www.npmjs.com/package/es-constants)) 61 | * `MIN_SAFE_INTEGER` ([a standalone shim is also available](https://www.npmjs.com/package/es-constants)) 62 | * `isNaN()` ([a standalone shim is also available](https://www.npmjs.com/package/is-nan)) 63 | * `isInteger()` ([a standalone shim is also available](https://www.npmjs.com/package/number.isinteger)) 64 | * `isSafeInteger()`([a standalone shim is also available](https://www.npmjs.com/package/number.issafeinteger)) 65 | * `isFinite()` ([a standalone shim is also available](https://www.npmjs.com/package/number.isfinite)) 66 | * `parseInt()` ([a standalone shim is also available](https://www.npmjs.com/package/parseint)) 67 | * `parseFloat()` 68 | * `Array`: 69 | * `from()` ([a standalone shim is also available](https://www.npmjs.com/package/array.from)) 70 | * `of()` ([a standalone shim is also available](https://www.npmjs.com/package/array.of)) 71 | * `Array.prototype`: 72 | * `copyWithin()` ([a standalone shim is also available](https://npmjs.com/array.prototype.copywithin)) 73 | * `entries()` ([a standalone shim is also available](https://npmjs.com/array.prototype.entries)) 74 | * `fill()` 75 | * `find()` ([a standalone shim is also available](https://npmjs.com/array.prototype.find)) 76 | * `findIndex()` ([a standalone shim is also available](https://npmjs.com/array.prototype.findindex)) 77 | * `keys()` ([a standalone shim is also available](https://npmjs.com/array.prototype.keys)) 78 | * `values()` ([a standalone shim is also available](https://npmjs.com/array.prototype.values)) 79 | * `indexOf()` (ES6 errata) ([a standalone shim is also available](https://npmjs.com/array.prototype.indexof)) 80 | * `Object`: 81 | * `assign()` ([a standalone shim is also available](https://npmjs.com/object.assign)) 82 | * `is()` ([a standalone shim is also available](https://npmjs.com/object-is)) 83 | * `keys()` (in ES5, but no longer throws on non-object non-null/undefined values in ES6) ([a standalone shim is also available](https://npmjs.com/object-keys) 84 | * `setPrototypeOf()` (IE >= 11) 85 | * `Function.prototype`: 86 | * `name` (es6-sham, covers IE 9-11) ([a standalone shim is also available](https://npmjs.com/function.prototype.name) 87 | * `Math`: 88 | * `acosh()` ([a standalone shim is also available](https://npmjs.com/math.acosh)) 89 | * `asinh()` 90 | * `atanh()` ([a standalone shim is also available](https://npmjs.com/math.atanh)) 91 | * `cbrt()` ([a standalone shim is also available](https://npmjs.com/math.cbrt)) 92 | * `clz32()` ([a standalone shim is also available](https://npmjs.com/math.clz32)) 93 | * `cosh()` 94 | * `expm1()` 95 | * `fround()` ([a standalone shim is also available](https://npmjs.com/math.fround)) 96 | * `hypot()` 97 | * `imul()` ([a standalone shim is also available](https://npmjs.com/math.imul)) 98 | * `log10()` ([a standalone shim is also available](https://npmjs.com/math.log10)) 99 | * `log1p()` ([a standalone shim is also available](https://npmjs.com/math.log1p)) 100 | * `log2()` 101 | * `sign()` ([a standalone shim is also available](https://npmjs.com/math.sign)) 102 | * `sinh()` 103 | * `tanh()` 104 | * `trunc()` 105 | 106 | Math functions’ accuracy is 1e-11. 107 | 108 | * `Reflect` 109 | * `apply()` ([a standalone shim is also available](https://npmjs.com/reflect.apply)) 110 | * `construct()` 111 | * `defineProperty()` 112 | * `deleteProperty()` 113 | * `get()` 114 | * `getOwnPropertyDescriptor()` 115 | * `getPrototypeOf()` ([a standalone shim is also available](https://npmjs.com/reflect.getprototypeof)) 116 | * `has()` 117 | * `isExtensible()` 118 | * `ownKeys()` ([a standalone shim is also available](https://npmjs.com/reflect.ownkeys)) 119 | * `preventExtensions()` 120 | * `set()` 121 | * `setPrototypeOf()` 122 | 123 | * `Symbol` (only if it already exists) 124 | * `match` (and corresponding `String#match`, `String#startsWith`, `String#endsWith`, `String#includes`, `RegExp` support) 125 | * `replace` (and corresponding `String#replace` support) 126 | * `search` (and corresponding `String#search` support) 127 | * `split` (and corresponding `String#split` support) 128 | 129 | Well-known symbols will only be provided if the engine already has `Symbol` support. 130 | 131 | * `String.prototype` Annex B HTML methods ([a standalone shim is also available](https://www.npmjs.com/package/es-string-html-methods)) 132 | * `anchor()` 133 | * `big()` 134 | * `blink()` 135 | * `bold()` 136 | * `fixed()` 137 | * `fontcolor()` 138 | * `fontsize()` 139 | * `italics()` 140 | * `link()` 141 | * `small()` 142 | * `strike()` 143 | * `sub()` 144 | * `sup()` 145 | 146 | These methods are part of "Annex B", which means that although they are a defacto standard, you shouldn't use them. None the less, the `es6-shim` provides them and normalizes their behavior across browsers. 147 | 148 | ## Subclassing 149 | The `Map`, `Set`, and `Promise` implementations are subclassable. 150 | You should use the following pattern to create a subclass in ES5 which will continue to work in ES6: 151 | ```javascript 152 | require('es6-shim'); 153 | 154 | function MyPromise(exec) { 155 | var promise = new Promise(exec); 156 | Object.setPrototypeOf(promise, MyPromise.prototype); 157 | // ... 158 | return promise; 159 | } 160 | Object.setPrototypeOf(MyPromise, Promise); 161 | MyPromise.prototype = Object.create(Promise.prototype, { 162 | constructor: { value: MyPromise } 163 | }); 164 | ``` 165 | 166 | ## String.prototype.normalize 167 | Including a proper shim for `String.prototype.normalize` would increase the size of this library by a factor of more than 4. 168 | So instead we recommend that you install the [`unorm`](https://github.com/walling/unorm) package alongside `es6-shim` if you need `String.prototype.normalize`. 169 | See https://github.com/paulmillr/es6-shim/issues/134 for more discussion. 170 | 171 | 172 | ## WeakMap shim 173 | It is not possible to implement WeakMap in pure javascript. 174 | The [es6-collections](https://github.com/WebReflection/es6-collections) implementation doesn't hold values strongly, which is critical for the collection. `es6-shim` decided to not include an incorrect shim. 175 | 176 | `WeakMap` has very unusual use-cases, so you probably won't need it at all (use simple `Map` instead). 177 | 178 | ## Getting started 179 | 180 | ```javascript 181 | require('es6-shim'); 182 | var assert = require('assert'); 183 | 184 | assert.equal(true, 'abc'.startsWith('a')); 185 | assert.equal(false, 'abc'.endsWith('a')); 186 | assert.equal(true, 'john alice'.includes('john')); 187 | assert.equal('123'.repeat(2), '123123'); 188 | 189 | assert.equal(false, NaN === NaN); 190 | assert.equal(true, Object.is(NaN, NaN)); 191 | assert.equal(true, -0 === 0); 192 | assert.equal(false, Object.is(-0, 0)); 193 | 194 | var result = Object.assign({ a: 1 }, { b: 2 }); 195 | assert.deepEqual(result, { a: 1, b: 2 }); 196 | 197 | assert.equal(true, isNaN('a')); 198 | assert.equal(false, Number.isNaN('a')); 199 | assert.equal(true, Number.isNaN(NaN)); 200 | 201 | assert.equal(true, isFinite('123')); 202 | assert.equal(false, Number.isFinite('123')); 203 | assert.equal(false, Number.isFinite(Infinity)); 204 | 205 | // Tests if value is a number, finite, 206 | // >= -9007199254740992 && <= 9007199254740992 and floor(value) === value 207 | assert.equal(false, Number.isInteger(2.4)); 208 | 209 | assert.equal(1, Math.sign(400)); 210 | assert.equal(0, Math.sign(0)); 211 | assert.equal(-1, Math.sign(-400)); 212 | 213 | var found = [5, 10, 15, 10].find(function (item) { return item / 2 === 5; }); 214 | assert.equal(10, found); 215 | 216 | var foundIndex = [5, 10, 15, 10].findIndex(function (item) { return item / 2 === 5; }); 217 | assert.equal(1, foundIndex); 218 | 219 | // Replacement for `{}` key-value storage. 220 | // Keys can be anything. 221 | var map = new Map([['Bob', 42], ['Foo', 'bar']]); 222 | map.set('John', 25); 223 | map.set('Alice', 400); 224 | map.set(['meh'], 555); 225 | assert.equal(undefined, map.get(['meh'])); // undefined because you need to use exactly the same object. 226 | map.delete('Alice'); 227 | map.keys(); 228 | map.values(); 229 | assert.equal(4, map.size); 230 | 231 | // Useful for storing unique items. 232 | var set = new Set([0, 1]); 233 | set.add(2); 234 | set.add(5); 235 | assert.equal(true, set.has(0)); 236 | assert.equal(true, set.has(1)); 237 | assert.equal(true, set.has(2)); 238 | assert.equal(false, set.has(4)); 239 | assert.equal(true, set.has(5)); 240 | set.delete(5); 241 | assert.equal(false, set.has(5)); 242 | 243 | // Promises, see 244 | // http://www.slideshare.net/domenicdenicola/callbacks-promises-and-coroutines-oh-my-the-evolution-of-asynchronicity-in-javascript 245 | // https://github.com/petkaantonov/bluebird/#what-are-promises-and-why-should-i-use-them 246 | Promise.resolve(5).then(function (value) { 247 | assert.equal(value, 5); 248 | if (value) throw new Error('whoops!'); 249 | // do some stuff 250 | return anotherPromise(); 251 | }).catch(function (e) { 252 | assert.equal(e.message, 'whoops!'); 253 | assert.equal(true, e instanceof Error); 254 | // any errors thrown asynchronously end up here 255 | }); 256 | ``` 257 | 258 | ## Caveats 259 | 260 | - `Object.setPrototypeOf` / `Reflect.setPrototypeOf` 261 | - Note that null objects (`Object.create(null)`, eg, an object with `null` as its `[[Prototype]]`) can not have their `[[Prototype]]` changed except via a native `Object.setPrototypeOf`. 262 | - Well-known `Symbol`s 263 | - In order to make them work cross-realm, these are created with the global `Symbol` registry via `Symbol.for`. This does not violate the spec, but it does mean that `Symbol.for('Symbol.search') === Symbol.search` will be `true`, which it would not by default in a fresh compliant realm. 264 | 265 | ## [License][license-url] 266 | 267 | The project was initially based on es6-shim by Axel Rauschmayer. 268 | 269 | [license-url]: https://github.com/paulmillr/es6-shim/blob/master/LICENSE 270 | [spec-html-url]: http://www.ecma-international.org/ecma-262/6.0/ 271 | [es5-shim-url]: https://github.com/es-shims/es5-shim 272 | 273 | [package-url]: https://npmjs.org/package/es6-shim 274 | [npm-version-svg]: https://versionbadg.es/paulmillr/es6-shim.svg 275 | [deps-svg]: https://david-dm.org/paulmillr/es6-shim.svg 276 | [deps-url]: https://david-dm.org/paulmillr/es6-shim 277 | [dev-deps-svg]: https://david-dm.org/paulmillr/es6-shim/dev-status.svg 278 | [dev-deps-url]: https://david-dm.org/paulmillr/es6-shim#info=devDependencies 279 | [npm-badge-png]: https://nodei.co/npm/es6-shim.png?downloads=true&stars=true 280 | [license-image]: https://img.shields.io/npm/l/es6-shim.svg 281 | [license-url]: LICENSE 282 | [downloads-image]: https://img.shields.io/npm/dm/es6-shim.svg 283 | [downloads-url]: https://npm-stat.com/charts.html?package=es6-shim 284 | [codecov-image]: https://codecov.io/gh/paulmillr/es6-shim/branch/main/graphs/badge.svg 285 | [codecov-url]: https://app.codecov.io/gh/paulmillr/es6-shim/ 286 | [actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/paulmillr/es6-shim 287 | [actions-url]: https://github.com/paulmillr/es6-shim/actions 288 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es6-shim", 3 | "repo": "paulmillr/es6-shim", 4 | "description": "ECMAScript 6 (Harmony) compatibility shims for legacy JavaScript engines", 5 | "keywords": [ 6 | "ecmascript", 7 | "harmony", 8 | "es6", 9 | "shim", 10 | "promise", 11 | "promises", 12 | "setPrototypeOf", 13 | "map", 14 | "set", 15 | "__proto__" 16 | ], 17 | "main": "es6-shim.js", 18 | "scripts": ["es6-shim.js"], 19 | "dependencies": {}, 20 | "development": {}, 21 | "ignore": [ 22 | "**/.*", 23 | "node_modules", 24 | "components", 25 | "test" 26 | ] 27 | } 28 | 29 | -------------------------------------------------------------------------------- /component.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es6-shim", 3 | "version": "0.35.3", 4 | "repo": "paulmillr/es6-shim", 5 | "description": "ECMAScript 6 (Harmony) compatibility shims for legacy JavaScript engines", 6 | "keywords": [ 7 | "ecmascript", 8 | "harmony", 9 | "es6", 10 | "shim", 11 | "promise", 12 | "promises", 13 | "setPrototypeOf", 14 | "map", 15 | "set", 16 | "__proto__" 17 | ], 18 | "main": "es6-shim.js", 19 | "scripts": ["es6-shim.js"], 20 | "dependencies": {}, 21 | "development": {} 22 | } 23 | 24 | -------------------------------------------------------------------------------- /es6-sham.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * https://github.com/paulmillr/es6-shim 3 | * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com) 4 | * and contributors, MIT License 5 | * es6-sham: v0.35.4 6 | * see https://github.com/paulmillr/es6-shim/blob/0.35.3/LICENSE 7 | * Details and documentation: 8 | * https://github.com/paulmillr/es6-shim/ 9 | */ 10 | 11 | // UMD (Universal Module Definition) 12 | // see https://github.com/umdjs/umd/blob/master/returnExports.js 13 | (function (root, factory) { 14 | /*global define */ 15 | if (typeof define === 'function' && define.amd) { 16 | // AMD. Register as an anonymous module. 17 | define(factory); 18 | } else if (typeof exports === 'object') { 19 | // Node. Does not work with strict CommonJS, but 20 | // only CommonJS-like environments that support module.exports, 21 | // like Node. 22 | module.exports = factory(); 23 | } else { 24 | // Browser globals (root is window) 25 | root.returnExports = factory(); 26 | } 27 | }(this, function () { 28 | 'use strict'; 29 | 30 | /* eslint-disable no-new-func */ 31 | var getGlobal = new Function('return this;'); 32 | /* eslint-enable no-new-func */ 33 | 34 | var globals = getGlobal(); 35 | var Object = globals.Object; 36 | var _call = Function.call.bind(Function.call); 37 | var functionToString = Function.toString; 38 | var _strMatch = String.prototype.match; 39 | 40 | var throwsError = function (func) { 41 | try { 42 | func(); 43 | return false; 44 | } catch (e) { 45 | return true; 46 | } 47 | }; 48 | var arePropertyDescriptorsSupported = function () { 49 | // if Object.defineProperty exists but throws, it's IE 8 50 | return !throwsError(function () { 51 | Object.defineProperty({}, 'x', { get: function () {} }); // eslint-disable-line getter-return 52 | }); 53 | }; 54 | var supportsDescriptors = !!Object.defineProperty && arePropertyDescriptorsSupported(); 55 | 56 | // NOTE: This versions needs object ownership 57 | // because every promoted object needs to be reassigned 58 | // otherwise uncompatible browsers cannot work as expected 59 | // 60 | // NOTE: This might need es5-shim or polyfills upfront 61 | // because it's based on ES5 API. 62 | // (probably just an IE <= 8 problem) 63 | // 64 | // NOTE: nodejs is fine in version 0.8, 0.10, and future versions. 65 | (function () { 66 | if (Object.setPrototypeOf) { return; } 67 | 68 | // @author Andrea Giammarchi - @WebReflection 69 | 70 | var getOwnPropertyNames = Object.getOwnPropertyNames; 71 | var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; 72 | var create = Object.create; 73 | var defineProperty = Object.defineProperty; 74 | var getPrototypeOf = Object.getPrototypeOf; 75 | var objProto = Object.prototype; 76 | 77 | var copyDescriptors = function (target, source) { 78 | // define into target descriptors from source 79 | getOwnPropertyNames(source).forEach(function (key) { 80 | defineProperty( 81 | target, 82 | key, 83 | getOwnPropertyDescriptor(source, key) 84 | ); 85 | }); 86 | return target; 87 | }; 88 | // used as fallback when no promotion is possible 89 | var createAndCopy = function (origin, proto) { 90 | return copyDescriptors(create(proto), origin); 91 | }; 92 | var set, setPrototypeOf; 93 | try { 94 | // this might fail for various reasons 95 | // ignore if Chrome cought it at runtime 96 | set = getOwnPropertyDescriptor(objProto, '__proto__').set; 97 | set.call({}, null); 98 | // setter not poisoned, it can promote 99 | // Firefox, Chrome 100 | setPrototypeOf = function (origin, proto) { 101 | set.call(origin, proto); 102 | return origin; 103 | }; 104 | } catch (e) { 105 | // do one or more feature detections 106 | set = { __proto__: null }; 107 | // if proto does not work, needs to fallback 108 | // some Opera, Rhino, ducktape 109 | if (set instanceof Object) { 110 | setPrototypeOf = createAndCopy; 111 | } else { 112 | // verify if null objects are buggy 113 | /* eslint-disable no-proto */ 114 | set.__proto__ = objProto; 115 | /* eslint-enable no-proto */ 116 | // if null objects are buggy 117 | // nodejs 0.8 to 0.10 118 | if (set instanceof Object) { 119 | setPrototypeOf = function (origin, proto) { 120 | // use such bug to promote 121 | /* eslint-disable no-proto */ 122 | origin.__proto__ = proto; 123 | /* eslint-enable no-proto */ 124 | return origin; 125 | }; 126 | } else { 127 | // try to use proto or fallback 128 | // Safari, old Firefox, many others 129 | setPrototypeOf = function (origin, proto) { 130 | // if proto is not null 131 | if (getPrototypeOf(origin)) { 132 | // use __proto__ to promote 133 | /* eslint-disable no-proto */ 134 | origin.__proto__ = proto; 135 | /* eslint-enable no-proto */ 136 | return origin; 137 | } 138 | // otherwise unable to promote: fallback 139 | return createAndCopy(origin, proto); 140 | }; 141 | } 142 | } 143 | } 144 | Object.setPrototypeOf = setPrototypeOf; 145 | }()); 146 | 147 | if (supportsDescriptors && function foo() {}.name !== 'foo') { 148 | /* eslint no-extend-native: 1 */ 149 | Object.defineProperty(Function.prototype, 'name', { 150 | configurable: true, 151 | enumerable: false, 152 | get: function () { 153 | if (this === Function.prototype) { 154 | return ''; 155 | } 156 | var str = _call(functionToString, this); 157 | var match = _call(_strMatch, str, /\s*function\s+([^(\s]*)\s*/); 158 | var name = match && match[1]; 159 | Object.defineProperty(this, 'name', { 160 | configurable: true, 161 | enumerable: false, 162 | writable: false, 163 | value: name 164 | }); 165 | return name; 166 | } 167 | }); 168 | } 169 | })); 170 | -------------------------------------------------------------------------------- /es6-sham.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["es6-sham.js"],"names":["root","factory","define","amd","exports","module","returnExports","this","getGlobal","Function","globals","Object","_call","call","bind","functionToString","toString","_strMatch","String","prototype","match","throwsError","func","e","arePropertyDescriptorsSupported","defineProperty","get","supportsDescriptors","setPrototypeOf","getOwnPropertyNames","getOwnPropertyDescriptor","create","getPrototypeOf","objProto","copyDescriptors","target","source","forEach","key","createAndCopy","origin","proto","set","__proto__","foo","name","configurable","enumerable","str","writable","value"],"mappings":";;;;;;;;;CAYC,SAAUA,EAAMC,GAEf,SAAWC,UAAW,YAAcA,OAAOC,IAAK,CAE9CD,OAAOD,OACF,UAAWG,WAAY,SAAU,CAItCC,OAAOD,QAAUH,QACZ,CAELD,EAAKM,cAAgBL,OAEvBM,KAAM,WACN,YAGA,IAAIC,GAAY,GAAIC,UAAS,eAG7B,IAAIC,GAAUF,GACd,IAAIG,GAASD,EAAQC,MACrB,IAAIC,GAAQH,SAASI,KAAKC,KAAKL,SAASI,KACxC,IAAIE,GAAmBN,SAASO,QAChC,IAAIC,GAAYC,OAAOC,UAAUC,KAEjC,IAAIC,GAAc,SAAUC,GAC1B,IACEA,GACA,OAAO,OACP,MAAOC,GACP,MAAO,OAGX,IAAIC,GAAkC,WAEpC,OAAQH,EAAY,WAClBV,EAAOc,kBAAmB,KAAOC,IAAK,iBAG1C,IAAIC,KAAwBhB,EAAOc,gBAAkBD,KAWpD,WACC,GAAIb,EAAOiB,eAAgB,CAAE,OAI7B,GAAIC,GAAsBlB,EAAOkB,mBACjC,IAAIC,GAA2BnB,EAAOmB,wBACtC,IAAIC,GAASpB,EAAOoB,MACpB,IAAIN,GAAiBd,EAAOc,cAC5B,IAAIO,GAAiBrB,EAAOqB,cAC5B,IAAIC,GAAWtB,EAAOQ,SAEtB,IAAIe,GAAkB,SAAUC,EAAQC,GAEtCP,EAAoBO,GAAQC,QAAQ,SAAUC,GAC5Cb,EACEU,EACAG,EACAR,EAAyBM,EAAQE,KAGrC,OAAOH,GAGT,IAAII,GAAgB,SAAUC,EAAQC,GACpC,MAAOP,GAAgBH,EAAOU,GAAQD,GAExC,IAAIE,GAAKd,CACT,KAGEc,EAAMZ,EAAyBG,EAAU,aAAaS,GACtDA,GAAI7B,QAAS,KAGbe,GAAiB,SAAUY,EAAQC,GACjCC,EAAI7B,KAAK2B,EAAQC,EACjB,OAAOD,IAET,MAAOjB,GAEPmB,GAAQC,UAAW,KAGnB,IAAID,YAAe/B,GAAQ,CACzBiB,EAAiBW,MACZ,CAGLG,EAAIC,UAAYV,CAIhB,IAAIS,YAAe/B,GAAQ,CACzBiB,EAAiB,SAAUY,EAAQC,GAGjCD,EAAOG,UAAYF,CAEnB,OAAOD,QAEJ,CAGLZ,EAAiB,SAAUY,EAAQC,GAEjC,GAAIT,EAAeQ,GAAS,CAG1BA,EAAOG,UAAYF,CAEnB,OAAOD,GAGT,MAAOD,GAAcC,EAAQC,MAKrC9B,EAAOiB,eAAiBA,KAG1B,IAAID,GAAuB,QAASiB,SAASC,OAAS,MAAO,CAE3DlC,EAAOc,eAAehB,SAASU,UAAW,QACxC2B,aAAc,KACdC,WAAY,MACZrB,IAAK,WACH,GAAInB,OAASE,SAASU,UAAW,CAC/B,MAAO,GAET,GAAI6B,GAAMpC,EAAMG,EAAkBR,KAClC,IAAIa,GAAQR,EAAMK,EAAW+B,EAAK,6BAClC,IAAIH,GAAOzB,GAASA,EAAM,EAC1BT,GAAOc,eAAelB,KAAM,QAC1BuC,aAAc,KACdC,WAAY,MACZE,SAAU,MACVC,MAAOL,GAET,OAAOA"} -------------------------------------------------------------------------------- /es6-sham.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * https://github.com/paulmillr/es6-shim 3 | * @license es6-shim Copyright 2013-2016 by Paul Miller (http://paulmillr.com) 4 | * and contributors, MIT License 5 | * es6-sham: v0.35.4 6 | * see https://github.com/paulmillr/es6-shim/blob/0.35.3/LICENSE 7 | * Details and documentation: 8 | * https://github.com/paulmillr/es6-shim/ 9 | */ 10 | (function(t,e){if(typeof define==="function"&&define.amd){define(e)}else if(typeof exports==="object"){module.exports=e()}else{t.returnExports=e()}})(this,function(){"use strict";var t=new Function("return this;");var e=t();var r=e.Object;var n=Function.call.bind(Function.call);var o=Function.toString;var i=String.prototype.match;var f=function(t){try{t();return false}catch(e){return true}};var u=function(){return!f(function(){r.defineProperty({},"x",{get:function(){}})})};var a=!!r.defineProperty&&u();(function(){if(r.setPrototypeOf){return}var t=r.getOwnPropertyNames;var e=r.getOwnPropertyDescriptor;var n=r.create;var o=r.defineProperty;var i=r.getPrototypeOf;var f=r.prototype;var u=function(r,n){t(n).forEach(function(t){o(r,t,e(n,t))});return r};var a=function(t,e){return u(n(e),t)};var c,p;try{c=e(f,"__proto__").set;c.call({},null);p=function(t,e){c.call(t,e);return t}}catch(s){c={__proto__:null};if(c instanceof r){p=a}else{c.__proto__=f;if(c instanceof r){p=function(t,e){t.__proto__=e;return t}}else{p=function(t,e){if(i(t)){t.__proto__=e;return t}return a(t,e)}}}}r.setPrototypeOf=p})();if(a&&function foo(){}.name!=="foo"){r.defineProperty(Function.prototype,"name",{configurable:true,enumerable:false,get:function(){if(this===Function.prototype){return""}var t=n(o,this);var e=n(i,t,/\s*function\s+([^(\s]*)\s*/);var f=e&&e[1];r.defineProperty(this,"name",{configurable:true,enumerable:false,writable:false,value:f});return f}})}}); 11 | //# sourceMappingURL=es6-sham.map 12 | -------------------------------------------------------------------------------- /node_modules/mocha/mocha.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | body { 4 | margin:0; 5 | } 6 | 7 | #mocha { 8 | font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; 9 | margin: 60px 50px; 10 | } 11 | 12 | #mocha ul, 13 | #mocha li { 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | #mocha ul { 19 | list-style: none; 20 | } 21 | 22 | #mocha h1, 23 | #mocha h2 { 24 | margin: 0; 25 | } 26 | 27 | #mocha h1 { 28 | margin-top: 15px; 29 | font-size: 1em; 30 | font-weight: 200; 31 | } 32 | 33 | #mocha h1 a { 34 | text-decoration: none; 35 | color: inherit; 36 | } 37 | 38 | #mocha h1 a:hover { 39 | text-decoration: underline; 40 | } 41 | 42 | #mocha .suite .suite h1 { 43 | margin-top: 0; 44 | font-size: .8em; 45 | } 46 | 47 | #mocha .hidden { 48 | display: none; 49 | } 50 | 51 | #mocha h2 { 52 | font-size: 12px; 53 | font-weight: normal; 54 | cursor: pointer; 55 | } 56 | 57 | #mocha .suite { 58 | margin-left: 15px; 59 | } 60 | 61 | #mocha .test { 62 | margin-left: 15px; 63 | overflow: hidden; 64 | } 65 | 66 | #mocha .test.pending:hover h2::after { 67 | content: '(pending)'; 68 | font-family: arial, sans-serif; 69 | } 70 | 71 | #mocha .test.pass.medium .duration { 72 | background: #c09853; 73 | } 74 | 75 | #mocha .test.pass.slow .duration { 76 | background: #b94a48; 77 | } 78 | 79 | #mocha .test.pass::before { 80 | content: '✓'; 81 | font-size: 12px; 82 | display: block; 83 | float: left; 84 | margin-right: 5px; 85 | color: #00d6b2; 86 | } 87 | 88 | #mocha .test.pass .duration { 89 | font-size: 9px; 90 | margin-left: 5px; 91 | padding: 2px 5px; 92 | color: #fff; 93 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 94 | -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 95 | box-shadow: inset 0 1px 1px rgba(0,0,0,.2); 96 | -webkit-border-radius: 5px; 97 | -moz-border-radius: 5px; 98 | -ms-border-radius: 5px; 99 | -o-border-radius: 5px; 100 | border-radius: 5px; 101 | } 102 | 103 | #mocha .test.pass.fast .duration { 104 | display: none; 105 | } 106 | 107 | #mocha .test.pending { 108 | color: #0b97c4; 109 | } 110 | 111 | #mocha .test.pending::before { 112 | content: '◦'; 113 | color: #0b97c4; 114 | } 115 | 116 | #mocha .test.fail { 117 | color: #c00; 118 | } 119 | 120 | #mocha .test.fail pre { 121 | color: black; 122 | } 123 | 124 | #mocha .test.fail::before { 125 | content: '✖'; 126 | font-size: 12px; 127 | display: block; 128 | float: left; 129 | margin-right: 5px; 130 | color: #c00; 131 | } 132 | 133 | #mocha .test pre.error { 134 | color: #c00; 135 | max-height: 300px; 136 | overflow: auto; 137 | } 138 | 139 | #mocha .test .html-error { 140 | overflow: auto; 141 | color: black; 142 | line-height: 1.5; 143 | display: block; 144 | float: left; 145 | clear: left; 146 | font: 12px/1.5 monaco, monospace; 147 | margin: 5px; 148 | padding: 15px; 149 | border: 1px solid #eee; 150 | max-width: 85%; /*(1)*/ 151 | max-width: -webkit-calc(100% - 42px); 152 | max-width: -moz-calc(100% - 42px); 153 | max-width: calc(100% - 42px); /*(2)*/ 154 | max-height: 300px; 155 | word-wrap: break-word; 156 | border-bottom-color: #ddd; 157 | -webkit-box-shadow: 0 1px 3px #eee; 158 | -moz-box-shadow: 0 1px 3px #eee; 159 | box-shadow: 0 1px 3px #eee; 160 | -webkit-border-radius: 3px; 161 | -moz-border-radius: 3px; 162 | border-radius: 3px; 163 | } 164 | 165 | #mocha .test .html-error pre.error { 166 | border: none; 167 | -webkit-border-radius: 0; 168 | -moz-border-radius: 0; 169 | border-radius: 0; 170 | -webkit-box-shadow: 0; 171 | -moz-box-shadow: 0; 172 | box-shadow: 0; 173 | padding: 0; 174 | margin: 0; 175 | margin-top: 18px; 176 | max-height: none; 177 | } 178 | 179 | /** 180 | * (1): approximate for browsers not supporting calc 181 | * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) 182 | * ^^ seriously 183 | */ 184 | #mocha .test pre { 185 | display: block; 186 | float: left; 187 | clear: left; 188 | font: 12px/1.5 monaco, monospace; 189 | margin: 5px; 190 | padding: 15px; 191 | border: 1px solid #eee; 192 | max-width: 85%; /*(1)*/ 193 | max-width: -webkit-calc(100% - 42px); 194 | max-width: -moz-calc(100% - 42px); 195 | max-width: calc(100% - 42px); /*(2)*/ 196 | word-wrap: break-word; 197 | border-bottom-color: #ddd; 198 | -webkit-box-shadow: 0 1px 3px #eee; 199 | -moz-box-shadow: 0 1px 3px #eee; 200 | box-shadow: 0 1px 3px #eee; 201 | -webkit-border-radius: 3px; 202 | -moz-border-radius: 3px; 203 | border-radius: 3px; 204 | } 205 | 206 | #mocha .test h2 { 207 | position: relative; 208 | } 209 | 210 | #mocha .test a.replay { 211 | position: absolute; 212 | top: 3px; 213 | right: 0; 214 | text-decoration: none; 215 | vertical-align: middle; 216 | display: block; 217 | width: 15px; 218 | height: 15px; 219 | line-height: 15px; 220 | text-align: center; 221 | background: #eee; 222 | font-size: 15px; 223 | -webkit-border-radius: 15px; 224 | -moz-border-radius: 15px; 225 | border-radius: 15px; 226 | -webkit-transition:opacity 200ms; 227 | -moz-transition:opacity 200ms; 228 | -o-transition:opacity 200ms; 229 | transition: opacity 200ms; 230 | opacity: 0.3; 231 | color: #888; 232 | } 233 | 234 | #mocha .test:hover a.replay { 235 | opacity: 1; 236 | } 237 | 238 | #mocha-report.pass .test.fail { 239 | display: none; 240 | } 241 | 242 | #mocha-report.fail .test.pass { 243 | display: none; 244 | } 245 | 246 | #mocha-report.pending .test.pass, 247 | #mocha-report.pending .test.fail { 248 | display: none; 249 | } 250 | #mocha-report.pending .test.pass.pending { 251 | display: block; 252 | } 253 | 254 | #mocha-error { 255 | color: #c00; 256 | font-size: 1.5em; 257 | font-weight: 100; 258 | letter-spacing: 1px; 259 | } 260 | 261 | #mocha-stats { 262 | position: fixed; 263 | top: 15px; 264 | right: 10px; 265 | font-size: 12px; 266 | margin: 0; 267 | color: #888; 268 | z-index: 1; 269 | } 270 | 271 | #mocha-stats .progress { 272 | float: right; 273 | padding-top: 0; 274 | 275 | /** 276 | * Set safe initial values, so mochas .progress does not inherit these 277 | * properties from Bootstrap .progress (which causes .progress height to 278 | * equal line height set in Bootstrap). 279 | */ 280 | height: auto; 281 | -webkit-box-shadow: none; 282 | -moz-box-shadow: none; 283 | box-shadow: none; 284 | background-color: initial; 285 | } 286 | 287 | #mocha-stats em { 288 | color: black; 289 | } 290 | 291 | #mocha-stats a { 292 | text-decoration: none; 293 | color: inherit; 294 | } 295 | 296 | #mocha-stats a:hover { 297 | border-bottom: 1px solid #eee; 298 | } 299 | 300 | #mocha-stats li { 301 | display: inline-block; 302 | margin: 0 5px; 303 | list-style: none; 304 | padding-top: 11px; 305 | } 306 | 307 | #mocha-stats canvas { 308 | width: 40px; 309 | height: 40px; 310 | } 311 | 312 | #mocha code .comment { color: #ddd; } 313 | #mocha code .init { color: #2f6fad; } 314 | #mocha code .string { color: #5890ad; } 315 | #mocha code .keyword { color: #8a6343; } 316 | #mocha code .number { color: #2f6fad; } 317 | 318 | @media screen and (max-device-width: 480px) { 319 | #mocha { 320 | margin: 60px 0px; 321 | } 322 | 323 | #mocha #stats { 324 | position: absolute; 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es6-shim", 3 | "version": "0.35.8", 4 | "author": "Paul Miller (http://paulmillr.com)", 5 | "description": "ECMAScript 6 (Harmony) compatibility shims for legacy JavaScript engines", 6 | "keywords": [ 7 | "ecmascript", 8 | "harmony", 9 | "es6", 10 | "shim", 11 | "promise", 12 | "promises", 13 | "setPrototypeOf", 14 | "map", 15 | "set", 16 | "__proto__" 17 | ], 18 | "homepage": "https://github.com/paulmillr/es6-shim/", 19 | "license": "MIT", 20 | "repository": { 21 | "type": "git", 22 | "url": "git://github.com/paulmillr/es6-shim.git" 23 | }, 24 | "main": "es6-shim", 25 | "scripts": { 26 | "prepublishOnly": "safe-publish-latest && npm run minify", 27 | "prepublih": "not-in-publish || npm run prepublishOnly", 28 | "pretest": "npm run lint && evalmd *.md", 29 | "test": "NODE_OPTIONS='--unhandled-rejections=none' npm run tests-only", 30 | "posttest": "aud --production", 31 | "tests-only": "nyc mocha 'test/**/*.js' 'test-sham/*.js'", 32 | "test:shim": "nyc mocha 'test/**/*.js'", 33 | "test:sham": "nyc mocha 'test-sham/*.js'", 34 | "test:native": "NO_ES6_SHIM=1 npm run tests-only", 35 | "lint": "npm run lint:shim && npm run lint:sham", 36 | "lint:shim": "eslint es6-shim.js test/*.js test/*/*.js", 37 | "lint:sham": "eslint es6-sham.js test-sham/*.js", 38 | "minify": "npm run minify:shim && npm run minify:sham", 39 | "minify:shim": "uglifyjs es6-shim.js --support-ie8 --keep-fnames --comments --source-map=es6-shim.map -m -b ascii_only=true,beautify=false > es6-shim.min.js", 40 | "minify:sham": "uglifyjs es6-sham.js --support-ie8 --keep-fnames --comments --source-map=es6-sham.map -m -b ascii_only=true,beautify=false > es6-sham.min.js", 41 | "sauce-connect": "curl -L https://gist.githubusercontent.com/henrikhodne/9322897/raw/sauce-connect.sh | bash && export TRAVIS_SAUCE_CONNECT=true", 42 | "sauce": "npm run sauce-connect && grunt sauce" 43 | }, 44 | "testling": { 45 | "html": "testling.html", 46 | "browsers": [ 47 | "iexplore/6.0..latest", 48 | "firefox/3.0..6.0", 49 | "firefox/10.0", 50 | "firefox/15.0..latest", 51 | "firefox/nightly", 52 | "chrome/4.0..10.0", 53 | "chrome/20.0..latest", 54 | "chrome/canary", 55 | "opera/10.0..latest", 56 | "opera/next", 57 | "safari/4.0..latest", 58 | "ipad/6.0..latest", 59 | "iphone/6.0..latest", 60 | "android-browser/4.2..latest" 61 | ] 62 | }, 63 | "devDependencies": { 64 | "@ljharb/eslint-config": "^21.0.1", 65 | "aud": "^2.0.2", 66 | "chai": "^3.5.0", 67 | "es5-shim": "^4.6.7", 68 | "eslint": "=8.8.0", 69 | "evalmd": "^0.0.19", 70 | "grunt": "^0.4.5", 71 | "grunt-contrib-connect": "^1.0.2", 72 | "grunt-contrib-watch": "^1.1.0", 73 | "grunt-saucelabs": "^8.6.3", 74 | "in-publish": "^2.0.1", 75 | "mocha": "^3.5.3", 76 | "nyc": "^10.3.2", 77 | "promises-aplus-tests": "^2.1.2", 78 | "promises-es6-tests": "^0.5.0", 79 | "safe-publish-latest": "^2.0.0", 80 | "tape": "^5.6.3", 81 | "uglify-js": "2.7.3" 82 | }, 83 | "engines": { 84 | "node": ">= 0.4" 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /test-sham/function.js: -------------------------------------------------------------------------------- 1 | var identity = function (x) { return x; }; 2 | 3 | describe('Function', function () { 4 | describe('#name', function () { 5 | it('returns the name for named functions', function () { 6 | var foo = function bar() {}; 7 | expect(foo.name).to.equal('bar'); 8 | 9 | // pre-ES6, this property is nonconfigurable. 10 | var configurable = Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(foo, 'name').configurable : false; 11 | 12 | expect(foo).to.have.ownPropertyDescriptor('name', { 13 | configurable: !!configurable, 14 | enumerable: false, 15 | writable: false, 16 | value: 'bar' 17 | }); 18 | }); 19 | 20 | it('does not poison every name when accessed on Function.prototype', function () { 21 | expect((function foo() {}).name).to.equal('foo'); 22 | expect(Function.prototype.name).to.match(/^$|Empty/); 23 | expect((function foo() {}).name).to.equal('foo'); 24 | }); 25 | 26 | it('returns empty string for anonymous functions', function () { 27 | var anon = identity(function () {}); 28 | expect(anon.name).to.equal(''); 29 | 30 | // pre-ES6, this property is nonconfigurable. 31 | var configurable = Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(anon, 'name').configurable : false; 32 | 33 | expect(anon).to.have.ownPropertyDescriptor('name', { 34 | configurable: !!configurable, 35 | enumerable: false, 36 | writable: false, 37 | value: '' 38 | }); 39 | }); 40 | 41 | it('returns "anomymous" for Function functions', function () { 42 | // eslint-disable-next-line no-new-func 43 | var func = identity(Function('')); 44 | expect(typeof func.name).to.equal('string'); 45 | expect(func.name === 'anonymous' || func.name === '').to.equal(true); 46 | 47 | // pre-ES6, this property is nonconfigurable. 48 | var configurable = Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(func, 'name').configurable : false; 49 | 50 | expect(func).to.have.ownPropertyDescriptor('name', { 51 | configurable: !!configurable, 52 | enumerable: false, 53 | writable: false, 54 | value: func.name 55 | }); 56 | }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test-sham/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | es6-shim tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test-sham/set-prototype-of.js: -------------------------------------------------------------------------------- 1 | describe('Object.setPrototypeOf(o, p)', function () { 2 | 'use strict'; 3 | 4 | it('changes prototype to regular objects', function () { 5 | var obj = { a: 123 }; 6 | expect(obj instanceof Object).to.equal(true); 7 | // sham requires assignment to work cross browser 8 | obj = Object.setPrototypeOf(obj, null); 9 | expect(obj instanceof Object).to.equal(false); 10 | expect(obj.a).to.equal(123); 11 | }); 12 | 13 | it('changes prototype to null objects', function () { 14 | var obj = Object.create(null); 15 | obj.a = 456; 16 | expect(obj instanceof Object).to.equal(false); 17 | expect(obj.a).to.equal(456); 18 | // sham requires assignment to work cross browser 19 | obj = Object.setPrototypeOf(obj, { b: 789 }); 20 | expect(obj instanceof Object).to.equal(true); 21 | expect(obj.a).to.equal(456); 22 | expect(obj.b).to.equal(789); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/browser-onload.js: -------------------------------------------------------------------------------- 1 | if (typeof window !== 'undefined') { 2 | window.completedTests = 0; 3 | window.sawFail = false; 4 | window.onload = function () { 5 | window.testsPassed = null; 6 | var handleResults = function (runner) { 7 | var failedTests = []; 8 | if (runner.stats.end) { 9 | window.testsPassed = runner.stats.failures === 0; 10 | } 11 | runner.on('pass', function () { 12 | window.completedTests += 1; 13 | }); 14 | runner.on('fail', function (test, err) { 15 | window.sawFail = true; 16 | var flattenTitles = function (testToFlatten) { 17 | var titles = []; 18 | var currentTest = testToFlatten; 19 | while (currentTest.parent.title) { 20 | titles.push(currentTest.parent.title); 21 | currentTest = currentTest.parent; 22 | } 23 | return titles.reverse(); 24 | }; 25 | failedTests.push({ 26 | name: test.title, 27 | result: false, 28 | message: err.message, 29 | stack: err.stack, 30 | titles: flattenTitles(test) 31 | }); 32 | }); 33 | runner.on('end', function () { 34 | window.testsPassed = !window.sawFail; 35 | // for sauce 36 | window.mochaResults = runner.stats; 37 | window.mochaResults.reports = failedTests; 38 | }); 39 | return runner; 40 | }; 41 | handleResults(mocha.run()); 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /test/browser-setup.js: -------------------------------------------------------------------------------- 1 | if (typeof window !== 'undefined') { 2 | chai.config.includeStack = true; 3 | window.expect = chai.expect; 4 | window.assert = chai.assert; 5 | mocha.setup('bdd'); 6 | window.require = function () { 7 | return window; 8 | }; 9 | } 10 | -------------------------------------------------------------------------------- /test/date.js: -------------------------------------------------------------------------------- 1 | describe('Date', function () { 2 | it('when invalid, dates should toString to "Invalid Date"', function () { 3 | expect(String(new Date(NaN))).to.equal('Invalid Date'); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /test/google-translate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | es6-shim tests 6 | 7 | 8 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | es6-shim tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /test/json.js: -------------------------------------------------------------------------------- 1 | describe('JSON', function () { 2 | var functionsHaveNames = (function foo() {}).name === 'foo'; 3 | var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit; 4 | var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol'; 5 | var ifSymbolsIt = hasSymbols ? it : xit; 6 | var ifSymbolsDescribe = hasSymbols ? describe : xit; 7 | 8 | describe('.stringify()', function () { 9 | ifFunctionsHaveNamesIt('has the right name', function () { 10 | expect(JSON.stringify.name).to.equal('stringify'); 11 | }); 12 | 13 | ifSymbolsIt('serializes a Symbol to undefined', function () { 14 | expect(JSON.stringify(Symbol())).to.equal(undefined); 15 | }); 16 | 17 | ifSymbolsIt('serializes a Symbol object to {}', function () { 18 | expect(function stringifyObjectSymbol() { JSON.stringify(Object(Symbol())); }).not.to['throw'](); 19 | expect(JSON.stringify(Object(Symbol()))).to.equal('{}'); 20 | }); 21 | 22 | ifSymbolsIt('serializes Symbols in an Array to null', function () { 23 | expect(JSON.stringify([Symbol('foo')])).to.equal('[null]'); 24 | }); 25 | 26 | ifSymbolsIt('serializes Symbol objects in an Array to {}', function () { 27 | expect(function stringifyObjectSymbolInArray() { JSON.stringify([Object(Symbol('foo'))]); }).not.to['throw'](); 28 | expect(JSON.stringify([Object(Symbol('foo'))])).to.equal('[{}]'); 29 | }); 30 | 31 | ifSymbolsDescribe('skips symbol properties and values in an object', function () { 32 | var enumSym = Symbol('enumerable'); 33 | var nonenum = Symbol('non-enumerable'); 34 | var createObject = function () { 35 | var obj = { a: 1 }; 36 | obj[enumSym] = true; 37 | obj.sym = enumSym; 38 | Object.defineProperty(obj, nonenum, { enumerable: false, value: true }); 39 | expect(Object.getOwnPropertySymbols(obj)).to.eql([enumSym, nonenum]); 40 | return obj; 41 | }; 42 | 43 | it('works with no replacer', function () { 44 | var obj = createObject(); 45 | expect(JSON.stringify(obj)).to.equal('{"a":1}'); 46 | expect(JSON.stringify(obj, null, '|')).to.equal('{\n|"a": 1\n}'); 47 | }); 48 | 49 | it('works with a replacer function', function () { 50 | var tuples = []; 51 | var replacer = function (key, value) { 52 | tuples.push([this, key, value]); 53 | return value; 54 | }; 55 | var obj = createObject(); 56 | expect(JSON.stringify(obj, replacer, '|')).to.equal('{\n|"a": 1\n}'); // populate `tuples` array 57 | expect(tuples).to.eql([ 58 | [{ '': obj }, '', obj], 59 | [obj, 'a', 1], 60 | [obj, 'sym', enumSym] 61 | ]); 62 | }); 63 | 64 | it('works with a replacer array', function () { 65 | var obj = createObject(); 66 | obj.foo = 'bar'; 67 | obj[Symbol.prototype.toString.call(enumSym)] = 'tricksy'; 68 | expect(JSON.stringify(obj, ['a', enumSym])).to.equal('{"a":1}'); 69 | expect(JSON.stringify(obj, ['a', enumSym], '|')).to.equal('{\n|"a": 1\n}'); 70 | }); 71 | 72 | it('ignores a non-array non-callable replacer object', function () { 73 | expect(JSON.stringify('z', { test: null })).to.equal('"z"'); 74 | }); 75 | }); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /test/map.js: -------------------------------------------------------------------------------- 1 | // Big thanks to V8 folks for test ideas. 2 | // v8/test/mjsunit/harmony/collections.js 3 | 4 | var Assertion = expect().constructor; 5 | Assertion.addMethod('theSameSet', function (otherArray) { 6 | var array = this._obj; 7 | 8 | expect(Array.isArray(array)).to.equal(true); 9 | expect(Array.isArray(otherArray)).to.equal(true); 10 | 11 | var diff = array.filter(function (value) { 12 | return otherArray.every(function (otherValue) { 13 | var areBothNaN = typeof value === 'number' && typeof otherValue === 'number' && value !== value && otherValue !== otherValue; 14 | return !areBothNaN && value !== otherValue; 15 | }); 16 | }); 17 | 18 | this.assert( 19 | diff.length === 0, 20 | 'expected #{this} to be equal to #{exp} (as sets, i.e. no order)', 21 | array, 22 | otherArray 23 | ); 24 | }); 25 | 26 | Assertion.addMethod('entries', function (expected) { 27 | var collection = this._obj; 28 | 29 | expect(Array.isArray(expected)).to.equal(true); 30 | var expectedEntries = expected.slice(); 31 | 32 | var iterator = collection.entries(); 33 | var result; 34 | do { 35 | result = iterator.next(); 36 | expect(result.value).to.be.eql(expectedEntries.shift()); 37 | } while (!result.done); 38 | }); 39 | 40 | describe('Map', function () { 41 | var functionsHaveNames = (function foo() {}).name === 'foo'; 42 | var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit; 43 | var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it; 44 | var ifGetPrototypeOfIt = Object.getPrototypeOf ? it : xit; 45 | 46 | var range = function range(from, to) { 47 | var result = []; 48 | for (var value = from; value < to; value++) { 49 | result.push(value); 50 | } 51 | return result; 52 | }; 53 | 54 | var prototypePropIsEnumerable = Object.prototype.propertyIsEnumerable.call(function () {}, 'prototype'); 55 | var expectNotEnumerable = function (object) { 56 | if (prototypePropIsEnumerable && typeof object === 'function') { 57 | expect(Object.keys(object)).to.eql(['prototype']); 58 | } else { 59 | expect(Object.keys(object)).to.eql([]); 60 | } 61 | }; 62 | 63 | var Sym = typeof Symbol === 'undefined' ? {} : Symbol; 64 | var isSymbol = function (sym) { 65 | return typeof Sym === 'function' && typeof sym === 'symbol'; 66 | }; 67 | var ifSymbolIteratorIt = isSymbol(Sym.iterator) ? it : xit; 68 | 69 | var testMapping = function (map, key, value) { 70 | expect(map.has(key)).to.equal(false); 71 | expect(map.get(key)).to.equal(undefined); 72 | expect(map.set(key, value)).to.equal(map); 73 | expect(map.get(key)).to.equal(value); 74 | expect(map.has(key)).to.equal(true); 75 | }; 76 | 77 | if (typeof Map === 'undefined') { 78 | return it('exists', function () { 79 | expect(typeof Map).to.equal('function'); 80 | }); 81 | } 82 | 83 | var map; 84 | beforeEach(function () { 85 | map = new Map(); 86 | }); 87 | 88 | afterEach(function () { 89 | map = null; 90 | }); 91 | 92 | ifShimIt('is on the exported object', function () { 93 | var exported = require('../'); 94 | expect(exported.Map).to.equal(Map); 95 | }); 96 | 97 | it('should exist in global namespace', function () { 98 | expect(typeof Map).to.equal('function'); 99 | }); 100 | 101 | it('should have the right arity', function () { 102 | expect(Map).to.have.property('length', 0); 103 | }); 104 | 105 | it('should has valid getter and setter calls', function () { 106 | ['get', 'set', 'has', 'delete'].forEach(function (method) { 107 | expect(function () { 108 | map[method]({}); 109 | }).to.not['throw'](); 110 | }); 111 | }); 112 | 113 | it('should accept an iterable as argument', function () { 114 | testMapping(map, 'a', 'b'); 115 | testMapping(map, 'c', 'd'); 116 | var map2; 117 | expect(function () { map2 = new Map(map); }).not.to['throw'](Error); 118 | expect(map2).to.be.an.instanceOf(Map); 119 | expect(map2.has('a')).to.equal(true); 120 | expect(map2.has('c')).to.equal(true); 121 | expect(map2).to.have.entries([['a', 'b'], ['c', 'd']]); 122 | }); 123 | 124 | it('should throw with iterables that return primitives', function () { 125 | expect(function () { return new Map('123'); }).to['throw'](TypeError); 126 | expect(function () { return new Map([1, 2, 3]); }).to['throw'](TypeError); 127 | expect(function () { return new Map(['1', '2', '3']); }).to['throw'](TypeError); 128 | expect(function () { return new Map([true]); }).to['throw'](TypeError); 129 | }); 130 | 131 | it('should not be callable without "new"', function () { 132 | expect(Map).to['throw'](TypeError); 133 | }); 134 | 135 | it('should be subclassable', function () { 136 | if (!Object.setPrototypeOf) { return; } // skip test if on IE < 11 137 | var MyMap = function MyMap() { 138 | var testMap = new Map([['a', 'b']]); 139 | Object.setPrototypeOf(testMap, MyMap.prototype); 140 | return testMap; 141 | }; 142 | Object.setPrototypeOf(MyMap, Map); 143 | MyMap.prototype = Object.create(Map.prototype, { 144 | constructor: { value: MyMap } 145 | }); 146 | 147 | var myMap = new MyMap(); 148 | testMapping(myMap, 'c', 'd'); 149 | expect(myMap).to.have.entries([['a', 'b'], ['c', 'd']]); 150 | }); 151 | 152 | it('uses SameValueZero even on a Map of size > 4', function () { 153 | // Chrome 38-42, node 0.11/0.12, iojs 1/2 have a bug when the Map has a size > 4 154 | var firstFour = [[1, 0], [2, 0], [3, 0], [4, 0]]; 155 | var fourMap = new Map(firstFour); 156 | expect(fourMap.size).to.equal(4); 157 | expect(fourMap.has(-0)).to.equal(false); 158 | expect(fourMap.has(0)).to.equal(false); 159 | 160 | fourMap.set(-0, fourMap); 161 | 162 | expect(fourMap.has(0)).to.equal(true); 163 | expect(fourMap.has(-0)).to.equal(true); 164 | }); 165 | 166 | it('treats positive and negative zero the same', function () { 167 | var value1 = {}; 168 | var value2 = {}; 169 | testMapping(map, +0, value1); 170 | expect(map.has(-0)).to.equal(true); 171 | expect(map.get(-0)).to.equal(value1); 172 | expect(map.set(-0, value2)).to.equal(map); 173 | expect(map.get(-0)).to.equal(value2); 174 | expect(map.get(+0)).to.equal(value2); 175 | }); 176 | 177 | it('should map values correctly', function () { 178 | // Run this test twice, one with the "fast" implementation (which only 179 | // allows string and numeric keys) and once with the "slow" impl. 180 | [true, false].forEach(function (slowkeys) { 181 | map = new Map(); 182 | 183 | range(1, 20).forEach(function (number) { 184 | if (slowkeys) { testMapping(map, number, {}); } 185 | testMapping(map, number / 100, {}); 186 | testMapping(map, 'key-' + number, {}); 187 | testMapping(map, String(number), {}); 188 | if (slowkeys) { testMapping(map, Object(String(number)), {}); } 189 | }); 190 | 191 | var testkeys = [Infinity, -Infinity, NaN]; 192 | if (slowkeys) { 193 | testkeys.push(true, false, null, undefined); 194 | } 195 | testkeys.forEach(function (key) { 196 | testMapping(map, key, {}); 197 | testMapping(map, String(key), {}); 198 | }); 199 | testMapping(map, '', {}); 200 | 201 | // verify that properties of Object don't peek through. 202 | [ 203 | 'hasOwnProperty', 204 | 'constructor', 205 | 'toString', 206 | 'isPrototypeOf', 207 | '__proto__', 208 | '__parent__', 209 | '__count__' 210 | ].forEach(function (key) { 211 | testMapping(map, key, {}); 212 | }); 213 | }); 214 | }); 215 | 216 | it('should map empty values correctly', function () { 217 | testMapping(map, {}, true); 218 | testMapping(map, null, true); 219 | testMapping(map, undefined, true); 220 | testMapping(map, '', true); 221 | testMapping(map, NaN, true); 222 | testMapping(map, 0, true); 223 | }); 224 | 225 | it('should has correct querying behavior', function () { 226 | var key = {}; 227 | testMapping(map, key, 'to-be-present'); 228 | expect(map.has(key)).to.equal(true); 229 | expect(map.has({})).to.equal(false); 230 | expect(map.set(key, void 0)).to.equal(map); 231 | expect(map.get(key)).to.equal(undefined); 232 | expect(map.has(key)).to.equal(true); 233 | expect(map.has({})).to.equal(false); 234 | }); 235 | 236 | it('should allow NaN values as keys', function () { 237 | expect(map.has(NaN)).to.equal(false); 238 | expect(map.has(NaN + 1)).to.equal(false); 239 | expect(map.has(23)).to.equal(false); 240 | expect(map.set(NaN, 'value')).to.equal(map); 241 | expect(map.has(NaN)).to.equal(true); 242 | expect(map.has(NaN + 1)).to.equal(true); 243 | expect(map.has(23)).to.equal(false); 244 | }); 245 | 246 | it('should not have [[Enumerable]] props', function () { 247 | expectNotEnumerable(Map); 248 | expectNotEnumerable(Map.prototype); 249 | expectNotEnumerable(new Map()); 250 | }); 251 | 252 | it('should not have an own constructor', function () { 253 | var m = new Map(); 254 | expect(m).not.to.haveOwnPropertyDescriptor('constructor'); 255 | expect(m.constructor).to.equal(Map); 256 | }); 257 | 258 | it('should allow common ecmascript idioms', function () { 259 | expect(map).to.be.an.instanceOf(Map); 260 | expect(typeof Map.prototype.get).to.equal('function'); 261 | expect(typeof Map.prototype.set).to.equal('function'); 262 | expect(typeof Map.prototype.has).to.equal('function'); 263 | expect(typeof Map.prototype['delete']).to.equal('function'); 264 | }); 265 | 266 | it('should have a unique constructor', function () { 267 | expect(Map.prototype).to.not.equal(Object.prototype); 268 | }); 269 | 270 | describe('#clear()', function () { 271 | ifFunctionsHaveNamesIt('has the right name', function () { 272 | expect(Map.prototype.clear).to.have.property('name', 'clear'); 273 | }); 274 | 275 | it('is not enumerable', function () { 276 | expect(Map.prototype).ownPropertyDescriptor('clear').to.have.property('enumerable', false); 277 | }); 278 | 279 | it('has the right arity', function () { 280 | expect(Map.prototype.clear).to.have.property('length', 0); 281 | }); 282 | 283 | it('should have #clear method', function () { 284 | expect(map.set(1, 2)).to.equal(map); 285 | expect(map.set(5, 2)).to.equal(map); 286 | expect(map.size).to.equal(2); 287 | expect(map.has(5)).to.equal(true); 288 | map.clear(); 289 | expect(map.size).to.equal(0); 290 | expect(map.has(5)).to.equal(false); 291 | }); 292 | }); 293 | 294 | describe('#keys()', function () { 295 | if (!Object.prototype.hasOwnProperty.call(Map.prototype, 'keys')) { 296 | return it('exists', function () { 297 | expect(Map.prototype).to.have.property('keys'); 298 | }); 299 | } 300 | 301 | ifFunctionsHaveNamesIt('has the right name', function () { 302 | expect(Map.prototype.keys).to.have.property('name', 'keys'); 303 | }); 304 | 305 | it('is not enumerable', function () { 306 | expect(Map.prototype).ownPropertyDescriptor('keys').to.have.property('enumerable', false); 307 | }); 308 | 309 | it('has the right arity', function () { 310 | expect(Map.prototype.keys).to.have.property('length', 0); 311 | }); 312 | }); 313 | 314 | describe('#values()', function () { 315 | if (!Object.prototype.hasOwnProperty.call(Map.prototype, 'values')) { 316 | return it('exists', function () { 317 | expect(Map.prototype).to.have.property('values'); 318 | }); 319 | } 320 | 321 | ifFunctionsHaveNamesIt('has the right name', function () { 322 | expect(Map.prototype.values).to.have.property('name', 'values'); 323 | }); 324 | 325 | it('is not enumerable', function () { 326 | expect(Map.prototype).ownPropertyDescriptor('values').to.have.property('enumerable', false); 327 | }); 328 | 329 | it('has the right arity', function () { 330 | expect(Map.prototype.values).to.have.property('length', 0); 331 | }); 332 | }); 333 | 334 | describe('#entries()', function () { 335 | if (!Object.prototype.hasOwnProperty.call(Map.prototype, 'entries')) { 336 | return it('exists', function () { 337 | expect(Map.prototype).to.have.property('entries'); 338 | }); 339 | } 340 | 341 | ifFunctionsHaveNamesIt('has the right name', function () { 342 | expect(Map.prototype.entries).to.have.property('name', 'entries'); 343 | }); 344 | 345 | it('is not enumerable', function () { 346 | expect(Map.prototype).ownPropertyDescriptor('entries').to.have.property('enumerable', false); 347 | }); 348 | 349 | it('has the right arity', function () { 350 | expect(Map.prototype.entries).to.have.property('length', 0); 351 | }); 352 | 353 | it('throws when called on a non-Map', function () { 354 | var expectedMessage = /^(Method )?Map.prototype.entries called on incompatible receiver |^entries method called on incompatible |^Cannot create a Map entry iterator for a non-Map object.|^Map\.prototype\.entries: 'this' is not a Map object$|^std_Map_iterator method called on incompatible \w$|Map.prototype.entries requires that \|this\| be Map+$|is not an object \(evaluating 'Map.prototype.entries.call\(nonMap\)'\)|Map operation called on non-Map object/; 355 | var nonMaps = [true, false, 'abc', NaN, new Set([1, 2]), { a: true }, [1], Object('abc'), Object(NaN)]; 356 | nonMaps.forEach(function (nonMap) { 357 | expect(function () { return Map.prototype.entries.call(nonMap); }).to['throw'](TypeError, expectedMessage); 358 | }); 359 | }); 360 | }); 361 | 362 | describe('#size', function () { 363 | it('throws TypeError when accessed directly', function () { 364 | // see https://github.com/paulmillr/es6-shim/issues/176 365 | expect(function () { return Map.prototype.size; }).to['throw'](TypeError); 366 | expect(function () { return Map.prototype.size; }).to['throw'](TypeError); 367 | }); 368 | 369 | it('is an accessor function on the prototype', function () { 370 | expect(Map.prototype).ownPropertyDescriptor('size').to.have.property('get'); 371 | expect(typeof Object.getOwnPropertyDescriptor(Map.prototype, 'size').get).to.equal('function'); 372 | expect(new Map()).not.to.haveOwnPropertyDescriptor('size'); 373 | }); 374 | }); 375 | 376 | it('should return false when deleting a nonexistent key', function () { 377 | expect(map.has('a')).to.equal(false); 378 | expect(map['delete']('a')).to.equal(false); 379 | }); 380 | 381 | it('should have keys, values and size props', function () { 382 | expect(map.set('a', 1)).to.equal(map); 383 | expect(map.set('b', 2)).to.equal(map); 384 | expect(map.set('c', 3)).to.equal(map); 385 | expect(typeof map.keys).to.equal('function'); 386 | expect(typeof map.values).to.equal('function'); 387 | expect(map.size).to.equal(3); 388 | expect(map['delete']('a')).to.equal(true); 389 | expect(map.size).to.equal(2); 390 | }); 391 | 392 | it('should have an iterator that works with Array.from', function () { 393 | expect(Array).to.have.property('from'); 394 | 395 | expect(map.set('a', 1)).to.equal(map); 396 | expect(map.set('b', NaN)).to.equal(map); 397 | expect(map.set('c', false)).to.equal(map); 398 | expect(Array.from(map)).to.eql([['a', 1], ['b', NaN], ['c', false]]); 399 | expect(Array.from(map.keys())).to.eql(['a', 'b', 'c']); 400 | expect(Array.from(map.values())).to.eql([1, NaN, false]); 401 | expect(map).to.have.entries(Array.from(map.entries())); 402 | }); 403 | 404 | ifSymbolIteratorIt('has the right default iteration function', function () { 405 | // fixed in Webkit https://bugs.webkit.org/show_bug.cgi?id=143838 406 | expect(Map.prototype).to.have.property(Sym.iterator, Map.prototype.entries); 407 | }); 408 | 409 | describe('#forEach', function () { 410 | var mapToIterate; 411 | 412 | beforeEach(function () { 413 | mapToIterate = new Map(); 414 | expect(mapToIterate.set('a', 1)).to.equal(mapToIterate); 415 | expect(mapToIterate.set('b', 2)).to.equal(mapToIterate); 416 | expect(mapToIterate.set('c', 3)).to.equal(mapToIterate); 417 | }); 418 | 419 | afterEach(function () { 420 | mapToIterate = null; 421 | }); 422 | 423 | ifFunctionsHaveNamesIt('has the right name', function () { 424 | expect(Map.prototype.forEach).to.have.property('name', 'forEach'); 425 | }); 426 | 427 | it('is not enumerable', function () { 428 | expect(Map.prototype).ownPropertyDescriptor('forEach').to.have.property('enumerable', false); 429 | }); 430 | 431 | it('has the right arity', function () { 432 | expect(Map.prototype.forEach).to.have.property('length', 1); 433 | }); 434 | 435 | it('should be iterable via forEach', function () { 436 | var expectedMap = { 437 | a: 1, 438 | b: 2, 439 | c: 3 440 | }; 441 | var foundMap = {}; 442 | mapToIterate.forEach(function (value, key, entireMap) { 443 | expect(entireMap).to.equal(mapToIterate); 444 | foundMap[key] = value; 445 | }); 446 | expect(foundMap).to.eql(expectedMap); 447 | }); 448 | 449 | it('should iterate over empty keys', function () { 450 | var mapWithEmptyKeys = new Map(); 451 | var expectedKeys = [{}, null, undefined, '', NaN, 0]; 452 | expectedKeys.forEach(function (key) { 453 | expect(mapWithEmptyKeys.set(key, true)).to.equal(mapWithEmptyKeys); 454 | }); 455 | var foundKeys = []; 456 | mapWithEmptyKeys.forEach(function (value, key, entireMap) { 457 | expect(entireMap.get(key)).to.equal(value); 458 | foundKeys.push(key); 459 | }); 460 | expect(foundKeys).to.be.theSameSet(expectedKeys); 461 | }); 462 | 463 | it('should support the thisArg', function () { 464 | var context = function () {}; 465 | mapToIterate.forEach(function () { 466 | expect(this).to.equal(context); 467 | }, context); 468 | }); 469 | 470 | it('should have a length of 1', function () { 471 | expect(Map.prototype.forEach.length).to.equal(1); 472 | }); 473 | 474 | it('should not revisit modified keys', function () { 475 | var hasModifiedA = false; 476 | mapToIterate.forEach(function (value, key) { 477 | if (!hasModifiedA && key === 'a') { 478 | expect(mapToIterate.set('a', 4)).to.equal(mapToIterate); 479 | hasModifiedA = true; 480 | } else { 481 | expect(key).not.to.equal('a'); 482 | } 483 | }); 484 | }); 485 | 486 | it('returns the map from #set() for chaining', function () { 487 | expect(mapToIterate.set({}, {})).to.equal(mapToIterate); 488 | expect(mapToIterate.set(42, {})).to.equal(mapToIterate); 489 | expect(mapToIterate.set(0, {})).to.equal(mapToIterate); 490 | expect(mapToIterate.set(NaN, {})).to.equal(mapToIterate); 491 | expect(mapToIterate.set(-0, {})).to.equal(mapToIterate); 492 | }); 493 | 494 | it('visits keys added in the iterator', function () { 495 | var hasAdded = false; 496 | var hasFoundD = false; 497 | mapToIterate.forEach(function (value, key) { 498 | if (!hasAdded) { 499 | mapToIterate.set('d', 5); 500 | hasAdded = true; 501 | } else if (key === 'd') { 502 | hasFoundD = true; 503 | } 504 | }); 505 | expect(hasFoundD).to.equal(true); 506 | }); 507 | 508 | it('visits keys added in the iterator when there is a deletion', function () { 509 | var hasSeenFour = false; 510 | var mapToMutate = new Map(); 511 | mapToMutate.set('0', 42); 512 | mapToMutate.forEach(function (value, key) { 513 | if (key === '0') { 514 | expect(mapToMutate['delete']('0')).to.equal(true); 515 | mapToMutate.set('4', 'a value'); 516 | } else if (key === '4') { 517 | hasSeenFour = true; 518 | } 519 | }); 520 | expect(hasSeenFour).to.equal(true); 521 | }); 522 | 523 | it('does not visit keys deleted before a visit', function () { 524 | var hasVisitedC = false; 525 | var hasDeletedC = false; 526 | mapToIterate.forEach(function (value, key) { 527 | if (key === 'c') { 528 | hasVisitedC = true; 529 | } 530 | if (!hasVisitedC && !hasDeletedC) { 531 | hasDeletedC = mapToIterate['delete']('c'); 532 | expect(hasDeletedC).to.equal(true); 533 | } 534 | }); 535 | expect(hasVisitedC).to.equal(false); 536 | }); 537 | 538 | it('should work after deletion of the current key', function () { 539 | var expectedMap = { 540 | a: 1, 541 | b: 2, 542 | c: 3 543 | }; 544 | var foundMap = {}; 545 | mapToIterate.forEach(function (value, key) { 546 | foundMap[key] = value; 547 | expect(mapToIterate['delete'](key)).to.equal(true); 548 | }); 549 | expect(foundMap).to.eql(expectedMap); 550 | }); 551 | 552 | it('should convert key -0 to +0', function () { 553 | var zeroMap = new Map(); 554 | var result = []; 555 | zeroMap.set(-0, 'a'); 556 | zeroMap.forEach(function (value, key) { 557 | result.push(String(1 / key) + ' ' + value); 558 | }); 559 | zeroMap.set(1, 'b'); 560 | zeroMap.set(0, 'c'); // shouldn't cause reordering 561 | zeroMap.forEach(function (value, key) { 562 | result.push(String(1 / key) + ' ' + value); 563 | }); 564 | expect(result.join(', ')).to.equal('Infinity a, Infinity c, 1 b'); 565 | }); 566 | }); 567 | 568 | it('should preserve insertion order', function () { 569 | var convertToPairs = function (item) { return [item, true]; }; 570 | var arr1 = ['d', 'a', 'b']; 571 | var arr2 = [3, 2, 'z', 'a', 1]; 572 | var arr3 = [3, 2, 'z', {}, 'a', 1]; 573 | 574 | [arr1, arr2, arr3].forEach(function (array) { 575 | var entries = array.map(convertToPairs); 576 | expect(new Map(entries)).to.have.entries(entries); 577 | }); 578 | }); 579 | 580 | it('map iteration', function () { 581 | var map = new Map(); 582 | map.set('a', 1); 583 | map.set('b', 2); 584 | map.set('c', 3); 585 | map.set('d', 4); 586 | 587 | var keys = []; 588 | var iterator = map.keys(); 589 | keys.push(iterator.next().value); 590 | expect(map['delete']('a')).to.equal(true); 591 | expect(map['delete']('b')).to.equal(true); 592 | expect(map['delete']('c')).to.equal(true); 593 | map.set('e'); 594 | keys.push(iterator.next().value); 595 | keys.push(iterator.next().value); 596 | 597 | expect(iterator.next().done).to.equal(true); 598 | map.set('f'); 599 | expect(iterator.next().done).to.equal(true); 600 | expect(keys).to.eql(['a', 'd', 'e']); 601 | }); 602 | 603 | ifGetPrototypeOfIt('MapIterator identification test prototype inequality', function () { 604 | var mapEntriesProto = Object.getPrototypeOf(new Map().entries()); 605 | var setEntriesProto = Object.getPrototypeOf(new Set().entries()); 606 | expect(mapEntriesProto).to.not.equal(setEntriesProto); 607 | }); 608 | 609 | it('MapIterator identification', function () { 610 | var fnMapValues = Map.prototype.values; 611 | var mapSentinel = new Map([[1, 'MapSentinel']]); 612 | var testMap = new Map(); 613 | var testMapValues = testMap.values(); 614 | expect(testMapValues.next.call(fnMapValues.call(mapSentinel)).value).to.equal('MapSentinel'); 615 | 616 | var testSet = new Set(); 617 | var testSetValues = testSet.values(); 618 | expect(function () { 619 | return testSetValues.next.call(fnMapValues.call(mapSentinel)).value; 620 | }).to['throw'](TypeError); 621 | }); 622 | }); 623 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require es5-shim 2 | --require ./es6-shim 3 | --require ./es6-sham 4 | --require test/test_helpers.js 5 | 6 | -------------------------------------------------------------------------------- /test/native.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | es6-shim tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/number.js: -------------------------------------------------------------------------------- 1 | describe('Number', function () { 2 | var functionsHaveNames = (function foo() {}).name === 'foo'; 3 | var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit; 4 | var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it; 5 | 6 | var integers = [5295, -5295, -9007199254740991, 9007199254740991, 0, -0]; 7 | var nonIntegers = [-9007199254741992, 9007199254741992, 5.9]; 8 | var infinities = [Infinity, -Infinity]; 9 | 10 | var valueOfThree = { valueOf: function () { return 3; } }; 11 | var valueOfNaN = { valueOf: function () { return NaN; } }; 12 | var valueOfThrows = { valueOf: function () { throw Object(17); } }; 13 | var toStringThrows = { toString: function () { throw Object(42); } }; 14 | var toPrimitiveThrows = { 15 | valueOf: function () { throw Object(17); }, 16 | toString: function () { throw Object(42); } 17 | }; 18 | 19 | var nonNumbers = [ 20 | undefined, 21 | true, 22 | false, 23 | null, 24 | {}, 25 | [], 26 | 'str', 27 | '', 28 | valueOfThree, 29 | valueOfNaN, 30 | valueOfThrows, 31 | toStringThrows, 32 | toPrimitiveThrows, 33 | /a/g 34 | ]; 35 | var expectTrue = function (item) { 36 | expect(item).to.equal(true); 37 | }; 38 | var expectFalse = function (item) { 39 | expect(item).to.equal(false); 40 | }; 41 | 42 | ifShimIt('is on the exported object', function () { 43 | var exported = require('../'); 44 | expect(exported.Number).to.equal(Number); 45 | }); 46 | 47 | describe('Number constants', function () { 48 | it('should have max safe integer', function () { 49 | expect(Number).to.have.property('MAX_SAFE_INTEGER'); 50 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'MAX_SAFE_INTEGER')).to.equal(false); 51 | expect(Number.MAX_SAFE_INTEGER).to.equal(Math.pow(2, 53) - 1); 52 | }); 53 | 54 | it('should have min safe integer', function () { 55 | expect(Number).to.have.property('MIN_SAFE_INTEGER'); 56 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'MIN_SAFE_INTEGER')).to.equal(false); 57 | expect(Number.MIN_SAFE_INTEGER).to.equal(-Math.pow(2, 53) + 1); 58 | }); 59 | 60 | it('should have epsilon', function () { 61 | expect(Number).to.have.property('EPSILON'); 62 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'EPSILON')).to.equal(false); 63 | expect(Number.EPSILON).to.equal(2.2204460492503130808472633361816e-16); 64 | }); 65 | 66 | it('should have NaN', function () { 67 | expect(Number).to.have.property('NaN'); 68 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'NaN')).to.equal(false); 69 | expect(isNaN(Number.NaN)).to.equal(true); 70 | }); 71 | 72 | it('should have MAX_VALUE', function () { 73 | expect(Number).to.have.property('MAX_VALUE'); 74 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'MAX_VALUE')).to.equal(false); 75 | expect(Number.MAX_VALUE).to.equal(1.7976931348623157e+308); 76 | }); 77 | 78 | it('should have MIN_VALUE', function () { 79 | expect(Number).to.have.property('MIN_VALUE'); 80 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'MIN_VALUE')).to.equal(false); 81 | expect(Number.MIN_VALUE).to.equal(5e-324); 82 | }); 83 | 84 | it('should have NEGATIVE_INFINITY', function () { 85 | expect(Number).to.have.property('NEGATIVE_INFINITY'); 86 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'NEGATIVE_INFINITY')).to.equal(false); 87 | expect(Number.NEGATIVE_INFINITY).to.equal(-Infinity); 88 | }); 89 | 90 | it('should have POSITIVE_INFINITY', function () { 91 | expect(Number).to.have.property('POSITIVE_INFINITY'); 92 | expect(Object.prototype.propertyIsEnumerable.call(Number, 'POSITIVE_INFINITY')).to.equal(false); 93 | expect(Number.POSITIVE_INFINITY).to.equal(Infinity); 94 | }); 95 | }); 96 | 97 | describe('.parseInt()', function () { 98 | if (!Object.prototype.hasOwnProperty.call(Number, 'parseInt')) { 99 | return it('exists', function () { 100 | expect(Number).to.have.property('parseInt'); 101 | }); 102 | } 103 | 104 | it('should work', function () { 105 | /* eslint-disable radix */ 106 | expect(Number.parseInt('601')).to.equal(601); 107 | /* eslint-enable radix */ 108 | }); 109 | 110 | ifFunctionsHaveNamesIt('has the right name', function () { 111 | expect(Number.parseInt).to.have.property('name', 'parseInt'); 112 | }); 113 | 114 | it('is not enumerable', function () { 115 | expect(Number).ownPropertyDescriptor('parseInt').to.have.property('enumerable', false); 116 | }); 117 | 118 | it('has the right arity', function () { 119 | // WebKit nightly had the wrong length; fixed in https://bugs.webkit.org/show_bug.cgi?id=143657 120 | expect(Number.parseInt).to.have.property('length', 2); 121 | }); 122 | 123 | it('is the same object as the global parseInt', function () { 124 | // fixed in WebKit nightly in https://bugs.webkit.org/show_bug.cgi?id=143799#add_comment 125 | expect(Number.parseInt).to.equal(parseInt); 126 | }); 127 | }); 128 | 129 | describe('.parseFloat()', function () { 130 | if (!Object.prototype.hasOwnProperty.call(Number, 'parseFloat')) { 131 | return it('exists', function () { 132 | expect(Number).to.have.property('parseFloat'); 133 | }); 134 | } 135 | 136 | it('should work', function () { 137 | expect(Number.parseFloat('5.5')).to.equal(5.5); 138 | }); 139 | 140 | ifFunctionsHaveNamesIt('has the right name', function () { 141 | expect(Number.parseFloat).to.have.property('name', 'parseFloat'); 142 | }); 143 | 144 | it('is not enumerable', function () { 145 | expect(Number).ownPropertyDescriptor('parseFloat').to.have.property('enumerable', false); 146 | }); 147 | 148 | it('has the right arity', function () { 149 | expect(Number.parseFloat).to.have.property('length', 1); 150 | }); 151 | }); 152 | 153 | describe('.isFinite()', function () { 154 | if (!Object.prototype.hasOwnProperty.call(Number, 'isFinite')) { 155 | return it('exists', function () { 156 | expect(Number).to.have.property('isFinite'); 157 | }); 158 | } 159 | 160 | ifFunctionsHaveNamesIt('has the right name', function () { 161 | expect(Number.isFinite).to.have.property('name', 'isFinite'); 162 | }); 163 | 164 | it('is not enumerable', function () { 165 | expect(Number).ownPropertyDescriptor('isFinite').to.have.property('enumerable', false); 166 | }); 167 | 168 | it('has the right arity', function () { 169 | expect(Number.isFinite).to.have.property('length', 1); 170 | }); 171 | 172 | it('should work', function () { 173 | integers.map(Number.isFinite).forEach(expectTrue); 174 | infinities.map(Number.isFinite).forEach(expectFalse); 175 | expect(Number.isFinite(Infinity)).to.equal(false); 176 | expect(Number.isFinite(-Infinity)).to.equal(false); 177 | expect(Number.isFinite(NaN)).to.equal(false); 178 | expect(Number.isFinite(4)).to.equal(true); 179 | expect(Number.isFinite(4.5)).to.equal(true); 180 | expect(Number.isFinite('hi')).to.equal(false); 181 | expect(Number.isFinite('1.3')).to.equal(false); 182 | expect(Number.isFinite('51')).to.equal(false); 183 | expect(Number.isFinite(0)).to.equal(true); 184 | expect(Number.isFinite(-0)).to.equal(true); 185 | expect(Number.isFinite(valueOfThree)).to.equal(false); 186 | expect(Number.isFinite(valueOfNaN)).to.equal(false); 187 | expect(Number.isFinite(valueOfThrows)).to.equal(false); 188 | expect(Number.isFinite(toStringThrows)).to.equal(false); 189 | expect(Number.isFinite(toPrimitiveThrows)).to.equal(false); 190 | }); 191 | 192 | it('should not be confused by type coercion', function () { 193 | nonNumbers.map(Number.isFinite).forEach(expectFalse); 194 | }); 195 | }); 196 | 197 | describe('.isInteger()', function () { 198 | if (!Object.prototype.hasOwnProperty.call(Number, 'isInteger')) { 199 | return it('exists', function () { 200 | expect(Number).to.have.property('isInteger'); 201 | }); 202 | } 203 | 204 | ifFunctionsHaveNamesIt('has the right name', function () { 205 | expect(Number.isInteger).to.have.property('name', 'isInteger'); 206 | }); 207 | 208 | it('is not enumerable', function () { 209 | expect(Number).ownPropertyDescriptor('isInteger').to.have.property('enumerable', false); 210 | }); 211 | 212 | it('has the right arity', function () { 213 | expect(Number.isInteger).to.have.property('length', 1); 214 | }); 215 | 216 | it('should be truthy on integers', function () { 217 | integers.map(Number.isInteger).forEach(expectTrue); 218 | expect(Number.isInteger(4)).to.equal(true); 219 | expect(Number.isInteger(4.0)).to.equal(true); 220 | expect(Number.isInteger(1801439850948)).to.equal(true); 221 | }); 222 | 223 | it('should be false when the type is not number', function () { 224 | nonNumbers.forEach(function (thing) { 225 | expect(Number.isInteger(thing)).to.equal(false); 226 | }); 227 | }); 228 | 229 | it('should be false when NaN', function () { 230 | expect(Number.isInteger(NaN)).to.equal(false); 231 | }); 232 | 233 | it('should be false when ∞', function () { 234 | expect(Number.isInteger(Infinity)).to.equal(false); 235 | expect(Number.isInteger(-Infinity)).to.equal(false); 236 | }); 237 | 238 | it('should be false when number is not integer', function () { 239 | expect(Number.isInteger(3.4)).to.equal(false); 240 | expect(Number.isInteger(-3.4)).to.equal(false); 241 | }); 242 | 243 | it('should be true when abs(number) is 2^53 or larger', function () { 244 | expect(Number.isInteger(Math.pow(2, 53))).to.equal(true); 245 | expect(Number.isInteger(Math.pow(2, 54))).to.equal(true); 246 | expect(Number.isInteger(-Math.pow(2, 53))).to.equal(true); 247 | expect(Number.isInteger(-Math.pow(2, 54))).to.equal(true); 248 | }); 249 | 250 | it('should be true when abs(number) is less than 2^53', function () { 251 | var safeIntegers = [0, 1, Math.pow(2, 53) - 1]; 252 | safeIntegers.forEach(function (integer) { 253 | expect(Number.isInteger(integer)).to.equal(true); 254 | expect(Number.isInteger(-integer)).to.equal(true); 255 | }); 256 | }); 257 | }); 258 | 259 | describe('.isSafeInteger()', function () { 260 | if (!Object.prototype.hasOwnProperty.call(Number, 'isSafeInteger')) { 261 | return it('exists', function () { 262 | expect(Number).to.have.property('isSafeInteger'); 263 | }); 264 | } 265 | 266 | ifFunctionsHaveNamesIt('has the right name', function () { 267 | expect(Number.isSafeInteger).to.have.property('name', 'isSafeInteger'); 268 | }); 269 | 270 | it('is not enumerable', function () { 271 | expect(Number).ownPropertyDescriptor('isSafeInteger').to.have.property('enumerable', false); 272 | }); 273 | 274 | it('has the right arity', function () { 275 | expect(Number.isSafeInteger).to.have.property('length', 1); 276 | }); 277 | 278 | it('should be truthy on integers', function () { 279 | integers.map(Number.isSafeInteger).forEach(expectTrue); 280 | expect(Number.isSafeInteger(4)).to.equal(true); 281 | expect(Number.isSafeInteger(4.0)).to.equal(true); 282 | expect(Number.isSafeInteger(1801439850948)).to.equal(true); 283 | }); 284 | 285 | it('should be false when the type is not number', function () { 286 | nonNumbers.forEach(function (thing) { 287 | expect(Number.isSafeInteger(thing)).to.equal(false); 288 | }); 289 | }); 290 | 291 | it('should be false when NaN', function () { 292 | expect(Number.isSafeInteger(NaN)).to.equal(false); 293 | }); 294 | 295 | it('should be false when ∞', function () { 296 | expect(Number.isSafeInteger(Infinity)).to.equal(false); 297 | expect(Number.isSafeInteger(-Infinity)).to.equal(false); 298 | }); 299 | 300 | it('should be false when number is not integer', function () { 301 | expect(Number.isSafeInteger(3.4)).to.equal(false); 302 | expect(Number.isSafeInteger(-3.4)).to.equal(false); 303 | }); 304 | 305 | it('should be false when abs(number) is 2^53 or larger', function () { 306 | expect(Number.isSafeInteger(Math.pow(2, 53))).to.equal(false); 307 | expect(Number.isSafeInteger(Math.pow(2, 54))).to.equal(false); 308 | expect(Number.isSafeInteger(-Math.pow(2, 53))).to.equal(false); 309 | expect(Number.isSafeInteger(-Math.pow(2, 54))).to.equal(false); 310 | }); 311 | 312 | it('should be true when abs(number) is less than 2^53', function () { 313 | var safeIntegers = [0, 1, Math.pow(2, 53) - 1]; 314 | safeIntegers.forEach(function (integer) { 315 | expect(Number.isSafeInteger(integer)).to.equal(true); 316 | expect(Number.isSafeInteger(-integer)).to.equal(true); 317 | }); 318 | }); 319 | }); 320 | 321 | describe('.isNaN()', function () { 322 | if (!Object.prototype.hasOwnProperty.call(Number, 'isNaN')) { 323 | return it('exists', function () { 324 | expect(Number).to.have.property('isNaN'); 325 | }); 326 | } 327 | 328 | ifFunctionsHaveNamesIt('has the right name', function () { 329 | expect(Number.isNaN).to.have.property('name', 'isNaN'); 330 | }); 331 | 332 | it('is not enumerable', function () { 333 | expect(Number).ownPropertyDescriptor('isNaN').to.have.property('enumerable', false); 334 | }); 335 | 336 | it('has the right arity', function () { 337 | expect(Number.isNaN).to.have.property('length', 1); 338 | }); 339 | 340 | it('should be truthy only on NaN', function () { 341 | integers.concat(nonIntegers).map(Number.isNaN).forEach(expectFalse); 342 | nonNumbers.map(Number.isNaN).forEach(expectFalse); 343 | expect(Number.isNaN(NaN)).to.equal(true); 344 | expect(Number.isNaN(0 / 0)).to.equal(true); 345 | expect(Number.isNaN(Number('NaN'))).to.equal(true); 346 | expect(Number.isNaN(4)).to.equal(false); 347 | expect(Number.isNaN(4.5)).to.equal(false); 348 | expect(Number.isNaN('hi')).to.equal(false); 349 | expect(Number.isNaN('1.3')).to.equal(false); 350 | expect(Number.isNaN('51')).to.equal(false); 351 | expect(Number.isNaN(0)).to.equal(false); 352 | expect(Number.isNaN(-0)).to.equal(false); 353 | expect(Number.isNaN(valueOfThree)).to.equal(false); 354 | expect(Number.isNaN(valueOfNaN)).to.equal(false); 355 | expect(Number.isNaN(valueOfThrows)).to.equal(false); 356 | expect(Number.isNaN(toStringThrows)).to.equal(false); 357 | expect(Number.isNaN(toPrimitiveThrows)).to.equal(false); 358 | }); 359 | }); 360 | 361 | describe('constructor', function () { 362 | it('behaves like the builtin', function () { 363 | expect((1).constructor).to.equal(Number); 364 | expect(Number()).to.equal(0); 365 | }); 366 | 367 | describe('strings in the constructor', function () { 368 | it('works on normal literals', function () { 369 | expect(Number('1')).to.equal(+'1'); 370 | expect(Number('1.1')).to.equal(+'1.1'); 371 | expect(Number('0xA')).to.equal(0xA); 372 | }); 373 | }); 374 | 375 | describe('when called with a receiver', function () { 376 | it('returns a primitive when called with a primitive receiver', function () { 377 | expect((1).constructor(2)).to.equal(2); 378 | expect((1).constructor.call(null, 3)).to.equal(3); 379 | expect(Object(1).constructor.call(null, 5)).to.equal(5); 380 | }); 381 | 382 | it('returns a primitive when called with a different number as an object receiver', function () { 383 | expect(Object(1).constructor(6)).to.equal(6); 384 | expect(Object(1).constructor.call(Object(1), 7)).to.equal(7); 385 | }); 386 | 387 | it('returns a primitive when called with the same number as an object receiver', function () { 388 | expect(Object(1).constructor.call(Object(8), 8)).to.equal(8); 389 | }); 390 | }); 391 | 392 | it('works with boxed primitives', function () { 393 | expect(1 instanceof Number).to.equal(false); 394 | expect(Object(1) instanceof Number).to.equal(true); 395 | }); 396 | 397 | it('works with `new`', function () { 398 | /* eslint-disable no-new-wrappers */ 399 | var one = new Number('1'); 400 | var a = new Number('0xA'); 401 | /* eslint-enable no-new-wrappers */ 402 | 403 | expect(+one).to.equal(1); 404 | expect(one instanceof Number).to.equal(true); 405 | expect(+a).to.equal(0xA); 406 | expect(a instanceof Number).to.equal(true); 407 | }); 408 | 409 | it('works with binary literals in string form', function () { 410 | expect(Number('0b1')).to.equal(1); 411 | expect(Number(' 0b1')).to.equal(1); 412 | expect(Number('0b1 ')).to.equal(1); 413 | 414 | expect(Number('0b10')).to.equal(2); 415 | expect(Number(' 0b10')).to.equal(2); 416 | expect(Number('0b10 ')).to.equal(2); 417 | 418 | expect(Number('0b11')).to.equal(3); 419 | expect(Number(' 0b11')).to.equal(3); 420 | expect(Number('0b11 ')).to.equal(3); 421 | 422 | expect(Number({ 423 | toString: function () { return '0b100'; }, 424 | valueOf: function () { return '0b101'; } 425 | })).to.equal(5); 426 | }); 427 | 428 | it('works with octal literals in string form', function () { 429 | expect(Number('0o7')).to.equal(7); 430 | expect(Number('0o10')).to.equal(8); 431 | expect(Number('0o11')).to.equal(9); 432 | expect(Number({ 433 | toString: function () { return '0o12'; }, 434 | valueOf: function () { return '0o13'; } 435 | })).to.equal(11); 436 | }); 437 | 438 | it('should produce NaN', function () { 439 | expect(String(Number('0b12'))).to.equal('NaN'); 440 | expect(String(Number('0o18'))).to.equal('NaN'); 441 | expect(String(Number('0x1g'))).to.equal('NaN'); 442 | expect(String(Number('+0b1'))).to.equal('NaN'); 443 | expect(String(Number('+0o1'))).to.equal('NaN'); 444 | expect(String(Number('+0x1'))).to.equal('NaN'); 445 | expect(String(Number('-0b1'))).to.equal('NaN'); 446 | expect(String(Number('-0o1'))).to.equal('NaN'); 447 | expect(String(Number('-0x1'))).to.equal('NaN'); 448 | }); 449 | 450 | it('should work with well formed and poorly formed objects', function () { 451 | expect(String(Number({}))).to.equal('NaN'); 452 | expect(String(Number({ valueOf: '1.1' }))).to.equal('NaN'); 453 | expect(Number({ valueOf: '1.1', toString: function () { return '2.2'; } })).to.equal(2.2); 454 | expect(Number({ valueOf: function () { return '1.1'; }, toString: '2.2' })).to.equal(1.1); 455 | expect(Number({ 456 | valueOf: function () { return '1.1'; }, 457 | toString: function () { return '2.2'; } 458 | })).to.equal(1.1); 459 | expect(String(Number({ valueOf: function () { return '-0x1a2b3c'; } }))).to.equal('NaN'); 460 | expect(String(Number({ toString: function () { return '-0x1a2b3c'; } }))).to.equal('NaN'); 461 | expect(Number({ valueOf: function () { return '0o12345'; } })).to.equal(5349); 462 | expect(Number({ toString: function () { return '0o12345'; } })).to.equal(5349); 463 | expect(Number({ valueOf: function () { return '0b101010'; } })).to.equal(42); 464 | expect(Number({ toString: function () { return '0b101010'; } })).to.equal(42); 465 | }); 466 | 467 | it('should work with correct whitespaces', function () { 468 | // Zero-width space (zws), next line character (nel), and non-character (bom) are not whitespace. 469 | var nonWhitespaces = ['\u0085', '\u200b', '\ufffe']; 470 | 471 | expect(String(Number(nonWhitespaces[0] + '0' + nonWhitespaces[0]))).to.equal('NaN'); 472 | expect(String(Number(nonWhitespaces[1] + '1' + nonWhitespaces[1]))).to.equal('NaN'); 473 | expect(String(Number(nonWhitespaces[2] + '2' + nonWhitespaces[2]))).to.equal('NaN'); 474 | }); 475 | 476 | it.skip('it works with updated unicode values', function () { 477 | var whitespace = ' \t\x0b\f\xa0\ufeff\n\r\u2028\u2029\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'; 478 | 479 | expect(String(Number(whitespace + '3' + whitespace))).to.equal('3'); 480 | }); 481 | }); 482 | }); 483 | -------------------------------------------------------------------------------- /test/object.js: -------------------------------------------------------------------------------- 1 | describe('Object', function () { 2 | var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it; 3 | 4 | ifShimIt('is on the exported object', function () { 5 | var exported = require('../'); 6 | expect(exported.Object).to.equal(Object); 7 | }); 8 | 9 | var functionsHaveNames = (function foo() {}).name === 'foo'; 10 | var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit; 11 | var ifExtensionsPreventable = Object.preventExtensions ? it : xit; 12 | 13 | var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol'; 14 | var ifSymbolsIt = hasSymbols ? it : xit; 15 | var ifBrowserIt = typeof window === 'object' && typeof document === 'object' ? it : xit; 16 | var ifObjectGetPrototypeOfIt = typeof Object.getPrototypeOf === 'function' ? it : xit; 17 | 18 | if (Object.getOwnPropertyNames) { 19 | describe('.getOwnPropertyNames()', function () { 20 | it('throws on null or undefined', function () { 21 | expect(function () { Object.getOwnPropertyNames(); }).to['throw'](TypeError); 22 | expect(function () { Object.getOwnPropertyNames(undefined); }).to['throw'](TypeError); 23 | expect(function () { Object.getOwnPropertyNames(null); }).to['throw'](TypeError); 24 | }); 25 | 26 | it('works on primitives', function () { 27 | [true, false, NaN, 42, /a/g, 'foo'].forEach(function (item) { 28 | expect(Object.getOwnPropertyNames(item)).to.eql(Object.getOwnPropertyNames(Object(item))); 29 | }); 30 | }); 31 | 32 | ifBrowserIt('does not break when an iframe is added', function () { 33 | var div = document.createElement('div'); 34 | div.innerHTML = ''; 35 | document.body.appendChild(div); 36 | setTimeout(function () { 37 | document.body.removeChild(div); 38 | }, 0); 39 | expect(Array.isArray(Object.getOwnPropertyNames(window))).to.eql(true); 40 | }); 41 | }); 42 | } 43 | 44 | if (Object.getOwnPropertyDescriptor) { 45 | describe('.getOwnPropertyDescriptor()', function () { 46 | it('throws on null or undefined', function () { 47 | expect(function () { Object.getOwnPropertyDescriptor(); }).to['throw'](TypeError); 48 | expect(function () { Object.getOwnPropertyDescriptor(undefined); }).to['throw'](TypeError); 49 | expect(function () { Object.getOwnPropertyDescriptor(null); }).to['throw'](TypeError); 50 | }); 51 | 52 | it('works on primitives', function () { 53 | [true, false, NaN, 42, /a/g, 'foo'].forEach(function (item) { 54 | expect(Object.getOwnPropertyDescriptor(item, 'foo')).to.eql(Object.getOwnPropertyDescriptor(Object(item), 'foo')); 55 | }); 56 | }); 57 | }); 58 | } 59 | 60 | if (Object.seal) { 61 | describe('.seal()', function () { 62 | it('works on primitives', function () { 63 | [null, undefined, true, false, NaN, 42, 'foo'].forEach(function (item) { 64 | expect(Object.seal(item)).to.eql(item); 65 | }); 66 | }); 67 | }); 68 | } 69 | 70 | if (Object.isSealed) { 71 | describe('.isSealed()', function () { 72 | it('works on primitives', function () { 73 | [null, undefined, true, false, NaN, 42, 'foo'].forEach(function (item) { 74 | expect(Object.isSealed(item)).to.equal(true); 75 | }); 76 | }); 77 | }); 78 | } 79 | 80 | if (Object.freeze) { 81 | describe('.freeze()', function () { 82 | it('works on primitives', function () { 83 | [null, undefined, true, false, NaN, 42, 'foo'].forEach(function (item) { 84 | expect(Object.freeze(item)).to.eql(item); 85 | }); 86 | }); 87 | }); 88 | } 89 | 90 | if (Object.isFrozen) { 91 | describe('.isFrozen()', function () { 92 | it('works on primitives', function () { 93 | [null, undefined, true, false, NaN, 42, 'foo'].forEach(function (item) { 94 | expect(Object.isFrozen(item)).to.equal(true); 95 | }); 96 | }); 97 | }); 98 | } 99 | 100 | if (Object.preventExtensions) { 101 | describe('.preventExtensions()', function () { 102 | it('works on primitives', function () { 103 | [null, undefined, true, false, NaN, 42, 'foo'].forEach(function (item) { 104 | expect(Object.preventExtensions(item)).to.eql(item); 105 | }); 106 | }); 107 | }); 108 | } 109 | 110 | if (Object.isExtensible) { 111 | describe('.isExtensible()', function () { 112 | it('works on primitives', function () { 113 | [null, undefined, true, false, NaN, 42, 'foo'].forEach(function (item) { 114 | expect(Object.isExtensible(item)).to.equal(false); 115 | }); 116 | }); 117 | }); 118 | } 119 | 120 | describe('.keys()', function () { 121 | it('works on strings', function () { 122 | expect(Object.keys('foo')).to.eql(['0', '1', '2']); 123 | }); 124 | 125 | it('throws on null or undefined', function () { 126 | expect(function () { Object.keys(); }).to['throw'](TypeError); 127 | expect(function () { Object.keys(undefined); }).to['throw'](TypeError); 128 | expect(function () { Object.keys(null); }).to['throw'](TypeError); 129 | }); 130 | 131 | it('works on other primitives', function () { 132 | [true, false, NaN, 42, /a/g].forEach(function (item) { 133 | expect(Object.keys(item)).to.eql([]); 134 | }); 135 | }); 136 | }); 137 | 138 | describe('.is()', function () { 139 | if (!Object.prototype.hasOwnProperty.call(Object, 'is')) { 140 | return it('exists', function () { 141 | expect(Object).to.have.property('is'); 142 | }); 143 | } 144 | 145 | ifFunctionsHaveNamesIt('has the right name', function () { 146 | expect(Object.is).to.have.property('name', 'is'); 147 | }); 148 | 149 | it('should have the right arity', function () { 150 | expect(Object.is).to.have.property('length', 2); 151 | }); 152 | 153 | it('should compare regular objects correctly', function () { 154 | [null, undefined, [0], 5, 'str', { a: null }].map(function (item) { 155 | return Object.is(item, item); 156 | }).forEach(function (result) { 157 | expect(result).to.equal(true); 158 | }); 159 | }); 160 | 161 | it('should compare 0 and -0 correctly', function () { 162 | expect(Object.is(0, -0)).to.equal(false); 163 | }); 164 | 165 | it('should compare NaNs correctly', function () { 166 | expect(Object.is(NaN, NaN)).to.equal(true); 167 | }); 168 | }); 169 | 170 | describe('.assign()', function () { 171 | if (!Object.prototype.hasOwnProperty.call(Object, 'assign')) { 172 | return it('exists', function () { 173 | expect(Object).to.have.property('assign'); 174 | }); 175 | } 176 | 177 | it('has the correct length', function () { 178 | expect(Object.assign.length).to.eql(2); 179 | }); 180 | 181 | it('returns the modified target object', function () { 182 | var target = {}; 183 | var returned = Object.assign(target, { a: 1 }); 184 | expect(returned).to.equal(target); 185 | }); 186 | 187 | it('should merge two objects', function () { 188 | var target = { a: 1 }; 189 | var returned = Object.assign(target, { b: 2 }); 190 | expect(returned).to.eql({ a: 1, b: 2 }); 191 | }); 192 | 193 | it('should merge three objects', function () { 194 | var target = { a: 1 }; 195 | var source1 = { b: 2 }; 196 | var source2 = { c: 3 }; 197 | var returned = Object.assign(target, source1, source2); 198 | expect(returned).to.eql({ a: 1, b: 2, c: 3 }); 199 | }); 200 | 201 | it('only iterates over own keys', function () { 202 | var Foo = function () {}; 203 | Foo.prototype.bar = true; 204 | var foo = new Foo(); 205 | foo.baz = true; 206 | var target = { a: 1 }; 207 | var returned = Object.assign(target, foo); 208 | expect(returned).to.equal(target); 209 | expect(target).to.eql({ baz: true, a: 1 }); 210 | }); 211 | 212 | it('throws when target is null or undefined', function () { 213 | expect(function () { Object.assign(null); }).to['throw'](TypeError); 214 | expect(function () { Object.assign(undefined); }).to['throw'](TypeError); 215 | }); 216 | 217 | it('coerces lone target to an object', function () { 218 | var result = { 219 | bool: Object.assign(true), 220 | number: Object.assign(1), 221 | string: Object.assign('1') 222 | }; 223 | 224 | expect(typeof result.bool).to.equal('object'); 225 | expect(Boolean.prototype.valueOf.call(result.bool)).to.equal(true); 226 | 227 | expect(typeof result.number).to.equal('object'); 228 | expect(Number.prototype.valueOf.call(result.number)).to.equal(1); 229 | 230 | expect(typeof result.string).to.equal('object'); 231 | expect(String.prototype.valueOf.call(result.string)).to.equal('1'); 232 | }); 233 | 234 | it('coerces target to an object, assigns from sources', function () { 235 | var sourceA = { a: 1 }; 236 | var sourceB = { b: 1 }; 237 | 238 | var result = { 239 | bool: Object.assign(true, sourceA, sourceB), 240 | number: Object.assign(1, sourceA, sourceB), 241 | string: Object.assign('1', sourceA, sourceB) 242 | }; 243 | 244 | expect(typeof result.bool).to.equal('object'); 245 | expect(Boolean.prototype.valueOf.call(result.bool)).to.equal(true); 246 | expect(result.bool).to.eql({ a: 1, b: 1 }); 247 | 248 | expect(typeof result.number).to.equal('object'); 249 | expect(Number.prototype.valueOf.call(result.number)).to.equal(1); 250 | 251 | expect(typeof result.string).to.equal('object'); 252 | expect(String.prototype.valueOf.call(result.string)).to.equal('1'); 253 | expect(result.string).to.eql({ 0: '1', a: 1, b: 1 }); 254 | }); 255 | 256 | it('ignores non-object sources', function () { 257 | expect(Object.assign({ a: 1 }, null, { b: 2 })).to.eql({ a: 1, b: 2 }); 258 | expect(Object.assign({ a: 1 }, undefined, { b: 2 })).to.eql({ a: 1, b: 2 }); 259 | expect(Object.assign({ a: 1 }, { b: 2 }, null)).to.eql({ a: 1, b: 2 }); 260 | }); 261 | 262 | ifExtensionsPreventable('does not have pending exceptions', function () { 263 | 'use strict'; 264 | 265 | // Firefox 37 still has "pending exception" logic in its Object.assign implementation, 266 | // which is 72% slower than our shim, and Firefox 40's native implementation. 267 | var thrower = { 1: 2, 2: 3, 3: 4 }; 268 | Object.defineProperty(thrower, 2, { 269 | get: function () { return 3; }, 270 | set: function (v) { throw new RangeError('IE 9 does not throw on preventExtensions: ' + v); } 271 | }); 272 | Object.preventExtensions(thrower); 273 | expect(thrower).to.have.property(2, 3); 274 | var error; 275 | try { 276 | Object.assign(thrower, 'wxyz'); 277 | } catch (e) { 278 | error = e; 279 | } 280 | expect(thrower).not.to.have.property(0); 281 | if (thrower[1] === 'x') { 282 | // IE 9 doesn't throw in strict mode with preventExtensions 283 | expect(error).to.be.an.instanceOf(RangeError); 284 | } else { 285 | expect(error).to.be.an.instanceOf(TypeError); 286 | expect(thrower).to.have.property(1, 2); 287 | } 288 | expect(thrower).to.have.property(2, 3); 289 | expect(thrower).to.have.property(3, 4); 290 | }); 291 | 292 | ifSymbolsIt('includes enumerable symbols, after keys', function () { 293 | /* eslint max-statements-per-line: 1 */ 294 | var visited = []; 295 | var obj = {}; 296 | Object.defineProperty(obj, 'a', { get: function () { visited.push('a'); return 42; }, enumerable: true }); 297 | var symbol = Symbol('enumerable'); 298 | Object.defineProperty(obj, symbol, { 299 | get: function () { visited.push(symbol); return Infinity; }, 300 | enumerable: true 301 | }); 302 | var nonEnumSymbol = Symbol('non-enumerable'); 303 | Object.defineProperty(obj, nonEnumSymbol, { 304 | get: function () { visited.push(nonEnumSymbol); return -Infinity; }, 305 | enumerable: false 306 | }); 307 | var target = Object.assign({}, obj); 308 | expect(visited).to.eql(['a', symbol]); 309 | expect(target.a).to.equal(42); 310 | expect(target[symbol]).to.equal(Infinity); 311 | expect(target[nonEnumSymbol]).not.to.equal(-Infinity); 312 | }); 313 | }); 314 | 315 | describe('Object.setPrototypeOf()', function () { 316 | if (!Object.setPrototypeOf) { 317 | return; // IE < 11 318 | } 319 | 320 | describe('argument checking', function () { 321 | it('should throw TypeError if first arg is not object', function () { 322 | var nonObjects = [null, undefined, true, false, 1, 3, 'foo']; 323 | nonObjects.forEach(function (value) { 324 | expect(function () { Object.setPrototypeOf(value); }).to['throw'](TypeError); 325 | }); 326 | }); 327 | 328 | it('should throw TypeError if second arg is not object or null', function () { 329 | expect(function () { Object.setPrototypeOf({}, null); }).not.to['throw'](TypeError); 330 | var invalidPrototypes = [true, false, 1, 3, 'foo']; 331 | invalidPrototypes.forEach(function (proto) { 332 | expect(function () { Object.setPrototypeOf({}, proto); }).to['throw'](TypeError); 333 | }); 334 | }); 335 | }); 336 | 337 | describe('set prototype', function () { 338 | it('should work', function () { 339 | var Foo = function () {}; 340 | var Bar = {}; 341 | var foo = new Foo(); 342 | expect(Object.getPrototypeOf(foo)).to.equal(Foo.prototype); 343 | 344 | var fooBar = Object.setPrototypeOf(foo, Bar); 345 | expect(fooBar).to.equal(foo); 346 | expect(Object.getPrototypeOf(foo)).to.equal(Bar); 347 | }); 348 | it('should be able to set to null', function () { 349 | var Foo = function () {}; 350 | var foo = new Foo(); 351 | 352 | var fooNull = Object.setPrototypeOf(foo, null); 353 | expect(fooNull).to.equal(foo); 354 | expect(Object.getPrototypeOf(foo)).to.equal(null); 355 | }); 356 | }); 357 | }); 358 | 359 | describe('.getPrototypeOf()', function () { 360 | ifObjectGetPrototypeOfIt('does not throw for a primitive', function () { 361 | expect(Object.getPrototypeOf(3)).to.equal(Number.prototype); 362 | }); 363 | }); 364 | }); 365 | -------------------------------------------------------------------------------- /test/promise.js: -------------------------------------------------------------------------------- 1 | /* This file is for testing implementation regressions of Promises. */ 2 | 3 | describe('Promise', function () { 4 | if (typeof Promise === 'undefined') { 5 | return it('exists', function () { 6 | expect(typeof Promise).to.be('function'); 7 | }); 8 | } 9 | 10 | var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it; 11 | 12 | ifShimIt('is on the exported object', function () { 13 | var exported = require('../'); 14 | expect(exported.Promise).to.equal(Promise); 15 | }); 16 | 17 | it('ignores non-function .then arguments', function () { 18 | expect(function () { 19 | Promise.reject(42).then(null, 5).then(null, function () {}); 20 | }).not.to['throw'](); 21 | }); 22 | 23 | describe('extra methods (bad Chrome!)', function () { 24 | it('does not have accept', function () { 25 | expect(Promise).not.to.have.property('accept'); 26 | }); 27 | 28 | it('does not have defer', function () { 29 | expect(Promise).not.to.have.property('defer'); 30 | }); 31 | 32 | it('does not have chain', function () { 33 | expect(Promise.prototype).not.to.have.property('chain'); 34 | }); 35 | }); 36 | 37 | it('requires an object context', function () { 38 | // this fails in Safari 7.1 - 9 39 | expect(function promiseDotCallThree() { 40 | Promise.call(3, function () {}); 41 | }).to['throw'](); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /test/promise/all.js: -------------------------------------------------------------------------------- 1 | var failIfThrows = function (done) { 2 | 'use strict'; 3 | 4 | return function (e) { 5 | done(e || new Error()); 6 | }; 7 | }; 8 | 9 | describe('Promise.all', function () { 10 | 'use strict'; 11 | 12 | it('should not be enumerable', function () { 13 | expect(Promise).ownPropertyDescriptor('all').to.have.property('enumerable', false); 14 | }); 15 | 16 | it('fulfills if passed an empty array', function (done) { 17 | var iterable = []; 18 | 19 | Promise.all(iterable).then(function (value) { 20 | assert(Array.isArray(value)); 21 | assert.deepEqual(value, []); 22 | }).then(done, failIfThrows(done)); 23 | }); 24 | 25 | it('fulfills if passed an empty array-like', function (done) { 26 | var f = function () { 27 | Promise.all(arguments).then(function (value) { 28 | assert(Array.isArray(value)); 29 | assert.deepEqual(value, []); 30 | }).then(done, failIfThrows(done)); 31 | }; 32 | f(); 33 | }); 34 | 35 | it('fulfills if passed an array of mixed fulfilled promises and values', function (done) { 36 | var iterable = [0, Promise.resolve(1), 2, Promise.resolve(3)]; 37 | 38 | Promise.all(iterable).then(function (value) { 39 | assert(Array.isArray(value)); 40 | assert.deepEqual(value, [0, 1, 2, 3]); 41 | }).then(done, failIfThrows(done)); 42 | }); 43 | 44 | it('rejects if any passed promise is rejected', function (done) { 45 | var foreverPending = new Promise(function () { }); 46 | var error = new Error('Rejected'); 47 | var rejected = Promise.reject(error); 48 | 49 | var iterable = [foreverPending, rejected]; 50 | 51 | Promise.all(iterable).then( 52 | function () { 53 | assert(false, 'should never get here'); 54 | }, 55 | function (reason) { 56 | assert.strictEqual(reason, error); 57 | } 58 | ).then(done, failIfThrows(done)); 59 | }); 60 | 61 | it('resolves foreign thenables', function (done) { 62 | var normal = Promise.resolve(1); 63 | var foreign = { then: function (f) { f(2); } }; 64 | 65 | var iterable = [normal, foreign]; 66 | 67 | Promise.all(iterable).then(function (value) { 68 | assert.deepEqual(value, [1, 2]); 69 | }).then(done, failIfThrows(done)); 70 | }); 71 | 72 | it('fulfills when passed an sparse array, giving `undefined` for the omitted values', function (done) { 73 | /* eslint-disable no-sparse-arrays */ 74 | var iterable = [Promise.resolve(0), , , Promise.resolve(1)]; 75 | /* eslint-enable no-sparse-arrays */ 76 | 77 | Promise.all(iterable).then(function (value) { 78 | assert.deepEqual(value, [0, undefined, undefined, 1]); 79 | }).then(done, failIfThrows(done)); 80 | }); 81 | 82 | it('does not modify the input array', function (done) { 83 | var input = [0, 1]; 84 | var iterable = input; 85 | 86 | Promise.all(iterable).then(function (value) { 87 | assert.notStrictEqual(input, value); 88 | }).then(done, failIfThrows(done)); 89 | }); 90 | 91 | it('should reject with a TypeError if given a non-iterable', function (done) { 92 | var notIterable = {}; 93 | 94 | Promise.all(notIterable).then( 95 | function () { 96 | assert(false, 'should never get here'); 97 | }, 98 | function (reason) { 99 | assert(reason instanceof TypeError); 100 | } 101 | ).then(done, failIfThrows(done)); 102 | }); 103 | 104 | // test cases from 105 | // https://github.com/domenic/promises-unwrapping/issues/89#issuecomment-33110203 106 | var tamper = function (p) { 107 | // eslint-disable-next-line no-param-reassign 108 | p.then = function (fulfill, reject) { 109 | fulfill('tampered'); 110 | return Promise.prototype.then.call(this, fulfill, reject); 111 | }; 112 | return p; 113 | }; 114 | 115 | it('should be robust against tampering (1)', function (done) { 116 | var g = [tamper(Promise.resolve(0))]; 117 | // Prevent countdownHolder.[[Countdown]] from ever reaching zero 118 | Promise.all(g).then( 119 | function () { done(); }, 120 | failIfThrows(done) 121 | ); 122 | }); 123 | 124 | it('should be robust against tampering (2)', function (done) { 125 | // Promise from Promise.all resolved before arguments 126 | var fulfillCalled = false; 127 | 128 | var g = [ 129 | Promise.resolve(0), 130 | tamper(Promise.resolve(1)), 131 | Promise.resolve(2).then(function () { 132 | assert(!fulfillCalled, 'should be resolved before all()'); 133 | }).then(function () { 134 | assert(!fulfillCalled, 'should be resolved before all()'); 135 | })['catch'](failIfThrows(done)) 136 | ]; 137 | Promise.all(g).then(function () { 138 | assert(!fulfillCalled, 'should be resolved last'); 139 | fulfillCalled = true; 140 | }).then(done, failIfThrows(done)); 141 | }); 142 | 143 | it('should be robust against tampering (3)', function (done) { 144 | var g = [ 145 | Promise.resolve(0), 146 | tamper(Promise.resolve(1)), 147 | Promise.reject(2) 148 | ]; 149 | // Promise from Promise.all resolved despite rejected promise in arguments 150 | Promise.all(g).then(function () { 151 | throw new Error('should not reach here!'); 152 | }, function (e) { 153 | assert.strictEqual(e, 2); 154 | }).then(done, failIfThrows(done)); 155 | }); 156 | 157 | it('should be robust against tampering (4)', function (done) { 158 | var hijack = true; 159 | var actualArguments = []; 160 | var P = function (resolver) { 161 | var self; 162 | if (hijack) { 163 | hijack = false; 164 | self = new Promise(function (resolve, reject) { 165 | resolver(function (values) { 166 | // record arguments & # of times resolve function is called 167 | actualArguments.push(values.slice()); 168 | return resolve(values); 169 | }, reject); 170 | }); 171 | } else { 172 | self = new Promise(resolver); 173 | } 174 | Object.setPrototypeOf(self, P.prototype); 175 | return self; 176 | }; 177 | if (!Object.setPrototypeOf) { return done(); } // skip test if on IE < 11 178 | Object.setPrototypeOf(P, Promise); 179 | P.prototype = Object.create(Promise.prototype, { 180 | constructor: { value: P } 181 | }); 182 | P.resolve = function (p) { return p; }; 183 | 184 | var g = [ 185 | Promise.resolve(0), 186 | tamper(Promise.resolve(1)), 187 | Promise.resolve(2) 188 | ]; 189 | 190 | // Promise.all calls resolver twice 191 | P.all(g)['catch'](failIfThrows(done)); 192 | Promise.resolve().then(function () { 193 | assert.deepEqual(actualArguments, [[0, 'tampered', 2]]); 194 | }).then(done, failIfThrows(done)); 195 | }); 196 | }); 197 | -------------------------------------------------------------------------------- /test/promise/evil-promises.js: -------------------------------------------------------------------------------- 1 | describe('Evil promises should not be able to break invariants', function () { 2 | 'use strict'; 3 | 4 | specify('resolving to a promise that calls onFulfilled twice', function (done) { 5 | // note that we have to create a trivial subclass, as otherwise the 6 | // Promise.resolve(evilPromise) is just the identity function. 7 | // (And in fact, most native Promise implementations use a private 8 | // [[PromiseConstructor]] field in `Promise.resolve` which can't be 9 | // easily patched in an ES5 engine, so instead of 10 | // `Promise.resolve(evilPromise)` we'll use 11 | // `new Promise(function(r){r(evilPromise);})` below.) 12 | var EvilPromise = function (executor) { 13 | var self = new Promise(executor); 14 | Object.setPrototypeOf(self, EvilPromise.prototype); 15 | return self; 16 | }; 17 | if (!Object.setPrototypeOf) { return done(); } // skip test if on IE < 11 18 | Object.setPrototypeOf(EvilPromise, Promise); 19 | EvilPromise.prototype = Object.create(Promise.prototype, { 20 | constructor: { value: EvilPromise } 21 | }); 22 | 23 | var evilPromise = EvilPromise.resolve(); 24 | evilPromise.then = function (f) { 25 | f(1); 26 | f(2); 27 | }; 28 | 29 | var calledAlready = false; 30 | new Promise(function (r) { r(evilPromise); }).then(function (value) { 31 | assert.strictEqual(calledAlready, false); 32 | calledAlready = true; 33 | assert.strictEqual(value, 1); 34 | }).then(done, done); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /test/promise/promises-aplus.js: -------------------------------------------------------------------------------- 1 | // tests from promises-aplus-tests 2 | 3 | describe('Promises/A+ Tests', function () { 4 | 'use strict'; 5 | 6 | if (typeof Promise === 'undefined') { 7 | return; 8 | } 9 | 10 | require('promises-aplus-tests').mocha({ 11 | // an adapter from es6 spec to Promises/A+ 12 | deferred: function () { 13 | var result = {}; 14 | result.promise = new Promise(function (resolve, reject) { 15 | result.resolve = resolve; 16 | result.reject = reject; 17 | }); 18 | return result; 19 | }, 20 | resolved: Promise.resolve.bind(Promise), 21 | rejected: Promise.reject.bind(Promise) 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/promise/promises-es6.js: -------------------------------------------------------------------------------- 1 | // tests from promises-es6-tests 2 | (function () { 3 | 'use strict'; 4 | 5 | if (typeof Promise === 'undefined') { 6 | return; 7 | } 8 | 9 | describe('Promises/ES6 Tests', function () { 10 | 11 | // an adapter that sets up global.Promise 12 | // since it's already set up, empty functions will suffice 13 | var adapter = { 14 | defineGlobalPromise: function () { 15 | }, 16 | removeGlobalPromise: function () { 17 | } 18 | }; 19 | 20 | require('promises-es6-tests').mocha(adapter); 21 | }); 22 | }()); 23 | -------------------------------------------------------------------------------- /test/promise/race.js: -------------------------------------------------------------------------------- 1 | var failIfThrows = function (done) { 2 | 'use strict'; 3 | 4 | return function (e) { 5 | done(e || new Error()); 6 | }; 7 | }; 8 | 9 | var delayPromise = function (value, ms) { 10 | 'use strict'; 11 | 12 | return new Promise(function (resolve) { 13 | setTimeout(function () { 14 | resolve(value); 15 | }, ms); 16 | }); 17 | }; 18 | 19 | describe('Promise.race', function () { 20 | 'use strict'; 21 | 22 | it('should not be enumerable', function () { 23 | expect(Promise).ownPropertyDescriptor('race').to.have.property('enumerable', false); 24 | }); 25 | 26 | it('should fulfill if all promises are settled and the ordinally-first is fulfilled', function (done) { 27 | var iterable = [Promise.resolve(1), Promise.reject(2), Promise.resolve(3)]; 28 | 29 | Promise.race(iterable).then(function (value) { 30 | assert.strictEqual(value, 1); 31 | }).then(done, failIfThrows(done)); 32 | }); 33 | 34 | it('should reject if all promises are settled and the ordinally-first is rejected', function (done) { 35 | var iterable = [Promise.reject(1), Promise.reject(2), Promise.resolve(3)]; 36 | 37 | Promise.race(iterable).then( 38 | function () { 39 | assert(false, 'should never get here'); 40 | }, 41 | function (reason) { 42 | assert.strictEqual(reason, 1); 43 | } 44 | ).then(done, failIfThrows(done)); 45 | }); 46 | 47 | it('should settle in the same way as the first promise to settle', function (done) { 48 | // ensure that even if timeouts are delayed an all execute together, 49 | // p2 will settle first. 50 | var p2 = delayPromise(2, 200); 51 | var p1 = delayPromise(1, 1000); 52 | var p3 = delayPromise(3, 500); 53 | var iterable = [p1, p2, p3]; 54 | 55 | Promise.race(iterable).then(function (value) { 56 | assert.strictEqual(value, 2); 57 | }).then(done, failIfThrows(done)); 58 | }); 59 | 60 | // see https://github.com/domenic/promises-unwrapping/issues/75 61 | it('should never settle when given an empty iterable', function (done) { 62 | var iterable = []; 63 | var settled = false; 64 | 65 | Promise.race(iterable).then( 66 | function () { settled = true; }, 67 | function () { settled = true; } 68 | ); 69 | 70 | setTimeout(function () { 71 | assert.strictEqual(settled, false); 72 | done(); 73 | }, 300); 74 | }); 75 | 76 | it('should reject with a TypeError if given a non-iterable', function (done) { 77 | var notIterable = {}; 78 | 79 | Promise.race(notIterable).then( 80 | function () { 81 | assert(false, 'should never get here'); 82 | }, 83 | function (reason) { 84 | assert(reason instanceof TypeError); 85 | } 86 | ).then(done, failIfThrows(done)); 87 | }); 88 | }); 89 | -------------------------------------------------------------------------------- /test/promise/reject.js: -------------------------------------------------------------------------------- 1 | var failIfThrows = function (done) { 2 | 'use strict'; 3 | 4 | return function (e) { 5 | done(e || new Error()); 6 | }; 7 | }; 8 | 9 | describe('Promise.reject', function () { 10 | 'use strict'; 11 | 12 | it('should not be enumerable', function () { 13 | expect(Promise).ownPropertyDescriptor('reject').to.have.property('enumerable', false); 14 | }); 15 | 16 | it('should return a rejected promise', function (done) { 17 | var value = {}; 18 | Promise.reject(value).then(failIfThrows(done), function (result) { 19 | expect(result).to.equal(value); 20 | done(); 21 | }); 22 | }); 23 | 24 | it('throws when receiver is a primitive', function () { 25 | var promise = Promise.reject(); 26 | expect(function () { Promise.reject.call(undefined, promise); }).to['throw'](); 27 | expect(function () { Promise.reject.call(null, promise); }).to['throw'](); 28 | expect(function () { Promise.reject.call('', promise); }).to['throw'](); 29 | expect(function () { Promise.reject.call(42, promise); }).to['throw'](); 30 | expect(function () { Promise.reject.call(false, promise); }).to['throw'](); 31 | expect(function () { Promise.reject.call(true, promise); }).to['throw'](); 32 | promise.then(null, function () {}); // silence unhandled rejection errors in Chrome 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/promise/resolve.js: -------------------------------------------------------------------------------- 1 | var failIfThrows = function (done) { 2 | 'use strict'; 3 | 4 | return function (e) { 5 | done(e || new Error()); 6 | }; 7 | }; 8 | 9 | describe('Promise.resolve', function () { 10 | 'use strict'; 11 | 12 | it('should not be enumerable', function () { 13 | expect(Promise).ownPropertyDescriptor('resolve').to.have.property('enumerable', false); 14 | }); 15 | 16 | it('should return a resolved promise', function (done) { 17 | var value = {}; 18 | Promise.resolve(value).then(function (result) { 19 | expect(result).to.equal(value); 20 | done(); 21 | }, failIfThrows(done)); 22 | }); 23 | 24 | it('throws when receiver is a primitive', function () { 25 | var promise = Promise.resolve(); 26 | expect(function () { Promise.resolve.call(undefined, promise); }).to['throw'](); 27 | expect(function () { Promise.resolve.call(null, promise); }).to['throw'](); 28 | expect(function () { Promise.resolve.call('', promise); }).to['throw'](); 29 | expect(function () { Promise.resolve.call(42, promise); }).to['throw'](); 30 | expect(function () { Promise.resolve.call(false, promise); }).to['throw'](); 31 | expect(function () { Promise.resolve.call(true, promise); }).to['throw'](); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /test/promise/simple.js: -------------------------------------------------------------------------------- 1 | var failIfThrows = function (done) { 2 | 'use strict'; 3 | 4 | return function (e) { 5 | done(e || new Error()); 6 | }; 7 | }; 8 | 9 | describe('Promise', function () { 10 | 'use strict'; 11 | 12 | specify('sanity check: a fulfilled promise calls its fulfillment handler', function (done) { 13 | Promise.resolve(5).then(function (value) { 14 | assert.strictEqual(value, 5); 15 | }).then(done, failIfThrows(done)); 16 | }); 17 | 18 | specify('directly resolving the promise with itself', function (done) { 19 | var resolvePromise; 20 | var promise = new Promise(function (resolve) { resolvePromise = resolve; }); 21 | 22 | resolvePromise(promise); 23 | 24 | promise.then( 25 | function () { 26 | assert(false, 'Should not be fulfilled'); 27 | }, 28 | function (err) { 29 | assert(err instanceof TypeError); 30 | } 31 | ).then(done, failIfThrows(done)); 32 | }); 33 | 34 | specify('Stealing a resolver and using it to trigger possible reentrancy bug (#83)', function () { 35 | var stolenResolver; 36 | var StealingPromiseConstructor = function StealingPromiseConstructor(resolver) { 37 | stolenResolver = resolver; 38 | resolver(function () { }, function () { }); 39 | }; 40 | 41 | var iterable = {}; 42 | var atAtIterator = '@@iterator'; // on firefox, at least. 43 | iterable[atAtIterator] = function () { 44 | stolenResolver(null, null); 45 | throw new Error(0); 46 | }; 47 | 48 | assert.doesNotThrow(function () { 49 | Promise.all.call(StealingPromiseConstructor, iterable); 50 | }); 51 | }); 52 | 53 | specify('resolve with a thenable calls it once', function () { 54 | var resolve; 55 | var p = new Promise(function (r) { resolve = r; }); 56 | var count = 0; 57 | resolve({ 58 | then: function () { 59 | count += 1; 60 | throw new RangeError('reject the promise'); 61 | } 62 | }); 63 | var a = p.then(function () {})['catch'](function (err) { 64 | assert.equal(count, 1); 65 | assert.ok(err instanceof RangeError); 66 | }); 67 | var b = p.then(function () {})['catch'](function (err) { 68 | assert.equal(count, 1); 69 | assert.ok(err instanceof RangeError); 70 | }); 71 | return Promise.all([a, b]); 72 | }); 73 | 74 | specify('resolve with a thenable that throws on .then, rejects the promise synchronously', function () { 75 | var resolve; 76 | var p = new Promise(function (r) { resolve = r; }); 77 | var count = 0; 78 | var thenable = Object.defineProperty({}, 'then', { 79 | get: function () { 80 | count += 1; 81 | throw new RangeError('no then for you'); 82 | } 83 | }); 84 | resolve(thenable); 85 | assert.equal(count, 1); 86 | var a = p.then(function () {})['catch'](function (err) { 87 | assert.equal(count, 1); 88 | assert.ok(err instanceof RangeError); 89 | }); 90 | var b = p.then(function () {})['catch'](function (err) { 91 | assert.equal(count, 1); 92 | assert.ok(err instanceof RangeError); 93 | }); 94 | return Promise.all([a, b]); 95 | }); 96 | }); 97 | -------------------------------------------------------------------------------- /test/promise/subclass.js: -------------------------------------------------------------------------------- 1 | describe('Support user subclassing of Promise', function () { 2 | 'use strict'; 3 | 4 | it('should work if you do it right', function (done) { 5 | // This is the "correct" es6-compatible way. 6 | // (Thanks, @domenic and @zloirock!) 7 | var MyPromise = function (executor) { 8 | var self = new Promise(executor); 9 | Object.setPrototypeOf(self, MyPromise.prototype); 10 | self.mine = 'yeah'; 11 | return self; 12 | }; 13 | if (!Object.setPrototypeOf) { return done(); } // skip test if on IE < 11 14 | Object.setPrototypeOf(MyPromise, Promise); 15 | MyPromise.prototype = Object.create(Promise.prototype, { 16 | constructor: { value: MyPromise } 17 | }); 18 | 19 | // let's try it! 20 | var p1 = MyPromise.resolve(5); 21 | assert.strictEqual(p1.mine, 'yeah'); 22 | p1 = p1.then(function (x) { 23 | assert.strictEqual(x, 5); 24 | }); 25 | assert.strictEqual(p1.mine, 'yeah'); 26 | 27 | var p2 = new MyPromise(function (r) { r(6); }); 28 | assert.strictEqual(p2.mine, 'yeah'); 29 | p2 = p2.then(function (x) { 30 | assert.strictEqual(x, 6); 31 | }); 32 | assert.strictEqual(p2.mine, 'yeah'); 33 | 34 | var p3 = MyPromise.all([p1, p2]); 35 | assert.strictEqual(p3.mine, 'yeah'); 36 | p3.then(function () { done(); }, done); 37 | }); 38 | 39 | it("should throw if you don't inherit at all", function () { 40 | var MyPromise = function () {}; 41 | assert['throws'](function () { 42 | Promise.all.call(MyPromise, []); 43 | }, TypeError); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/reflect.js: -------------------------------------------------------------------------------- 1 | var arePropertyDescriptorsSupported = function () { 2 | try { 3 | Object.defineProperty({}, 'x', {}); 4 | return true; 5 | } catch (e) { /* this is IE 8. */ 6 | return false; 7 | } 8 | }; 9 | var supportsDescriptors = !!Object.defineProperty && arePropertyDescriptorsSupported(); 10 | var functionsHaveNames = function f() {}.name === 'f'; 11 | 12 | var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol'; 13 | var ifSymbolsIt = hasSymbols ? it : xit; 14 | var describeIfGetProto = Object.getPrototypeOf ? describe : xdescribe; 15 | var describeIfSetProto = Object.setPrototypeOf ? describe : xdescribe; 16 | var describeIfES5 = supportsDescriptors ? describe : xdescribe; 17 | var describeIfExtensionsPreventible = Object.preventExtensions ? describe : xdescribe; 18 | var describeIfGetOwnPropertyNames = Object.getOwnPropertyNames ? describe : xdescribe; 19 | var ifExtensionsPreventibleIt = Object.preventExtensions ? it : xit; 20 | var ifES5It = supportsDescriptors ? it : xit; 21 | var ifFreezeIt = typeof Object.freeze === 'function' ? it : xit; 22 | var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit; 23 | var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it; 24 | 25 | describe('Reflect', function () { 26 | if (typeof Reflect === 'undefined') { 27 | return it('exists', function () { 28 | expect(this).to.have.property('Reflect'); 29 | }); 30 | } 31 | 32 | var object = { 33 | something: 1, 34 | _value: 0 35 | }; 36 | 37 | if (supportsDescriptors) { 38 | /* eslint-disable accessor-pairs */ 39 | Object.defineProperties(object, { 40 | value: { 41 | get: function () { 42 | return this._value; 43 | } 44 | }, 45 | 46 | setter: { 47 | set: function (val) { 48 | this._value = val; 49 | } 50 | }, 51 | 52 | bool: { 53 | value: true 54 | } 55 | }); 56 | /* eslint-enable accessor-pairs */ 57 | } 58 | 59 | var testXThrow = function (values, func) { 60 | var checker = function checker(item) { 61 | try { 62 | func(item); 63 | return false; 64 | } catch (e) { 65 | return e instanceof TypeError; 66 | } 67 | }; 68 | 69 | values.forEach(function (item) { 70 | expect(item).to.satisfy(checker); 71 | }); 72 | }; 73 | 74 | var testCallableThrow = testXThrow.bind(null, [null, undefined, 1, 'string', true, [], {}]); 75 | 76 | var testPrimitiveThrow = testXThrow.bind(null, [null, undefined, 1, 'string', true]); 77 | 78 | ifShimIt('is on the exported object', function () { 79 | var exported = require('../'); 80 | expect(exported.Reflect).to.equal(Reflect); 81 | }); 82 | 83 | describe('.apply()', function () { 84 | if (typeof Reflect.apply === 'undefined') { 85 | return it('exists', function () { 86 | expect(Reflect).to.have.property('apply'); 87 | }); 88 | } 89 | 90 | it('is a function', function () { 91 | expect(typeof Reflect.apply).to.equal('function'); 92 | }); 93 | 94 | ifFunctionsHaveNamesIt('has the right name', function () { 95 | expect(Reflect.apply.name).to.equal('apply'); 96 | }); 97 | 98 | it('throws if target isn’t callable', function () { 99 | testCallableThrow(function (item) { 100 | return Reflect.apply(item, null, []); 101 | }); 102 | }); 103 | 104 | it('works also with redefined apply', function () { 105 | expect(Reflect.apply(Array.prototype.push, [1, 2], [3, 4, 5])).to.equal(5); 106 | 107 | var F = function F(a, b, c) { 108 | return a + b + c; 109 | }; 110 | 111 | F.apply = false; 112 | 113 | expect(Reflect.apply(F, null, [1, 2, 3])).to.equal(6); 114 | 115 | var G = function G(last) { 116 | return this.x + 'lo' + last; 117 | }; 118 | 119 | G.apply = function nop() {}; 120 | 121 | expect(Reflect.apply(G, { x: 'yel' }, ['!'])).to.equal('yello!'); 122 | }); 123 | }); 124 | 125 | describe('.construct()', function () { 126 | if (typeof Reflect.construct === 'undefined') { 127 | return it('exists', function () { 128 | expect(Reflect).to.have.property('construct'); 129 | }); 130 | } 131 | 132 | it('is a function', function () { 133 | expect(typeof Reflect.construct).to.equal('function'); 134 | }); 135 | 136 | ifFunctionsHaveNamesIt('has the right name', function () { 137 | expect(Reflect.construct.name).to.equal('construct'); 138 | }); 139 | 140 | it('throws if target isn’t callable', function () { 141 | testCallableThrow(function (item) { 142 | return Reflect.apply(item, null, []); 143 | }); 144 | }); 145 | 146 | it('works also with redefined apply', function () { 147 | var C = function C(a, b, c) { 148 | this.qux = [a, b, c].join('|'); 149 | }; 150 | 151 | C.apply = undefined; 152 | 153 | expect(Reflect.construct(C, ['foo', 'bar', 'baz']).qux).to.equal('foo|bar|baz'); 154 | }); 155 | 156 | it('correctly handles newTarget param', function () { 157 | var F = function F() {}; 158 | expect(Reflect.construct(function () {}, [], F) instanceof F).to.equal(true); 159 | }); 160 | }); 161 | 162 | describeIfES5('.defineProperty()', function () { 163 | if (typeof Reflect.defineProperty === 'undefined') { 164 | return it('exists', function () { 165 | expect(Reflect).to.have.property('defineProperty'); 166 | }); 167 | } 168 | 169 | it('is a function', function () { 170 | expect(typeof Reflect.defineProperty).to.equal('function'); 171 | }); 172 | 173 | ifFunctionsHaveNamesIt('has the right name', function () { 174 | expect(Reflect.defineProperty.name).to.equal('defineProperty'); 175 | }); 176 | 177 | it('throws if the target isn’t an object', function () { 178 | testPrimitiveThrow(function (item) { 179 | return Reflect.defineProperty(item, 'prop', { value: true }); 180 | }); 181 | }); 182 | 183 | ifExtensionsPreventibleIt('returns false for non-extensible objects', function () { 184 | var o = Object.preventExtensions({}); 185 | 186 | expect(Reflect.defineProperty(o, 'prop', {})).to.equal(false); 187 | }); 188 | 189 | it('can return true, even for non-configurable, non-writable properties', function () { 190 | var o = {}; 191 | var desc = { 192 | value: 13, 193 | enumerable: false, 194 | writable: false, 195 | configurable: false 196 | }; 197 | 198 | expect(Reflect.defineProperty(o, 'prop', desc)).to.equal(true); 199 | 200 | // Defined as non-configurable, but descriptor is identical. 201 | expect(Reflect.defineProperty(o, 'prop', desc)).to.equal(true); 202 | 203 | desc.value = 37; // Change 204 | 205 | expect(Reflect.defineProperty(o, 'prop', desc)).to.equal(false); 206 | }); 207 | 208 | it('can change from one property type to another, if configurable', function () { 209 | var o = {}; 210 | 211 | var desc1 = { 212 | set: function () {}, 213 | configurable: true 214 | }; 215 | 216 | var desc2 = { 217 | value: 13, 218 | configurable: false 219 | }; 220 | 221 | var desc3 = { 222 | get: function () {} 223 | }; 224 | 225 | expect(Reflect.defineProperty(o, 'prop', desc1)).to.equal(true); 226 | 227 | expect(Reflect.defineProperty(o, 'prop', desc2)).to.equal(true); 228 | 229 | expect(Reflect.defineProperty(o, 'prop', desc3)).to.equal(false); 230 | }); 231 | }); 232 | 233 | describe('.deleteProperty()', function () { 234 | if (typeof Reflect.deleteProperty === 'undefined') { 235 | return it('exists', function () { 236 | expect(Reflect).to.have.property('deleteProperty'); 237 | }); 238 | } 239 | 240 | it('is a function', function () { 241 | expect(typeof Reflect.deleteProperty).to.equal('function'); 242 | }); 243 | 244 | ifFunctionsHaveNamesIt('has the right name', function () { 245 | expect(Reflect.deleteProperty.name).to.equal('deleteProperty'); 246 | }); 247 | 248 | it('throws if the target isn’t an object', function () { 249 | testPrimitiveThrow(function (item) { 250 | return Reflect.deleteProperty(item, 'prop'); 251 | }); 252 | }); 253 | 254 | ifES5It('returns true for success and false for failure', function () { 255 | var o = { a: 1 }; 256 | 257 | Object.defineProperty(o, 'b', { value: 2 }); 258 | 259 | expect(o).to.have.property('a'); 260 | expect(o).to.have.property('b'); 261 | expect(o.a).to.equal(1); 262 | expect(o.b).to.equal(2); 263 | 264 | expect(Reflect.deleteProperty(o, 'a')).to.equal(true); 265 | 266 | expect(o).not.to.have.property('a'); 267 | expect(o.b).to.equal(2); 268 | 269 | expect(Reflect.deleteProperty(o, 'b')).to.equal(false); 270 | 271 | expect(o).to.have.property('b'); 272 | expect(o.b).to.equal(2); 273 | 274 | expect(Reflect.deleteProperty(o, 'a')).to.equal(true); 275 | }); 276 | 277 | it('cannot delete an array’s length property', function () { 278 | expect(Reflect.deleteProperty([], 'length')).to.equal(false); 279 | }); 280 | }); 281 | 282 | describeIfES5('.get()', function () { 283 | if (typeof Reflect.get === 'undefined') { 284 | return it('exists', function () { 285 | expect(Reflect).to.have.property('get'); 286 | }); 287 | } 288 | 289 | it('is a function', function () { 290 | expect(typeof Reflect.get).to.equal('function'); 291 | }); 292 | 293 | ifFunctionsHaveNamesIt('has the right name', function () { 294 | expect(Reflect.get.name).to.equal('get'); 295 | }); 296 | 297 | it('throws on null and undefined', function () { 298 | [null, undefined].forEach(function (item) { 299 | expect(function () { 300 | return Reflect.get(item, 'property'); 301 | }).to['throw'](TypeError); 302 | }); 303 | }); 304 | 305 | it('can retrieve a simple value, from the target', function () { 306 | var p = { something: 2, bool: false }; 307 | 308 | expect(Reflect.get(object, 'something')).to.equal(1); 309 | // p has no effect 310 | expect(Reflect.get(object, 'something', p)).to.equal(1); 311 | 312 | // Value-defined properties take the target's value, 313 | // and ignore that of the receiver. 314 | expect(Reflect.get(object, 'bool', p)).to.equal(true); 315 | 316 | // Undefined values 317 | expect(Reflect.get(object, 'undefined_property')).to.equal(undefined); 318 | }); 319 | 320 | it('will invoke getters on the receiver rather than target', function () { 321 | var other = { _value: 1337 }; 322 | 323 | expect(Reflect.get(object, 'value', other)).to.equal(1337); 324 | 325 | // No getter for setter property 326 | expect(Reflect.get(object, 'setter', other)).to.equal(undefined); 327 | }); 328 | 329 | it('will search the prototype chain', function () { 330 | var other = Object.create(object); 331 | other._value = 17; 332 | 333 | var yetAnother = { _value: 4711 }; 334 | 335 | expect(Reflect.get(other, 'value', yetAnother)).to.equal(4711); 336 | 337 | expect(Reflect.get(other, 'bool', yetAnother)).to.equal(true); 338 | }); 339 | }); 340 | 341 | describeIfES5('.set()', function () { 342 | if (typeof Reflect.set === 'undefined') { 343 | return it('exists', function () { 344 | expect(Reflect).to.have.property('set'); 345 | }); 346 | } 347 | 348 | it('is a function', function () { 349 | expect(typeof Reflect.set).to.equal('function'); 350 | }); 351 | 352 | ifFunctionsHaveNamesIt('has the right name', function () { 353 | expect(Reflect.set.name).to.equal('set'); 354 | }); 355 | 356 | it('throws if the target isn’t an object', function () { 357 | testPrimitiveThrow(function (item) { 358 | return Reflect.set(item, 'prop', 'value'); 359 | }); 360 | }); 361 | 362 | it('sets values on receiver', function () { 363 | var target = {}; 364 | var receiver = {}; 365 | 366 | expect(Reflect.set(target, 'foo', 1, receiver)).to.equal(true); 367 | 368 | expect('foo' in target).to.equal(false); 369 | expect(receiver.foo).to.equal(1); 370 | 371 | expect(Reflect.defineProperty(receiver, 'bar', { 372 | value: 0, 373 | writable: true, 374 | enumerable: false, 375 | configurable: true 376 | })).to.equal(true); 377 | 378 | expect(Reflect.set(target, 'bar', 1, receiver)).to.equal(true); 379 | expect(receiver.bar).to.equal(1); 380 | expect(Reflect.getOwnPropertyDescriptor(receiver, 'bar').enumerable).to.equal(false); 381 | 382 | var out; 383 | /* eslint-disable accessor-pairs */ 384 | target = Object.create({}, { 385 | o: { 386 | set: function () { out = this; } 387 | } 388 | }); 389 | /* eslint-enable accessor-pairs */ 390 | 391 | expect(Reflect.set(target, 'o', 17, receiver)).to.equal(true); 392 | expect(out).to.equal(receiver); 393 | }); 394 | }); 395 | 396 | describeIfES5('.getOwnPropertyDescriptor()', function () { 397 | if (typeof Reflect.getOwnPropertyDescriptor === 'undefined') { 398 | return it('exists', function () { 399 | expect(Reflect).to.have.property('getOwnPropertyDescriptor'); 400 | }); 401 | } 402 | 403 | it('is a function', function () { 404 | expect(typeof Reflect.getOwnPropertyDescriptor).to.equal('function'); 405 | }); 406 | 407 | ifFunctionsHaveNamesIt('has the right name', function () { 408 | expect(Reflect.getOwnPropertyDescriptor.name).to.equal('getOwnPropertyDescriptor'); 409 | }); 410 | 411 | it('throws if the target isn’t an object', function () { 412 | testPrimitiveThrow(function (item) { 413 | return Reflect.getOwnPropertyDescriptor(item, 'prop'); 414 | }); 415 | }); 416 | 417 | it('retrieves property descriptors', function () { 418 | var obj = { a: 4711 }; 419 | 420 | var desc = Reflect.getOwnPropertyDescriptor(obj, 'a'); 421 | 422 | expect(desc).to.deep.equal({ 423 | value: 4711, 424 | configurable: true, 425 | writable: true, 426 | enumerable: true 427 | }); 428 | }); 429 | }); 430 | 431 | describeIfGetProto('.getPrototypeOf()', function () { 432 | if (typeof Reflect.getPrototypeOf === 'undefined') { 433 | return it('exists', function () { 434 | expect(Reflect).to.have.property('getPrototypeOf'); 435 | }); 436 | } 437 | 438 | it('is a function', function () { 439 | expect(typeof Reflect.getPrototypeOf).to.equal('function'); 440 | }); 441 | 442 | ifFunctionsHaveNamesIt('has the right name', function () { 443 | expect(Reflect.getPrototypeOf.name).to.equal('getPrototypeOf'); 444 | }); 445 | 446 | it('throws if the target isn’t an object', function () { 447 | testPrimitiveThrow(function (item) { 448 | return Reflect.getPrototypeOf(item); 449 | }); 450 | }); 451 | 452 | it('retrieves prototypes', function () { 453 | expect(Reflect.getPrototypeOf(Object.create(null))).to.equal(null); 454 | 455 | expect(Reflect.getPrototypeOf([])).to.equal(Array.prototype); 456 | }); 457 | }); 458 | 459 | describe('.has()', function () { 460 | if (typeof Reflect.has === 'undefined') { 461 | return it('exists', function () { 462 | expect(Reflect).to.have.property('has'); 463 | }); 464 | } 465 | 466 | it('is a function', function () { 467 | expect(typeof Reflect.has).to.equal('function'); 468 | }); 469 | 470 | ifFunctionsHaveNamesIt('has the right name', function () { 471 | expect(Reflect.has.name).to.equal('has'); 472 | }); 473 | 474 | it('throws if the target isn’t an object', function () { 475 | testPrimitiveThrow(function (item) { 476 | return Reflect.has(item, 'prop'); 477 | }); 478 | }); 479 | 480 | it('will detect own properties', function () { 481 | var target = Object.create ? Object.create(null) : {}; 482 | 483 | expect(Reflect.has(target, 'prop')).to.equal(false); 484 | 485 | target.prop = undefined; 486 | expect(Reflect.has(target, 'prop')).to.equal(true); 487 | 488 | delete target.prop; 489 | expect(Reflect.has(target, 'prop')).to.equal(false); 490 | 491 | expect(Reflect.has(Reflect.has, 'length')).to.equal(true); 492 | }); 493 | 494 | ifES5It('will detect an own accessor property', function () { 495 | var target = Object.create(null); 496 | /* eslint-disable accessor-pairs */ 497 | Object.defineProperty(target, 'accessor', { 498 | set: function () {} 499 | }); 500 | /* eslint-enable accessor-pairs */ 501 | 502 | expect(Reflect.has(target, 'accessor')).to.equal(true); 503 | }); 504 | 505 | it('will search the prototype chain', function () { 506 | var Parent = function () {}; 507 | Parent.prototype.someProperty = undefined; 508 | 509 | var Child = function () {}; 510 | Child.prototype = new Parent(); 511 | 512 | var target = new Child(); 513 | target.bool = true; 514 | 515 | expect(Reflect.has(target, 'bool')).to.equal(true); 516 | expect(Reflect.has(target, 'someProperty')).to.equal(true); 517 | expect(Reflect.has(target, 'undefinedProperty')).to.equal(false); 518 | }); 519 | }); 520 | 521 | describeIfExtensionsPreventible('.isExtensible()', function () { 522 | if (typeof Reflect.isExtensible === 'undefined') { 523 | return it('exists', function () { 524 | expect(Reflect).to.have.property('isExtensible'); 525 | }); 526 | } 527 | 528 | it('is a function', function () { 529 | expect(typeof Reflect.isExtensible).to.equal('function'); 530 | }); 531 | 532 | ifFunctionsHaveNamesIt('has the right name', function () { 533 | expect(Reflect.isExtensible.name).to.equal('isExtensible'); 534 | }); 535 | 536 | it('returns true for plain objects', function () { 537 | expect(Reflect.isExtensible({})).to.equal(true); 538 | expect(Reflect.isExtensible(Object.preventExtensions({}))).to.equal(false); 539 | }); 540 | 541 | it('throws if the target isn’t an object', function () { 542 | testPrimitiveThrow(function (item) { 543 | return Reflect.isExtensible(item); 544 | }); 545 | }); 546 | }); 547 | 548 | describeIfGetOwnPropertyNames('.ownKeys()', function () { 549 | if (typeof Reflect.ownKeys === 'undefined') { 550 | return it('exists', function () { 551 | expect(Reflect).to.have.property('ownKeys'); 552 | }); 553 | } 554 | 555 | it('is a function', function () { 556 | expect(typeof Reflect.ownKeys).to.equal('function'); 557 | }); 558 | 559 | ifFunctionsHaveNamesIt('has the right name', function () { 560 | expect(Reflect.ownKeys.name).to.equal('ownKeys'); 561 | }); 562 | 563 | it('throws if the target isn’t an object', function () { 564 | testPrimitiveThrow(function (item) { 565 | return Reflect.ownKeys(item); 566 | }); 567 | }); 568 | 569 | it('should return the same result as Object.getOwnPropertyNames if there are no Symbols', function () { 570 | var obj = { foo: 1, bar: 2 }; 571 | 572 | obj[1] = 'first'; 573 | 574 | var result = Object.getOwnPropertyNames(obj); 575 | 576 | // Reflect.ownKeys depends on the implementation of 577 | // Object.getOwnPropertyNames, at least for non-symbol keys. 578 | expect(Reflect.ownKeys(obj)).to.deep.equal(result); 579 | 580 | // We can only be sure of which keys should exist. 581 | expect(result.sort()).to.deep.equal(['1', 'bar', 'foo']); 582 | }); 583 | 584 | ifSymbolsIt('symbols come last', function () { 585 | var s = Symbol(); 586 | 587 | var o = { 588 | 'non-symbol': true 589 | }; 590 | 591 | o[s] = true; 592 | 593 | expect(Reflect.ownKeys(o)).to.deep.equal(['non-symbol', s]); 594 | }); 595 | }); 596 | 597 | describeIfExtensionsPreventible('.preventExtensions()', function () { 598 | if (typeof Reflect.preventExtensions === 'undefined') { 599 | return it('exists', function () { 600 | expect(Reflect).to.have.property('preventExtensions'); 601 | }); 602 | } 603 | 604 | it('is a function', function () { 605 | expect(typeof Reflect.preventExtensions).to.equal('function'); 606 | }); 607 | 608 | ifFunctionsHaveNamesIt('has the right name', function () { 609 | expect(Reflect.preventExtensions.name).to.equal('preventExtensions'); 610 | }); 611 | 612 | it('throws if the target isn’t an object', function () { 613 | testPrimitiveThrow(function (item) { 614 | return Reflect.preventExtensions(item); 615 | }); 616 | }); 617 | 618 | it('prevents extensions on objects', function () { 619 | var obj = {}; 620 | Reflect.preventExtensions(obj); 621 | expect(Object.isExtensible(obj)).to.equal(false); 622 | }); 623 | }); 624 | 625 | describeIfSetProto('.setPrototypeOf()', function () { 626 | if (typeof Reflect.setPrototypeOf === 'undefined') { 627 | return it('exists', function () { 628 | expect(Reflect).to.have.property('setPrototypeOf'); 629 | }); 630 | } 631 | 632 | it('is a function', function () { 633 | expect(typeof Reflect.setPrototypeOf).to.equal('function'); 634 | }); 635 | 636 | ifFunctionsHaveNamesIt('has the right name', function () { 637 | expect(Reflect.setPrototypeOf.name).to.equal('setPrototypeOf'); 638 | }); 639 | 640 | it('throws if the target isn’t an object', function () { 641 | testPrimitiveThrow(function (item) { 642 | return Reflect.setPrototypeOf(item, null); 643 | }); 644 | }); 645 | 646 | it('throws if the prototype is neither object nor null', function () { 647 | var o = {}; 648 | 649 | [undefined, 1, 'string', true].forEach(function (item) { 650 | expect(function () { 651 | return Reflect.setPrototypeOf(o, item); 652 | }).to['throw'](TypeError); 653 | }); 654 | }); 655 | 656 | it('can set prototypes, and returns true on success', function () { 657 | var obj = {}; 658 | 659 | expect(Reflect.setPrototypeOf(obj, Array.prototype)).to.equal(true); 660 | expect(obj).to.be.an.instanceOf(Array); 661 | 662 | expect(obj.toString).not.to.equal(undefined); 663 | expect(Reflect.setPrototypeOf(obj, null)).to.equal(true); 664 | expect(obj.toString).to.equal(undefined); 665 | }); 666 | 667 | ifFreezeIt('is returns false on failure', function () { 668 | var obj = Object.freeze({}); 669 | 670 | expect(Reflect.setPrototypeOf(obj, null)).to.equal(false); 671 | }); 672 | 673 | it('fails when attempting to create a circular prototype chain', function () { 674 | var o = {}; 675 | 676 | expect(Reflect.setPrototypeOf(o, o)).to.equal(false); 677 | }); 678 | }); 679 | }); 680 | -------------------------------------------------------------------------------- /test/regexp.js: -------------------------------------------------------------------------------- 1 | var getRegexLiteral = function (stringRegex) { 2 | try { 3 | /* eslint-disable no-new-func */ 4 | return Function('return ' + stringRegex + ';')(); 5 | /* eslint-enable no-new-func */ 6 | } catch (e) { /**/ } 7 | }; 8 | var describeIfSupportsDescriptors = Object.getOwnPropertyDescriptor ? describe : describe.skip; 9 | var callAllowsPrimitives = (function () { return this === 3; }.call(3)); 10 | var ifCallAllowsPrimitivesIt = callAllowsPrimitives ? it : it.skip; 11 | var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it; 12 | var hasSymbols = typeof Symbol === 'function' && typeof Symbol['for'] === 'function' && typeof Symbol('') === 'symbol'; 13 | var ifSymbolsDescribe = hasSymbols ? describe : describe.skip; 14 | var defaultRegex = (function () { 15 | // Chrome Canary 51 has an undefined RegExp#toSource, and 16 | // RegExp#toString produces `/undefined/` 17 | try { 18 | return RegExp.prototype.source ? String(RegExp.prototype) : '/(?:)/'; 19 | } catch (e) { 20 | return '/(?:)/'; 21 | } 22 | }()); 23 | 24 | describe('RegExp', function () { 25 | ifShimIt('is on the exported object', function () { 26 | var exported = require('../'); 27 | expect(exported.RegExp).to.equal(RegExp); 28 | }); 29 | 30 | it('can be called with no arguments', function () { 31 | var regex = RegExp(); 32 | expect(String(regex)).to.equal(defaultRegex); 33 | expect(regex).to.be.an.instanceOf(RegExp); 34 | }); 35 | 36 | it('can be called with null/undefined', function () { 37 | expect(String(RegExp(null))).to.equal('/null/'); 38 | expect(String(RegExp(undefined))).to.equal(defaultRegex); 39 | }); 40 | 41 | describe('constructor', function () { 42 | it('allows a regex as the pattern', function () { 43 | var a = /a/g; 44 | var b = new RegExp(a); 45 | if (typeof a !== 'function') { 46 | // in browsers like Safari 5, new RegExp with a regex returns the same instance. 47 | expect(a).not.to.equal(b); 48 | } 49 | expect(a).to.eql(b); 50 | }); 51 | 52 | it('allows a string with flags', function () { 53 | expect(new RegExp('a', 'mgi')).to.eql(/a/gim); 54 | expect(String(new RegExp('a', 'mgi'))).to.equal('/a/gim'); 55 | }); 56 | 57 | it('allows a regex with flags', function () { 58 | var a = /a/g; 59 | var makeRegex = function () { return new RegExp(a, 'mi'); }; 60 | expect(makeRegex).not.to['throw'](TypeError); 61 | expect(makeRegex()).to.eql(/a/mi); 62 | expect(String(makeRegex())).to.equal('/a/im'); 63 | }); 64 | 65 | it('works with instanceof', function () { 66 | expect(/a/g).to.be.an.instanceOf(RegExp); 67 | expect(new RegExp('a', 'im')).to.be.an.instanceOf(RegExp); 68 | expect(new RegExp(/a/g, 'im')).to.be.an.instanceOf(RegExp); 69 | }); 70 | 71 | it('has the right constructor', function () { 72 | expect(/a/g).to.have.property('constructor', RegExp); 73 | expect(new RegExp('a', 'im')).to.have.property('constructor', RegExp); 74 | expect(new RegExp(/a/g, 'im')).to.have.property('constructor', RegExp); 75 | }); 76 | 77 | it('toStrings properly', function () { 78 | expect(Object.prototype.toString.call(/a/g)).to.equal('[object RegExp]'); 79 | expect(Object.prototype.toString.call(new RegExp('a', 'g'))).to.equal('[object RegExp]'); 80 | expect(Object.prototype.toString.call(new RegExp(/a/g, 'im'))).to.equal('[object RegExp]'); 81 | }); 82 | 83 | it('functions as a boxed primitive wrapper', function () { 84 | var regex = /a/g; 85 | expect(RegExp(regex)).to.equal(regex); 86 | }); 87 | 88 | ifSymbolsDescribe('Symbol.replace', function () { 89 | if (!hasSymbols || typeof Symbol.replace === 'undefined') { 90 | return; 91 | } 92 | 93 | it('is a function', function () { 94 | expect(RegExp.prototype).to.have.property(Symbol.replace); 95 | expect(typeof RegExp.prototype[Symbol.replace]).to.equal('function'); 96 | }); 97 | 98 | it('is the same as String#replace', function () { 99 | var regex = /a/g; 100 | var str = 'abc'; 101 | var symbolReplace = regex[Symbol.replace](str); 102 | var stringReplace = str.replace(regex); 103 | expect(Object.keys(symbolReplace)).to.eql(Object.keys(stringReplace)); 104 | expect(symbolReplace).to.eql(stringReplace); 105 | }); 106 | }); 107 | 108 | ifSymbolsDescribe('Symbol.search', function () { 109 | if (!hasSymbols || typeof Symbol.search === 'undefined') { 110 | return; 111 | } 112 | 113 | it('is a function', function () { 114 | expect(RegExp.prototype).to.have.property(Symbol.search); 115 | expect(typeof RegExp.prototype[Symbol.search]).to.equal('function'); 116 | }); 117 | 118 | it('is the same as String#search', function () { 119 | var regex = /a/g; 120 | var str = 'abc'; 121 | var symbolSearch = regex[Symbol.search](str); 122 | var stringSearch = str.search(regex); 123 | expect(Object.keys(symbolSearch)).to.eql(Object.keys(stringSearch)); 124 | expect(symbolSearch).to.eql(stringSearch); 125 | }); 126 | }); 127 | 128 | ifSymbolsDescribe('Symbol.split', function () { 129 | if (!hasSymbols || typeof Symbol.split === 'undefined') { 130 | return; 131 | } 132 | 133 | it('is a function', function () { 134 | expect(RegExp.prototype).to.have.property(Symbol.split); 135 | expect(typeof RegExp.prototype[Symbol.split]).to.equal('function'); 136 | }); 137 | 138 | it('is the same as String#split', function () { 139 | var regex = /a/g; 140 | var str = 'abcabc'; 141 | var symbolSplit = regex[Symbol.split](str, 1); 142 | var stringSplit = str.split(regex, 1); 143 | expect(Object.keys(symbolSplit)).to.eql(Object.keys(stringSplit)); 144 | expect(symbolSplit).to.eql(stringSplit); 145 | }); 146 | }); 147 | 148 | ifSymbolsDescribe('Symbol.match', function () { 149 | if (!hasSymbols || typeof Symbol.match === 'undefined') { 150 | return; 151 | } 152 | 153 | var regexFalsyMatch; 154 | var nonregexTruthyMatch; 155 | 156 | beforeEach(function () { 157 | regexFalsyMatch = /./; 158 | regexFalsyMatch[Symbol.match] = false; 159 | nonregexTruthyMatch = { constructor: RegExp }; 160 | nonregexTruthyMatch[Symbol.match] = true; 161 | }); 162 | 163 | it('is a function', function () { 164 | expect(RegExp.prototype).to.have.property(Symbol.match); 165 | expect(typeof RegExp.prototype[Symbol.match]).to.equal('function'); 166 | }); 167 | 168 | it('is the same as String#match', function () { 169 | var regex = /a/g; 170 | var str = 'abc'; 171 | var symbolMatch = regex[Symbol.match](str); 172 | var stringMatch = str.match(regex); 173 | expect(Object.keys(symbolMatch)).to.eql(Object.keys(stringMatch)); 174 | expect(symbolMatch).to.eql(stringMatch); 175 | }); 176 | 177 | it('function does not passthrough regexes with a falsy Symbol.match', function () { 178 | expect(RegExp(regexFalsyMatch)).not.to.equal(regexFalsyMatch); 179 | }); 180 | 181 | it('constructor does not passthrough regexes with a falsy Symbol.match', function () { 182 | expect(new RegExp(regexFalsyMatch)).not.to.equal(regexFalsyMatch); 183 | }); 184 | 185 | it('function passes through non-regexes with a truthy Symbol.match', function () { 186 | expect(RegExp(nonregexTruthyMatch)).to.equal(nonregexTruthyMatch); 187 | }); 188 | 189 | it('constructor does not pass through non-regexes with a truthy Symbol.match', function () { 190 | expect(new RegExp(nonregexTruthyMatch)).not.to.equal(nonregexTruthyMatch); 191 | }); 192 | }); 193 | }); 194 | 195 | describeIfSupportsDescriptors('#flags', function () { 196 | if (!Object.prototype.hasOwnProperty.call(RegExp.prototype, 'flags')) { 197 | return it('exists', function () { 198 | expect(RegExp.prototype).to.have.property('flags'); 199 | }); 200 | } 201 | 202 | var regexpFlagsDescriptor = Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags'); 203 | var testGenericRegExpFlags = function (object) { 204 | return regexpFlagsDescriptor.get.call(object); 205 | }; 206 | 207 | it('has the correct descriptor', function () { 208 | expect(regexpFlagsDescriptor.configurable).to.equal(true); 209 | expect(regexpFlagsDescriptor.enumerable).to.equal(false); 210 | expect(regexpFlagsDescriptor.get instanceof Function).to.equal(true); 211 | expect(regexpFlagsDescriptor.set).to.equal(undefined); 212 | }); 213 | 214 | ifCallAllowsPrimitivesIt('throws when not called on an object', function () { 215 | var nonObjects = ['', false, true, 42, NaN, null, undefined]; 216 | nonObjects.forEach(function (nonObject) { 217 | expect(function () { testGenericRegExpFlags(nonObject); }).to['throw'](TypeError); 218 | }); 219 | }); 220 | 221 | it('has the correct flags on a literal', function () { 222 | expect((/a/g).flags).to.equal('g'); 223 | expect((/a/i).flags).to.equal('i'); 224 | expect((/a/m).flags).to.equal('m'); 225 | if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'sticky')) { 226 | expect(getRegexLiteral('/a/y').flags).to.equal('y'); 227 | } 228 | if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'unicode')) { 229 | expect(getRegexLiteral('/a/u').flags).to.equal('u'); 230 | } 231 | }); 232 | 233 | it('has the correct flags on a constructed RegExp', function () { 234 | expect(new RegExp('a', 'g').flags).to.equal('g'); 235 | expect(new RegExp('a', 'i').flags).to.equal('i'); 236 | expect(new RegExp('a', 'm').flags).to.equal('m'); 237 | if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'sticky')) { 238 | expect(new RegExp('a', 'y').flags).to.equal('y'); 239 | } 240 | if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'unicode')) { 241 | expect(new RegExp('a', 'u').flags).to.equal('u'); 242 | } 243 | }); 244 | 245 | it('returns flags sorted on a literal', function () { 246 | expect((/a/gim).flags).to.equal('gim'); 247 | expect((/a/mig).flags).to.equal('gim'); 248 | expect((/a/mgi).flags).to.equal('gim'); 249 | if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'sticky')) { 250 | expect(getRegexLiteral('/a/gyim').flags).to.equal('gimy'); 251 | } 252 | if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'unicode')) { 253 | expect(getRegexLiteral('/a/ugmi').flags).to.equal('gimu'); 254 | } 255 | }); 256 | 257 | it('returns flags sorted on a constructed RegExp', function () { 258 | expect(new RegExp('a', 'gim').flags).to.equal('gim'); 259 | expect(new RegExp('a', 'mig').flags).to.equal('gim'); 260 | expect(new RegExp('a', 'mgi').flags).to.equal('gim'); 261 | if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'sticky')) { 262 | expect(new RegExp('a', 'mygi').flags).to.equal('gimy'); 263 | } 264 | if (Object.prototype.hasOwnProperty.call(RegExp.prototype, 'unicode')) { 265 | expect(new RegExp('a', 'mugi').flags).to.equal('gimu'); 266 | } 267 | }); 268 | }); 269 | 270 | describe('#toString()', function () { 271 | it('throws on null/undefined', function () { 272 | expect(function () { RegExp.prototype.toString.call(null); }).to['throw'](TypeError); 273 | expect(function () { RegExp.prototype.toString.call(undefined); }).to['throw'](TypeError); 274 | }); 275 | 276 | it('has an undefined prototype', function () { 277 | expect(RegExp.prototype.toString.prototype).to.equal(undefined); 278 | }); 279 | 280 | it('works on regexes', function () { 281 | expect(RegExp.prototype.toString.call(/a/g)).to.equal('/a/g'); 282 | expect(RegExp.prototype.toString.call(new RegExp('a', 'g'))).to.equal('/a/g'); 283 | }); 284 | 285 | it('works on non-regexes', function () { 286 | expect(RegExp.prototype.toString.call({ source: 'abc', flags: '' })).to.equal('/abc/'); 287 | expect(RegExp.prototype.toString.call({ source: 'abc', flags: 'xyz' })).to.equal('/abc/xyz'); 288 | }); 289 | 290 | ifSymbolsDescribe('Symbol.match', function () { 291 | if (!hasSymbols || typeof Symbol.match === 'undefined') { 292 | return; 293 | } 294 | 295 | it('accepts a non-regex with Symbol.match', function () { 296 | var obj = { source: 'abc', flags: 'def' }; 297 | obj[Symbol.match] = RegExp.prototype[Symbol.match]; 298 | expect(RegExp.prototype.toString.call(obj)).to.equal('/abc/def'); 299 | }); 300 | }); 301 | }); 302 | 303 | describe('Object properties', function () { 304 | it('does not have the nonstandard $input property', function () { 305 | expect(RegExp).not.to.have.property('$input'); // Chrome < 39, Opera < 26 have this 306 | }); 307 | 308 | it('has "input" property', function () { 309 | expect(RegExp).to.have.ownProperty('input'); 310 | expect(RegExp).to.have.ownProperty('$_'); 311 | }); 312 | 313 | it('has "last match" property', function () { 314 | expect(RegExp).to.have.ownProperty('lastMatch'); 315 | expect(RegExp).to.have.ownProperty('$+'); 316 | }); 317 | 318 | it('has "last paren" property', function () { 319 | expect(RegExp).to.have.ownProperty('lastParen'); 320 | expect(RegExp).to.have.ownProperty('$&'); 321 | }); 322 | 323 | it('has "leftContext" property', function () { 324 | expect(RegExp).to.have.ownProperty('leftContext'); 325 | expect(RegExp).to.have.ownProperty('$`'); 326 | }); 327 | 328 | it('has "rightContext" property', function () { 329 | expect(RegExp).to.have.ownProperty('rightContext'); 330 | expect(RegExp).to.have.ownProperty("$'"); 331 | }); 332 | 333 | it.skip('has "multiline" property', function () { 334 | // fails in IE 9, 10, 11 335 | expect(RegExp).to.have.ownProperty('multiline'); 336 | expect(RegExp).to.have.ownProperty('$*'); 337 | }); 338 | 339 | it('has the right globals', function () { 340 | var matchVars = [ 341 | '$1', 342 | '$2', 343 | '$3', 344 | '$4', 345 | '$5', 346 | '$6', 347 | '$7', 348 | '$8', 349 | '$9' 350 | ]; 351 | matchVars.forEach(function (match) { 352 | expect(RegExp).to.have.property(match); 353 | }); 354 | }); 355 | 356 | describe('updates RegExp globals', function () { 357 | var str = 'abcdefghijklmnopq'; 358 | var re; 359 | beforeEach(function () { 360 | re = /(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)(l)(m)(n)(o)(p)/; 361 | re.exec(str); 362 | }); 363 | 364 | it('has "input"', function () { 365 | expect(RegExp.input).to.equal(str); 366 | expect(RegExp.$_).to.equal(str); 367 | }); 368 | 369 | it('has "multiline"', function () { 370 | if (Object.prototype.hasOwnProperty.call(RegExp, 'multiline')) { 371 | expect(RegExp.multiline).to.equal(false); 372 | } 373 | if (Object.prototype.hasOwnProperty.call(RegExp, '$*')) { 374 | expect(RegExp['$*']).to.equal(false); 375 | } 376 | }); 377 | 378 | it('has "lastMatch"', function () { 379 | expect(RegExp.lastMatch).to.equal('bcdefghijklmnop'); 380 | expect(RegExp['$&']).to.equal('bcdefghijklmnop'); 381 | }); 382 | 383 | // in all but IE, this works. IE lastParen breaks after 11 tokens. 384 | it.skip('has "lastParen"', function () { 385 | expect(RegExp.lastParen).to.equal('p'); 386 | expect(RegExp['$+']).to.equal('p'); 387 | }); 388 | it('has "lastParen" for less than 11 tokens', function () { 389 | (/(b)(c)(d)/).exec('abcdef'); 390 | expect(RegExp.lastParen).to.equal('d'); 391 | expect(RegExp['$+']).to.equal('d'); 392 | }); 393 | 394 | it('has "leftContext"', function () { 395 | expect(RegExp.leftContext).to.equal('a'); 396 | expect(RegExp['$`']).to.equal('a'); 397 | }); 398 | 399 | it('has "rightContext"', function () { 400 | expect(RegExp.rightContext).to.equal('q'); 401 | expect(RegExp["$'"]).to.equal('q'); 402 | }); 403 | 404 | it('has $1 - $9', function () { 405 | expect(RegExp.$1).to.equal('b'); 406 | expect(RegExp.$2).to.equal('c'); 407 | expect(RegExp.$3).to.equal('d'); 408 | expect(RegExp.$4).to.equal('e'); 409 | expect(RegExp.$5).to.equal('f'); 410 | expect(RegExp.$6).to.equal('g'); 411 | expect(RegExp.$7).to.equal('h'); 412 | expect(RegExp.$8).to.equal('i'); 413 | expect(RegExp.$9).to.equal('j'); 414 | }); 415 | }); 416 | }); 417 | }); 418 | -------------------------------------------------------------------------------- /test/set.js: -------------------------------------------------------------------------------- 1 | // Big thanks to V8 folks for test ideas. 2 | // v8/test/mjsunit/harmony/collections.js 3 | 4 | var Assertion = expect().constructor; 5 | Assertion.addMethod('theSameSet', function (otherArray) { 6 | var array = this._obj; 7 | 8 | expect(Array.isArray(array)).to.equal(true); 9 | expect(Array.isArray(otherArray)).to.equal(true); 10 | 11 | var diff = array.filter(function (value) { 12 | return otherArray.every(function (otherValue) { 13 | var areBothNaN = typeof value === 'number' && typeof otherValue === 'number' && value !== value && otherValue !== otherValue; 14 | return !areBothNaN && value !== otherValue; 15 | }); 16 | }); 17 | 18 | this.assert( 19 | diff.length === 0, 20 | 'expected #{this} to be equal to #{exp} (as sets, i.e. no order)', 21 | array, 22 | otherArray 23 | ); 24 | }); 25 | 26 | var $iterator$ = typeof Symbol === 'function' ? Symbol.iterator : '_es6-shim iterator_'; 27 | if (typeof Set === 'function' && typeof Set.prototype['@@iterator'] === 'function') { 28 | $iterator$ = '@@iterator'; 29 | } 30 | 31 | Assertion.addMethod('iterations', function (expected) { 32 | var iterator = this._obj[$iterator$](); 33 | 34 | expect(Array.isArray(expected)).to.equal(true); 35 | var expectedValues = expected.slice(); 36 | 37 | var result; 38 | do { 39 | result = iterator.next(); 40 | expect(result.value).to.eql(expectedValues.shift()); 41 | } while (!result.done); 42 | }); 43 | 44 | describe('Set', function () { 45 | var functionsHaveNames = (function foo() {}).name === 'foo'; 46 | var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit; 47 | var ifShimIt = (typeof process !== 'undefined' && process.env.NO_ES6_SHIM) ? it.skip : it; 48 | var ifGetPrototypeOfIt = Object.getPrototypeOf ? it : xit; 49 | 50 | var range = function (from, to) { 51 | var result = []; 52 | for (var value = from; value < to; value++) { 53 | result.push(value); 54 | } 55 | return result; 56 | }; 57 | 58 | var prototypePropIsEnumerable = Object.prototype.propertyIsEnumerable.call(function () {}, 'prototype'); 59 | var expectNotEnumerable = function (object) { 60 | if (prototypePropIsEnumerable && typeof object === 'function') { 61 | expect(Object.keys(object)).to.eql(['prototype']); 62 | } else { 63 | expect(Object.keys(object)).to.eql([]); 64 | } 65 | }; 66 | 67 | var Sym = typeof Symbol === 'undefined' ? {} : Symbol; 68 | var isSymbol = function (sym) { 69 | return typeof Sym === 'function' && typeof sym === 'symbol'; 70 | }; 71 | var ifSymbolIteratorIt = isSymbol(Sym.iterator) ? it : xit; 72 | 73 | var testSet = function (set, key) { 74 | expect(set.has(key)).to.equal(false); 75 | expect(set['delete'](key)).to.equal(false); 76 | expect(set.add(key)).to.equal(set); 77 | expect(set.has(key)).to.equal(true); 78 | expect(set['delete'](key)).to.equal(true); 79 | expect(set.has(key)).to.equal(false); 80 | expect(set.add(key)).to.equal(set); // add it back 81 | }; 82 | 83 | if (typeof Set === 'undefined') { 84 | return it('exists', function () { 85 | expect(typeof Set).to.equal('function'); 86 | }); 87 | } 88 | 89 | var set; 90 | beforeEach(function () { 91 | set = new Set(); 92 | }); 93 | 94 | afterEach(function () { 95 | set = null; 96 | }); 97 | 98 | it('set iteration', function () { 99 | expect(set.add('a')).to.equal(set); 100 | expect(set.add('b')).to.equal(set); 101 | expect(set.add('c')).to.equal(set); 102 | expect(set.add('d')).to.equal(set); 103 | 104 | var keys = []; 105 | var iterator = set.keys(); 106 | keys.push(iterator.next().value); 107 | expect(set['delete']('a')).to.equal(true); 108 | expect(set['delete']('b')).to.equal(true); 109 | expect(set['delete']('c')).to.equal(true); 110 | expect(set.add('e')).to.equal(set); 111 | keys.push(iterator.next().value); 112 | keys.push(iterator.next().value); 113 | 114 | expect(iterator.next().done).to.equal(true); 115 | expect(set.add('f')).to.equal(set); 116 | expect(iterator.next().done).to.equal(true); 117 | expect(keys).to.eql(['a', 'd', 'e']); 118 | }); 119 | 120 | ifShimIt('is on the exported object', function () { 121 | var exported = require('../'); 122 | expect(exported.Set).to.equal(Set); 123 | }); 124 | 125 | it('should exist in global namespace', function () { 126 | expect(typeof Set).to.equal('function'); 127 | }); 128 | 129 | it('has the right arity', function () { 130 | expect(Set).to.have.property('length', 0); 131 | }); 132 | 133 | it('returns the set from #add() for chaining', function () { 134 | expect(set.add({})).to.equal(set); 135 | }); 136 | 137 | it('should return false when deleting an item not in the set', function () { 138 | expect(set.has('a')).to.equal(false); 139 | expect(set['delete']('a')).to.equal(false); 140 | }); 141 | 142 | it('should accept an iterable as argument', function () { 143 | testSet(set, 'a'); 144 | testSet(set, 'b'); 145 | var set2 = new Set(set); 146 | expect(set2.has('a')).to.equal(true); 147 | expect(set2.has('b')).to.equal(true); 148 | expect(set2).to.have.iterations(['a', 'b']); 149 | }); 150 | 151 | it('accepts an array as an argument', function () { 152 | var arr = ['a', 'b', 'c']; 153 | var setFromArray = new Set(arr); 154 | expect(setFromArray).to.have.iterations(['a', 'b', 'c']); 155 | }); 156 | 157 | it('should not be callable without "new"', function () { 158 | expect(Set).to['throw'](TypeError); 159 | }); 160 | 161 | it('should be subclassable', function () { 162 | if (!Object.setPrototypeOf) { return; } // skip test if on IE < 11 163 | var MySet = function MySet() { 164 | var actualSet = new Set(['a', 'b']); 165 | Object.setPrototypeOf(actualSet, MySet.prototype); 166 | return actualSet; 167 | }; 168 | Object.setPrototypeOf(MySet, Set); 169 | MySet.prototype = Object.create(Set.prototype, { 170 | constructor: { value: MySet } 171 | }); 172 | 173 | var mySet = new MySet(); 174 | testSet(mySet, 'c'); 175 | testSet(mySet, 'd'); 176 | expect(mySet).to.have.iterations(['a', 'b', 'c', 'd']); 177 | }); 178 | 179 | it('should has valid getter and setter calls', function () { 180 | ['add', 'has', 'delete'].forEach(function (method) { 181 | expect(function () { 182 | set[method]({}); 183 | }).to.not['throw'](); 184 | }); 185 | }); 186 | 187 | it('uses SameValueZero even on a Set of size > 4', function () { 188 | var firstFour = [1, 2, 3, 4]; 189 | var fourSet = new Set(firstFour); 190 | expect(fourSet.size).to.equal(4); 191 | expect(fourSet.has(-0)).to.equal(false); 192 | expect(fourSet.has(0)).to.equal(false); 193 | 194 | fourSet.add(-0); 195 | 196 | expect(fourSet.size).to.equal(5); 197 | expect(fourSet.has(0)).to.equal(true); 198 | expect(fourSet.has(-0)).to.equal(true); 199 | }); 200 | 201 | it('should work as expected', function () { 202 | // Run this test twice, one with the "fast" implementation (which only 203 | // allows string and numeric keys) and once with the "slow" impl. 204 | [true, false].forEach(function (slowkeys) { 205 | set = new Set(); 206 | 207 | range(1, 20).forEach(function (number) { 208 | if (slowkeys) { testSet(set, {}); } 209 | testSet(set, number); 210 | testSet(set, number / 100); 211 | testSet(set, 'key-' + number); 212 | testSet(set, String(number)); 213 | if (slowkeys) { testSet(set, Object(String(number))); } 214 | }); 215 | 216 | var testkeys = [+0, Infinity, -Infinity, NaN]; 217 | if (slowkeys) { 218 | testkeys.push(true, false, null, undefined); 219 | } 220 | testkeys.forEach(function (number) { 221 | testSet(set, number); 222 | testSet(set, String(number)); 223 | }); 224 | testSet(set, ''); 225 | 226 | // -0 and +0 should be the same key (Set uses SameValueZero) 227 | expect(set.has(-0)).to.equal(true); 228 | expect(set['delete'](+0)).to.equal(true); 229 | testSet(set, -0); 230 | expect(set.has(+0)).to.equal(true); 231 | 232 | // verify that properties of Object don't peek through. 233 | [ 234 | 'hasOwnProperty', 235 | 'constructor', 236 | 'toString', 237 | 'isPrototypeOf', 238 | '__proto__', 239 | '__parent__', 240 | '__count__' 241 | ].forEach(function (prop) { testSet(set, prop); }); 242 | }); 243 | }); 244 | 245 | describe('#size', function () { 246 | it('returns the expected size', function () { 247 | expect(set.add(1)).to.equal(set); 248 | expect(set.add(5)).to.equal(set); 249 | expect(set.size).to.equal(2); 250 | }); 251 | }); 252 | 253 | describe('#clear()', function () { 254 | ifFunctionsHaveNamesIt('has the right name', function () { 255 | expect(Set.prototype.clear).to.have.property('name', 'clear'); 256 | }); 257 | 258 | it('is not enumerable', function () { 259 | expect(Set.prototype).ownPropertyDescriptor('clear').to.have.property('enumerable', false); 260 | }); 261 | 262 | it('has the right arity', function () { 263 | expect(Set.prototype.clear).to.have.property('length', 0); 264 | }); 265 | 266 | it('clears a Set with only primitives', function () { 267 | expect(set.add(1)).to.equal(set); 268 | expect(set.size).to.equal(1); 269 | expect(set.add(5)).to.equal(set); 270 | expect(set.size).to.equal(2); 271 | expect(set.has(5)).to.equal(true); 272 | set.clear(); 273 | expect(set.size).to.equal(0); 274 | expect(set.has(5)).to.equal(false); 275 | }); 276 | 277 | it('clears a Set with primitives and objects', function () { 278 | expect(set.add(1)).to.equal(set); 279 | expect(set.size).to.equal(1); 280 | var obj = {}; 281 | expect(set.add(obj)).to.equal(set); 282 | expect(set.size).to.equal(2); 283 | expect(set.has(obj)).to.equal(true); 284 | set.clear(); 285 | expect(set.size).to.equal(0); 286 | expect(set.has(obj)).to.equal(false); 287 | }); 288 | }); 289 | 290 | describe('#keys()', function () { 291 | if (!Object.prototype.hasOwnProperty.call(Set.prototype, 'keys')) { 292 | return it('exists', function () { 293 | expect(Set.prototype).to.have.property('keys'); 294 | }); 295 | } 296 | 297 | it('is the same object as #values()', function () { 298 | expect(Set.prototype.keys).to.equal(Set.prototype.values); 299 | }); 300 | 301 | ifFunctionsHaveNamesIt('has the right name', function () { 302 | expect(Set.prototype.keys).to.have.property('name', 'values'); 303 | }); 304 | 305 | it('is not enumerable', function () { 306 | expect(Set.prototype).ownPropertyDescriptor('keys').to.have.property('enumerable', false); 307 | }); 308 | 309 | it('has the right arity', function () { 310 | expect(Set.prototype.keys).to.have.property('length', 0); 311 | }); 312 | }); 313 | 314 | describe('#values()', function () { 315 | if (!Object.prototype.hasOwnProperty.call(Set.prototype, 'values')) { 316 | return it('exists', function () { 317 | expect(Set.prototype).to.have.property('values'); 318 | }); 319 | } 320 | 321 | ifFunctionsHaveNamesIt('has the right name', function () { 322 | expect(Set.prototype.values).to.have.property('name', 'values'); 323 | }); 324 | 325 | it('is not enumerable', function () { 326 | expect(Set.prototype).ownPropertyDescriptor('values').to.have.property('enumerable', false); 327 | }); 328 | 329 | it('has the right arity', function () { 330 | expect(Set.prototype.values).to.have.property('length', 0); 331 | }); 332 | 333 | it('throws when called on a non-Set', function () { 334 | var expectedMessage = /^(Method )?Set.prototype.values called on incompatible receiver |^values method called on incompatible |^Cannot create a Set value iterator for a non-Set object.$|^Set.prototype.values: 'this' is not a Set object$|^std_Set_iterator method called on incompatible \w+$|Set.prototype.values requires that \|this\| be Set| is not an object|Set operation called on non-Set object/; 335 | var nonSets = [true, false, 'abc', NaN, new Map([[1, 2]]), { a: true }, [1], Object('abc'), Object(NaN)]; 336 | nonSets.forEach(function (nonSet) { 337 | expect(function () { return Set.prototype.values.call(nonSet); }).to['throw'](TypeError, expectedMessage); 338 | }); 339 | }); 340 | }); 341 | 342 | describe('#entries()', function () { 343 | if (!Object.prototype.hasOwnProperty.call(Set.prototype, 'entries')) { 344 | return it('exists', function () { 345 | expect(Set.prototype).to.have.property('entries'); 346 | }); 347 | } 348 | 349 | ifFunctionsHaveNamesIt('has the right name', function () { 350 | expect(Set.prototype.entries).to.have.property('name', 'entries'); 351 | }); 352 | 353 | it('is not enumerable', function () { 354 | expect(Set.prototype).ownPropertyDescriptor('entries').to.have.property('enumerable', false); 355 | }); 356 | 357 | it('has the right arity', function () { 358 | expect(Set.prototype.entries).to.have.property('length', 0); 359 | }); 360 | }); 361 | 362 | describe('#has()', function () { 363 | if (!Object.prototype.hasOwnProperty.call(Set.prototype, 'has')) { 364 | return it('exists', function () { 365 | expect(Set.prototype).to.have.property('has'); 366 | }); 367 | } 368 | 369 | ifFunctionsHaveNamesIt('has the right name', function () { 370 | expect(Set.prototype.has).to.have.property('name', 'has'); 371 | }); 372 | 373 | it('is not enumerable', function () { 374 | expect(Set.prototype).ownPropertyDescriptor('has').to.have.property('enumerable', false); 375 | }); 376 | 377 | it('has the right arity', function () { 378 | expect(Set.prototype.has).to.have.property('length', 1); 379 | }); 380 | }); 381 | 382 | it('should allow NaN values as keys', function () { 383 | expect(set.has(NaN)).to.equal(false); 384 | expect(set.has(NaN + 1)).to.equal(false); 385 | expect(set.has(23)).to.equal(false); 386 | expect(set.add(NaN)).to.equal(set); 387 | expect(set.has(NaN)).to.equal(true); 388 | expect(set.has(NaN + 1)).to.equal(true); 389 | expect(set.has(23)).to.equal(false); 390 | }); 391 | 392 | it('should not have [[Enumerable]] props', function () { 393 | expectNotEnumerable(Set); 394 | expectNotEnumerable(Set.prototype); 395 | expectNotEnumerable(new Set()); 396 | }); 397 | 398 | it('should not have an own constructor', function () { 399 | var s = new Set(); 400 | expect(s).not.to.haveOwnPropertyDescriptor('constructor'); 401 | expect(s.constructor).to.equal(Set); 402 | }); 403 | 404 | it('should allow common ecmascript idioms', function () { 405 | expect(set instanceof Set).to.equal(true); 406 | expect(typeof Set.prototype.add).to.equal('function'); 407 | expect(typeof Set.prototype.has).to.equal('function'); 408 | expect(typeof Set.prototype['delete']).to.equal('function'); 409 | }); 410 | 411 | it('should have a unique constructor', function () { 412 | expect(Set.prototype).to.not.equal(Object.prototype); 413 | }); 414 | 415 | describe('has an iterator that works with Array.from', function () { 416 | if (!Object.prototype.hasOwnProperty.call(Array, 'from')) { 417 | return it('requires Array.from to exist', function () { 418 | expect(Array).to.have.property('from'); 419 | }); 420 | } 421 | 422 | var values = [1, NaN, false, true, null, undefined, 'a']; 423 | 424 | it('works with the full set', function () { 425 | expect(new Set(values)).to.have.iterations(values); 426 | }); 427 | 428 | it('works with Set#keys()', function () { 429 | expect(new Set(values).keys()).to.have.iterations(values); 430 | }); 431 | 432 | it('works with Set#values()', function () { 433 | expect(new Set(values).values()).to.have.iterations(values); 434 | }); 435 | 436 | it('works with Set#entries()', function () { 437 | expect(new Set(values).entries()).to.have.iterations([ 438 | [1, 1], 439 | [NaN, NaN], 440 | [false, false], 441 | [true, true], 442 | [null, null], 443 | [undefined, undefined], 444 | ['a', 'a'] 445 | ]); 446 | }); 447 | }); 448 | 449 | ifSymbolIteratorIt('has the right default iteration function', function () { 450 | // fixed in Webkit https://bugs.webkit.org/show_bug.cgi?id=143838 451 | expect(Set.prototype).to.have.property(Sym.iterator, Set.prototype.values); 452 | }); 453 | 454 | it('should preserve insertion order', function () { 455 | var arr1 = ['d', 'a', 'b']; 456 | var arr2 = [3, 2, 'z', 'a', 1]; 457 | var arr3 = [3, 2, 'z', {}, 'a', 1]; 458 | 459 | [arr1, arr2, arr3].forEach(function (array) { 460 | expect(new Set(array)).to.have.iterations(array); 461 | }); 462 | }); 463 | 464 | describe('#forEach', function () { 465 | var setToIterate; 466 | beforeEach(function () { 467 | setToIterate = new Set(); 468 | expect(setToIterate.add('a')).to.equal(setToIterate); 469 | expect(setToIterate.add('b')).to.equal(setToIterate); 470 | expect(setToIterate.add('c')).to.equal(setToIterate); 471 | }); 472 | 473 | afterEach(function () { 474 | setToIterate = null; 475 | }); 476 | 477 | ifFunctionsHaveNamesIt('has the right name', function () { 478 | expect(Set.prototype.forEach).to.have.property('name', 'forEach'); 479 | }); 480 | 481 | it('is not enumerable', function () { 482 | expect(Set.prototype).ownPropertyDescriptor('forEach').to.have.property('enumerable', false); 483 | }); 484 | 485 | it('has the right arity', function () { 486 | expect(Set.prototype.forEach).to.have.property('length', 1); 487 | }); 488 | 489 | it('should be iterable via forEach', function () { 490 | var expectedSet = ['a', 'b', 'c']; 491 | var foundSet = []; 492 | setToIterate.forEach(function (value, alsoValue, entireSet) { 493 | expect(entireSet).to.equal(setToIterate); 494 | expect(value).to.equal(alsoValue); 495 | foundSet.push(value); 496 | }); 497 | expect(foundSet).to.eql(expectedSet); 498 | }); 499 | 500 | it('should iterate over empty keys', function () { 501 | var setWithEmptyKeys = new Set(); 502 | var expectedKeys = [{}, null, undefined, '', NaN, 0]; 503 | expectedKeys.forEach(function (key) { 504 | expect(setWithEmptyKeys.add(key)).to.equal(setWithEmptyKeys); 505 | }); 506 | var foundKeys = []; 507 | setWithEmptyKeys.forEach(function (value, key, entireSet) { 508 | expect([key]).to.be.theSameSet([value]); // handles NaN correctly 509 | expect(entireSet.has(key)).to.equal(true); 510 | foundKeys.push(key); 511 | }); 512 | expect(foundKeys).to.be.theSameSet(expectedKeys); 513 | }); 514 | 515 | it('should support the thisArg', function () { 516 | var context = function () {}; 517 | setToIterate.forEach(function () { 518 | expect(this).to.equal(context); 519 | }, context); 520 | }); 521 | 522 | it('should have a length of 1', function () { 523 | expect(Set.prototype.forEach.length).to.equal(1); 524 | }); 525 | 526 | it('should not revisit modified keys', function () { 527 | var hasModifiedA = false; 528 | setToIterate.forEach(function (value, key) { 529 | if (!hasModifiedA && key === 'a') { 530 | expect(setToIterate.add('a')).to.equal(setToIterate); 531 | hasModifiedA = true; 532 | } else { 533 | expect(key).not.to.equal('a'); 534 | } 535 | }); 536 | }); 537 | 538 | it('visits keys added in the iterator', function () { 539 | var hasAdded = false; 540 | var hasFoundD = false; 541 | setToIterate.forEach(function (value, key) { 542 | if (!hasAdded) { 543 | expect(setToIterate.add('d')).to.equal(setToIterate); 544 | hasAdded = true; 545 | } else if (key === 'd') { 546 | hasFoundD = true; 547 | } 548 | }); 549 | expect(hasFoundD).to.equal(true); 550 | }); 551 | 552 | it('visits keys added in the iterator when there is a deletion (slow path)', function () { 553 | var hasSeenFour = false; 554 | var setToMutate = new Set(); 555 | expect(setToMutate.add({})).to.equal(setToMutate); // force use of the slow O(N) implementation 556 | expect(setToMutate.add('0')).to.equal(setToMutate); 557 | setToMutate.forEach(function (value, key) { 558 | if (key === '0') { 559 | expect(setToMutate['delete']('0')).to.equal(true); 560 | expect(setToMutate.add('4')).to.equal(setToMutate); 561 | } else if (key === '4') { 562 | hasSeenFour = true; 563 | } 564 | }); 565 | expect(hasSeenFour).to.equal(true); 566 | }); 567 | 568 | it('visits keys added in the iterator when there is a deletion (fast path)', function () { 569 | var hasSeenFour = false; 570 | var setToMutate = new Set(); 571 | expect(setToMutate.add('0')).to.equal(setToMutate); 572 | setToMutate.forEach(function (value, key) { 573 | if (key === '0') { 574 | expect(setToMutate['delete']('0')).to.equal(true); 575 | expect(setToMutate.add('4')).to.equal(setToMutate); 576 | } else if (key === '4') { 577 | hasSeenFour = true; 578 | } 579 | }); 580 | expect(hasSeenFour).to.equal(true); 581 | }); 582 | 583 | it('does not visit keys deleted before a visit', function () { 584 | var hasVisitedC = false; 585 | var hasDeletedC = false; 586 | setToIterate.forEach(function (value, key) { 587 | if (key === 'c') { 588 | hasVisitedC = true; 589 | } 590 | if (!hasVisitedC && !hasDeletedC) { 591 | hasDeletedC = setToIterate['delete']('c'); 592 | expect(hasDeletedC).to.equal(true); 593 | } 594 | }); 595 | expect(hasVisitedC).to.equal(false); 596 | }); 597 | 598 | it('should work after deletion of the current key', function () { 599 | var expectedSet = { 600 | a: 'a', 601 | b: 'b', 602 | c: 'c' 603 | }; 604 | var foundSet = {}; 605 | setToIterate.forEach(function (value, key) { 606 | foundSet[key] = value; 607 | expect(setToIterate['delete'](key)).to.equal(true); 608 | }); 609 | expect(foundSet).to.eql(expectedSet); 610 | }); 611 | 612 | it('should convert key -0 to +0', function () { 613 | var zeroSet = new Set(); 614 | var result = []; 615 | expect(zeroSet.add(-0)).to.equal(zeroSet); 616 | zeroSet.forEach(function (key) { 617 | result.push(String(1 / key)); 618 | }); 619 | expect(zeroSet.add(1)).to.equal(zeroSet); 620 | expect(zeroSet.add(0)).to.equal(zeroSet); // shouldn't cause reordering 621 | zeroSet.forEach(function (key) { 622 | result.push(String(1 / key)); 623 | }); 624 | expect(result.join(', ')).to.equal('Infinity, Infinity, 1'); 625 | }); 626 | }); 627 | 628 | it('Set.prototype.size should throw TypeError', function () { 629 | // see https://github.com/paulmillr/es6-shim/issues/176 630 | expect(function () { return Set.prototype.size; }).to['throw'](TypeError); 631 | expect(function () { return Set.prototype.size; }).to['throw'](TypeError); 632 | }); 633 | 634 | it.skip('should throw proper errors when user invokes methods with wrong types of receiver', function () { 635 | }); 636 | 637 | ifGetPrototypeOfIt('SetIterator identification test prototype inequality', function () { 638 | var mapEntriesProto = Object.getPrototypeOf(new Map().entries()); 639 | var setEntriesProto = Object.getPrototypeOf(new Set().entries()); 640 | expect(mapEntriesProto).to.not.equal(setEntriesProto); 641 | }); 642 | 643 | it('SetIterator identification', function () { 644 | var fnSetValues = Set.prototype.values; 645 | var setSentinel = new Set(['SetSentinel']); 646 | var testSet1 = new Set(); 647 | var testSetValues = testSet1.values(); 648 | expect(testSetValues.next.call(fnSetValues.call(setSentinel)).value).to.equal('SetSentinel'); 649 | 650 | var testMap = new Map(); 651 | var testMapValues = testMap.values(); 652 | expect(function () { 653 | return testMapValues.next.call(fnSetValues.call(setSentinel)).value; 654 | }).to['throw'](TypeError); 655 | }); 656 | }); 657 | -------------------------------------------------------------------------------- /test/test_helpers.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line no-native-reassign, no-implicit-globals, no-global-assign 2 | expect = (function () { 3 | var chai = require('chai'); 4 | chai.config.includeStack = true; 5 | return chai.expect; 6 | }()); 7 | 8 | // eslint-disable-next-line no-native-reassign, no-implicit-globals, no-global-assign 9 | assert = (function () { 10 | var chai = require('chai'); 11 | chai.config.includeStack = true; 12 | return chai.assert; 13 | }()); 14 | 15 | if (typeof process === 'undefined' || !process.env.NO_ES6_SHIM) { 16 | require('../'); 17 | } 18 | -------------------------------------------------------------------------------- /test/worker-runner.workerjs: -------------------------------------------------------------------------------- 1 | importScripts( 2 | '../node_modules/es5-shim/es5-shim.js', 3 | '../node_modules/es5-shim/es5-sham.js', 4 | '../es6-shim.js' 5 | ); 6 | 7 | postMessage('ready'); 8 | -------------------------------------------------------------------------------- /test/worker-test.js: -------------------------------------------------------------------------------- 1 | describe('Worker', function () { 2 | var workerErrorEventToError = function (errorEvent) { 3 | var errorText = 'Error in Worker'; 4 | if (errorEvent.filename !== undefined) { 5 | errorText += ' ' + errorEvent.filename; 6 | } 7 | if (errorEvent.lineno !== undefined) { 8 | errorText += '(' + errorEvent.lineno + ')'; 9 | } 10 | if (errorEvent.message !== undefined) { 11 | errorText += ': ' + errorEvent.message; 12 | } 13 | return new Error(errorText); 14 | }; 15 | var canRunWorkerTestInCurrentContext = function () { 16 | var workerConstructorExists = typeof Worker !== 'undefined'; 17 | var locationPropertyExists = typeof location !== 'undefined'; 18 | var runningOnFileUriScheme = locationPropertyExists && location.protocol === 'file:'; 19 | 20 | // The Worker constructor doesn't exist in some older browsers nor does it exist in non-browser contexts like Node. 21 | // Additionally some browsers (at least Chrome) don't allow Workers over file URIs. 22 | // To prevent false negative test failures in the cases where Workers are unavailable for either of those reasons 23 | // we skip this test. 24 | return workerConstructorExists && !runningOnFileUriScheme; 25 | }; 26 | 27 | if (canRunWorkerTestInCurrentContext()) { 28 | it('can import es6-shim', function (done) { 29 | var worker = new Worker('worker-runner.workerjs'); 30 | worker.addEventListener('error', function (errorEvent) { throw workerErrorEventToError(errorEvent); }); 31 | worker.addEventListener('message', function (messageEvent) { 32 | expect(messageEvent.data).to.eql('ready'); 33 | done(); 34 | }); 35 | }); 36 | } 37 | }); 38 | -------------------------------------------------------------------------------- /testling.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | es6-shim tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 | 37 | 38 | --------------------------------------------------------------------------------