Repository: es-shims/es5-shim Branch: master Commit: 901bfdb81324 Files: 36 Total size: 384.3 KB Directory structure: gitextract_r2whttpy/ ├── .eslintrc ├── .gitattributes ├── .github/ │ └── workflows/ │ ├── node-aught.yml │ ├── node-pretest.yml │ ├── node-tens.yml │ ├── rebase.yml │ └── require-allow-edits.yml ├── .gitignore ├── .npmrc ├── .nycrc ├── CHANGELOG.md ├── CONTRIBUTORS.md ├── LICENSE ├── README.md ├── bower.json ├── component.json ├── es5-sham.js ├── es5-shim.js ├── package.json ├── shims.json └── tests/ ├── helpers/ │ └── h-matchers.js ├── index.html ├── index.min.html ├── lib/ │ ├── jasmine-html.js │ ├── jasmine.css │ └── jasmine.js ├── native.html └── spec/ ├── s-array.js ├── s-date.js ├── s-error.js ├── s-function.js ├── s-global.js ├── s-number.js ├── s-object.js ├── s-regexp.js └── s-string.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .eslintrc ================================================ { "root": true, "extends": "@ljharb", "ignorePatterns": [ "*.min.js", "tests/lib/*", ], "rules": { "array-bracket-newline": 0, "object-curly-newline": 0, "camelcase": [0], "complexity": [0], "eqeqeq": [2, "allow-null"], "func-name-matching": 0, "id-length": [2, { "min": 1, "max": 40 }], "indent": [2, 4], "max-lines": 0, "max-lines-per-function": 0, "max-nested-callbacks": [2, 5], "max-params": [2, 7], "max-statements": [1, 30], "new-cap": [2, { "capIsNewExceptions": ["ToInteger", "ToObject", "ToPrimitive", "ToUint32"] }], "no-constant-condition": [1], "no-extend-native": [2, {"exceptions": ["Date", "Error", "RegExp"]}], "no-extra-parens": [0], "no-extra-semi": [1], "no-func-assign": [1], "no-implicit-coercion": [2, { "boolean": false, "number": false, "string": true, "disallowTemplateShorthand": false, "allow": [] }], "no-invalid-this": [0], "no-magic-numbers": [0], "no-native-reassign": [2, {"exceptions": ["Date", "parseInt"]}], "no-new-func": [1], "no-plusplus": [1], "no-restricted-syntax": [2, "ContinueStatement", "DebuggerStatement", "LabeledStatement", "WithStatement"], "no-shadow": [1], "no-unused-vars": [1, { "vars": "all", "args": "after-used" }], "operator-linebreak": [2, "before"], "sort-keys": [0], "spaced-comment": [0], "strict": [0], "multiline-comment-style": 0, }, "overrides": [ { "files": "tests/**", "rules": { "max-len": 0, "max-statements-per-line": [2, { "max": 2 }], }, "env": { "jasmine": true }, }, ], } ================================================ FILE: .gitattributes ================================================ *.min.js -diff merge=ours *.map -diff merge=ours ================================================ FILE: .github/workflows/node-aught.yml ================================================ name: 'Tests: node.js < 10' on: [pull_request, push] jobs: tests: uses: ljharb/actions/.github/workflows/node.yml@main with: range: '< 10' type: minors command: npm run tests-only node: name: 'node < 10' needs: [tests] runs-on: ubuntu-latest steps: - run: 'echo tests completed' ================================================ FILE: .github/workflows/node-pretest.yml ================================================ name: 'Tests: pretest/posttest' on: [pull_request, push] jobs: tests: uses: ljharb/actions/.github/workflows/pretest.yml@main ================================================ FILE: .github/workflows/node-tens.yml ================================================ name: 'Tests: node.js >= 10' on: [pull_request, push] jobs: tests: uses: ljharb/actions/.github/workflows/node.yml@main with: range: '>= 10' type: minors command: npm run tests-only node: name: 'node >= 10' needs: [tests] runs-on: ubuntu-latest steps: - run: 'echo tests completed' ================================================ FILE: .github/workflows/rebase.yml ================================================ name: Automatic Rebase on: [pull_request_target] jobs: _: uses: ljharb/actions/.github/workflows/rebase.yml@main secrets: token: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/require-allow-edits.yml ================================================ name: Require “Allow Edits” on: [pull_request_target] jobs: _: name: "Require “Allow Edits”" runs-on: ubuntu-latest steps: - uses: ljharb/require-allow-edits@main ================================================ FILE: .gitignore ================================================ # gitignore node_modules .DS_Store # Only apps should have lockfiles npm-shrinkwrap.json package-lock.json yarn.lock # coverage data coverage/ .nyc_output/ .npmignore ================================================ FILE: .npmrc ================================================ package-lock=false ================================================ FILE: .nycrc ================================================ { "all": true, "check-coverage": false, "reporter": ["text-summary", "text", "html", "json"], "exclude": [ "coverage", "test", "*.map", "*.min.js" ] } ================================================ FILE: CHANGELOG.md ================================================ 4.6.7 - [Fix] `parseInt`, `String#trim`: properly consider Mongolian Vowel Separator - [Robustness] `substr`: call-bind original substr method - [Tests] ensure only the actual shims are included in tests 4.6.6 - [Fix] `splice`: IE 8: upgrade ES5 impls to ES6 default argument behavior - [Fix] `toExponential`: IE 6 native toExponential does not throw with infinite fractionDigits - [Fix] `Date`: fix a bug in modern Safari (#481) - [Fix] ensure `parseInt` replacements are not constructible - [readme] add standalone shims - [readme] add `Array.prototype.splice` and standalone shim - [Tests] fix a test failure with a custom matcher in IE 6 - [Tests] pave over Firefox’s increased getMinutes precision - [Dev Deps] update `eslint`, `@ljharb/eslint-config` 4.6.5 - [Fix] IE 8 has a broken `Object.defineProperty` - [patch] replace dead link in comment with archive.org link - [Docs] update all possible http: links to https: - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `aud` 4.6.4 - [Fix] `Object.defineProperty`: when shimmed in Chrome <= 36, properly handle writability - [Tests] add some additional tests 4.6.3 - [Fix] `Object.defineProperty`: Chrome <= 36 has a broken dP when setting "prototype" while changing writability - [Fix] `toExponential`: use `thisNumberValue` instead of `Number()` - [readme] fix badges - [readme] add standalone shims - [actions] reuse common workflows - [actions] update codecov uploader - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `safe-publish-latest` - [Tests] avoid loading coverage data when running tests 4.6.2 - [Fix] IE 6-8 fails to throw on infinite fractional digits 4.6.1 - [Fix] `Math.log10` does not exist in older engines, oops - [Fix] `toExponential`: start from 16 instead of 22 - [Fix] `toExponential`: ensure ToNumber is only called once on the receiver - [Robustness] `toExponential`, `toPrecision`: ensure things do not break with later builtin modification 4.6.0 - [New] detect and patch `Number#toExponential` in Edge 15-18, which rounds incorrectly - [Fix] `parseInt`: fails to throw on boxed Symbols in Edge 15-18 - [eslint] ensure autofix makes no further changes - [readme] remove travis badge - [meta] use `prepublishOnly`, for npm 7+ - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `aud` - [tests] use `ljharb/actions/node/install` instead of `ljharb/actions/node/run`; use codecov action - [actions] update workflows 4.5.15 - [Fix] `es5-sham`: `getPrototypeOf`: avoid infinite loop in pre-`__proto__` browsers - [Fix] `split`: add a function name to the "broken capturing groups" shim - [Robustness] cache Math methods - [readme] add standalone shims - [meta] add `in-publish` to avoid running the minifier on install - [meta] run `aud` in `posttest` - [Tests] migrate tests to Github Actions (#474) - [Tests] run `nyc` on all tests - [actions] add "Allow Edits" workflow - [actions] switch Automatic Rebase workflow to `pull_request_target` event - [Dev Deps] update `eslint`, `@ljharb/eslint-config` 4.5.14 - [Fix] handle no `deleteCount` to `splice()` in Opera (#465) - [Refactor] remove unnecessary comparison - [meta] remove unused Makefile and associated utilities - [meta] add `funding` field - [meta] Rename CHANGES to CHANGELOG.md - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `replace`, `semver`; add `safe-publish-latest` - [Tests] fix negative Date tests to handle TZData - [Tests] use shared travis-ci configs - [Tests] remove `jscs` - [Tests] clarify toPrecision's range increased in ES2018 - [actions] add automatic rebasing / merge commit blocking 4.5.13 - [Fix] exclude deprecated Firefox keys (#460) - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `jasmine-node`, `replace`, `semver` 4.5.12 - [meta] republish broken 4.5.11 4.5.11 - [Fix] sync Object.keys excluded list from object-keys (#456) - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `jasmine-node`, `replace`, `semver` - [Tests] pin jasmine-node to ~1.13 4.5.10 - [Fix] Safari 11 throws on `.sort({})`, but not on `.sort(null)` - [Fix] ensure the shimmed parseInt throws with Symbols (#450) - [Fix] skip over `localStorage`, which can’t be accessed on file:// - [Fix] Accessing window.top.{constructor|prototype} throws error in iOS (#445) - [Fix] avoid `width` and `height` on `window`, to prevent reflow (https://github.com/ljharb/object-keys/issues/31) - [Fix] ensure minified literal of `1000000000000000128` stays as that literal (#441) - [Robustness] always prefer `String(x)` over `x.toString()` - [Tests] up to `node` `v9.3`, `v8.9`, `v7.10`, `v6.12`, `v5.12`, `v4.8`; improve test matrix; use `nvm install-latest-npm`; comment out OS X builds; pin included builds to LTS - [Tests] `parseInt`: add another test for NaN parsing (#433) - [Dev Deps] `uglify-js`: add `--support-ie8` and peg to v2.7.x since it doesn’t follow semver - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `jscs`, `uglify-js`, `semver`; remove `concurrently` (#421) 4.5.9 - [Fix] parseInt and parseFloat should both accept null/undefined (#402) - [Tests] up to `node` `v6.2` - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `jscs`, `concurrently` 4.5.8 - [Fix] Check if property descriptor is configurable before re-defining it (#394, #373) - [Dev Deps] update `eslint`, `jscs`, `@ljharb/eslint-config` - [Tests] up to `node` `v5.10`, `v4.4` - [Tests] Use `concurrently` instead of `parallelshell` - [Tests] use `pretest` to run the linter 4.5.7 - [Fix] `bind` in IE 8: Update `is-callable` implementation to v1.1.3 (#390) 4.5.6 - [Fix] `new Date(new Date())` should work in IE 8 (#389) - [Tests] on `node` `v5.7` - [Dev Deps] update `uglify-js` 4.5.5 - [Fix] Adobe Photoshop’s JS engine bizarrely can have `+date !== date.getTime()` (#365) - [Dev Deps] update `eslint` - [Refactor] Update `is-callable` implementation to match latest - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `jscs` 4.5.4 - [Fix] careless error from 5cf99aca49e59bae03b5d542381424bb1b13ec42 4.5.3 - [Fix] Saturday is a day in the week (#386) - [Robustness] improve Function#bind (#381) - [Tests] on `node` `v5.6`, `v4.3` - [Tests] use json3 (#382) - [Dev Deps] update `eslint`, `@ljharb/eslint-config` - [Docs] add note about script order (#379) 4.5.2 - [shim: fix] use `Array#slice`, not `String#slice`, on `String#split` output (#380) 4.5.1 - [Fix] Make sure preexisting + broken `Array#` methods that throw don’t break the runtime (#377) - [Dev Deps] update `jscs` 4.5.0 - [New] `parseFloat('-0')` should return -0 in Opera 12 (#371) - [New] Provide and replace Date UTC methods (#360) - [Robustness] cache `Date` getUTC methods so that `Date#toISOString` doesn’t observably look them up on the receiver - [Robustness] use a cached and shimmed `String#trim` - [Tests] up to `node` `v5.5` - [Tests] add `parallelshell` and use it in a few tasks - [Refactor] rename cached methods to avoid linter warnings - [Dev Deps] update `eslint`, `jscs`, '@ljharb/eslint-config' - [Docs] Update license year to 2016 (#374) 4.4.2 - [shim: fix] use `Array#slice`, not `String#slice`, on `String#split` output (#380) 4.4.1 - [Fix] ensure that IE 11 in compatibility mode doesn't throw (#370) - [Docs] add missing shimmed things 4.4.0 - [New] Detect and patch `RegExp#toString` in IE 8, which returns flags in the wrong order (#364) - [Fix] Patch `Array#sort` on {Chrome, Safari, IE < 9, FF 4} that throws improperly, per ES5 (#354) - [Fix] In IE 6, `window.external` makes `Object.keys` throw - [Fix] `Array#slice`: boxed string access on IE <= 8 (#349) - [Fix] `Array#join`: fix IE 6-8 join called on string literal (#352) - [Fix] Ensure that `Error#message` and `Error#name` are non-enumerable (#358) - [Fix: sham] `Object.getOwnPropertyDescriptor`: In Opera 11.6, `propertyIsEnumerable` is a nonshadowable global, like `toString` - [Robustness] Use a bound form of `Array#slice.call` - [Tests] Properly check for descriptor support in IE <= 8 - [Tests] on `node` `v5.1` - [Tests] Add `Array#slice` tests (#346) - [Dev Deps] update `uglify-js`, `eslint`, `jscs`, `uglify-js`, `semver` - [Docs] Fix broken UMD links (#344) 4.3.2 - [shim: fix] use `Array#slice`, not `String#slice`, on `String#split` output (#380) 4.3.1 - [Fix] `String#split`: revert part of dcce96ae21185a69d2d40e67416e7496b73e8e47 which broke in older browsers (#342) - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `jscs` - [Tests] Firefox allows `Number#toPrecision` values of [1,100], which the spec permits 4.3.0 - [New] `Array#push`: in IE <= 7, `Array#push` was not generic (#336) - [New] `Array#push` in Opera `10.6` has a super weird bug when pushing `undefined` - [New] `Array#join`: In IE <= 7, passing `undefined` didn't use the default separator (#333) - [New] `Error#toString`: prints out the proper message in IE 7 and below (#334) - [New] `Number#toPrecision`: IE 7 and below incorrectly throw when an explicit `undefined` precision is passed (#340) - [Fix] `String#lastIndexOf`: ensure the correct length in IE 8 - [Fix] ensure `parseInt` accepts negative and plus-prefixed hex values (#332) - [Robustness] Use a bound `Array#push` instead of relying on `Function#call` - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `jscs` - [Tests] Add some conditionals to avoid impossible-to-fix test failures in IE 6-8, due to it being unable to distinguish between `undefined` and an absent index (#114) - [Tests] Fix false negatives in IE 6-8 with jasmine comparing arrays to arraylikes (#114) - [Tests] add additional `Array#shift` tests (#337) - [Tests] Add additional `Array#splice` tests (#339) - [Tests] Add `Array#pop` tests, just in case (#338) - [Tests] include `global` tests in HTML test files - [Tests] Make sure the HTML tests run with the right charset - [Tests] ensure `node` `v0.8` tests stay passing. - [Tests] Prevent nondeterminism in the tests - this sometime produced values that are one ms off - [Tests] on `node` `v5.0` - [Tests] fix npm upgrades for older nodes 4.2.1 - [shim: fix] use `Array#slice`, not `String#slice`, on `String#split` output (#380) 4.2.0 - [shim: new] Overwrite `String#lastIndexOf` in IE 9, 10, 11, and Edge, so it has proper unicode support. - [Dev Deps] update `eslint`, `jscs` 4.1.16 - [shim: fix] use `Array#slice`, not `String#slice`, on `String#split` output (#380) 4.1.15 - [shim: fix] new Date + Date.parse: Fix a Safari 8 & 9 bug where the `ms` arg is treated as a signed instead of unsigned int (#329) - [shim: fix] add 'frame' to blacklisted keys (#330) - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `jscs`, `uglify-js` - [Tests] on `node` `v4.2` - [Tests] Date: prevent nondeterminism in the tests - this sometime produced values that are one ms off 4.1.14 - [shim: fix] Wrap more things in a try/catch, because IE sucks and sometimes throws on [[Get]] of window.localStorage (#327) - [Refactor] Use `ES.ToUint32` instead of inline `>>>` - [Tests] up to `node` `v4.1` - [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `semver`, `jscs` 4.1.13 - [shim: fix] Fix a bug where `Date(x)` threw instead of equalling `String(Date(x))` (#326) 4.1.12 - [fix] Make sure uglify doesn't remove function names - [shim: fix] Use `is-arguments` implementation; don't call down legacy code path in modern engines (#325) - [Tests] up to `io.js` `v3.3` - [Dev Deps] update `eslint`, `@ljharb/eslint-config` 4.1.11 - [shim: fix] Object.keys in Safari 9 has some bugs. (Already fixed in Webkit Nightly) - [shim: fix] Omit !Date.parse check in the if statement (#323) - [sham: fix] Fix Object.create sham to not set __proto__ (#301) - [sham: fix] Add a typeof check to Object.getPrototypeOf (#319, #320) - [Tests] up to `io.js` `v3.1` - [Tests] Make sure `Object.getPrototypeOf` tests don't fail when engines implement ES6 semantics - [Docs] Switch from vb.teelaun.ch to versionbadg.es for the npm version badge SVG (#318) - [Dev Deps] Update `eslint`, `uglify-js`, `jscs`; use my personal shared `eslint` config 4.1.10 - [Fix] Fix IE 8 issue with `window.frameElement` access in a child iframe (#322) - [Tests] Consolidating `Date.parse` extended year tests - [Tests] Account for a `Date.parse` precision variance in Safari 8 - [Tests] DRY up some Date.parse tests - [Tests] Don't create globals in Date tests - [Tests] Better failure output when an invalid date's toJSON throws - [Tests] Also compare lengths of array-likes - [Tests] Extra check on Object.keys(arguments) - [Tests] Skip appropriate tests when objects aren't extensible/freezeable/sealable 4.1.9 - [Fix] Remove "extended", add "unicode" in `String#split` shim, to match ES6 - [Fix] Object.keys: Preserve the IE 8 dontEnum bugfix, and the automation equality bugfix. - [Fix] Object.keys: Prevent a deprecation message from showing up in Chrome. - [Performance] Speed up blacklisted key check for Object.keys automation equality bug. - [Tests] Test on `io.js` `v2.4` - [Dev Deps] Update `eslint`, `semver` 4.1.8 - [Fix] Fix an `Object.keys` IE 8 bug where `localStorage.prototype.constructor === localStorage` would throw (#275) - [Fix] Shimmed `Object.defineProperty` should not throw for an empty descriptor (#315) - [Fix] Fix `Date#toISOString` in Safari 5.1 (#243) - [Fix] Use `Object#propertyIsEnumerable` to default the initial "enumerable" value in `Object.getOwnPropertyDescriptor` sham (#289) - [Fix] Fix `Array#splice` with large sparse arrays in Safari 7/8, and Opera 12.15 (#295) - [Robustness] Safely use and reference many builtins internally (also see #313) - [Tests] Add `Date#{getUTCDate,getUTCMonth}` tests to expose Opera 10.6/11.61/12 `Date` bugs - [Dev Deps] Update `eslint` 4.1.7 - Make sure `Date.parse` is not enumerable (#310) 4.1.6 - Support IE 8 when `document.domain` is set (#306, #150) - Remove version from `bower.json` (#307) 4.1.5 - Add a failing runtime check for Safari 8 `Date.parse` - Update `eslint`, `semver` - Test on `io.js` `v2.2` 4.1.4 - Make sure copied `Date` properties remain non-enumerable. - Using a more reliable check for supported property descriptors in non-IE ES3 - Fix 'constructor' in Object.defineProperties sham in ES3 (#252, #305) - Use a reference to `Array#concat` rather than relying on the runtime environment's `concat`. - Test on `io.js` `v2.1` - Clean up `Array.prototype` iteration methods 4.1.3 - Update `license` in `package.json` per https://docs.npmjs.com/files/package.json#license - Update `uglify-js`, `eslint` 4.1.2 - In IE 6-8, `Date` inside the function expression does not reference `DateShim` (#303) - Date: Ensure all code paths have the correct `constructor` property - Date: Don't copy non-own properties from original `Date` - Test up to `io.js` `v2.0.0` - Simplify `isPrimitive` check. - Adding sanity check tests for ES5 `Number` constants. - Update `uglify-js`, `eslint`, `semver` 4.1.1 - Fix name of `parseInt` replacement. - Update copyright year - Update `eslint`, `jscs` - Lock `uglify-js` down to v2.4.17, since v2.4.18 and v2.4.19 have a breaking change. - All grade A-supported `node`/`iojs` versions now ship with an `npm` that understands `^`. - Run `travis-ci` tests on latest `node` and `iojs`; speed up builds; allow 0.8 failures. - Ensure some Object tests don't fail in ES6 - Make sure `Date` instances don't have an enumerable `constructor` property, when possible. 4.1.0 - Update `eslint` - Improve type checks: `Array.isArray`, `isRegex` - Replace `isRegex`/`isString`/`isCallable` checks with inlined versions from npm modules - Note which ES abstract methods are replaceable via `es-abstract` - Run `travis-ci` tests on `iojs`! 4.0.6 - Update `jscs`, `uglify-js`, add `eslint` - es5-sham: fix Object.defineProperty to not check for own properties (#211) - Fix Array#splice bug in Safari 5 (#284) - Fix `Object.keys` issue with boxed primitives with extra properties in older browsers. (#242, #285) 4.0.5 - Update `jscs` so tests pass 4.0.4 - Style/indentation/whitespace cleanups. - README tweaks 4.0.3 - Fix keywords (#268) - add some Date tests - Note in README that the es5-sham requires the es5-shim (https://github.com/es-shims/es5-shim/issues/256#issuecomment-52875710) 4.0.2 - Start including version numbers in minified files (#267) 4.0.1 - Fix legacy arguments object detection in Object.keys (#260) 4.0.0 - No longer shim the ES5-spec behavior of splice when `deleteCount` is omitted - since no engines implement it, and ES6 changes it. (#255) - Use Object.defineProperty where available, so that polyfills are non-enumerable when possible (#250) - lots of internal refactoring - Fixed a bug referencing String#indexOf and String#lastIndexOf before polyfilling it (#253, #254) 3.4.0 - Removed nonstandard SpiderMonkey extension to Array#splice - when `deleteCount` is omitted, it's now treated as 0. (#192, #239) - Fix Object.keys with Arguments objects in Safari 5.0 - Now shimming String#split in Opera 10.6 - Avoid using "toString" as a variable name, since that breaks Opera - Internal implementation and test cleanups 3.3.2 - Remove an internal "bind" call, which should make the shim a bit faster - Fix a bug with object boxing in Array#reduceRight that was failing a test in IE 6 3.3.1 - Fixing an Array#splice bug in IE 6/7 - cleaning up Array#splice tests 3.3.0 - Fix Array#reduceRight in node 0.6 and older browsers (#238) 3.2.0 - Fix es5-sham UMD definition to work properly with AMD (#237) - Ensure that Array methods do not autobox context in strict mode (#233) 3.1.1 - Update minified files (#231) 3.1.0 - Fix String#replace in Firefox up through 29 (#228) 3.0.2 - Fix `Function#bind` in IE 7 and 8 (#224, #225, #226) 3.0.1 - Version bump to ensure npm has newest minified assets 3.0.0 - es5-sham: fix `Object.getPrototypeOf` and `Object.getOwnPropertyDescriptor` for Opera Mini - Better override noncompliant native ES5 methods: `Array#forEach`, `Array#map`, `Array#filter`, `Array#every`, `Array#some`, `Array#reduce`, `Date.parse`, `String#trim` - Added spec-compliant shim for `parseInt` - Ensure `Object.keys` handles more edge cases with `arguments` objects and boxed primitives - Improve minification of builds 2.3.0 - parseInt is now properly shimmed in ES3 browsers to default the radix - update URLs to point to the new organization 2.2.0 - Function.prototype.bind shim now reports correct length on a bound function - fix node 0.6.x v8 bug in Array#forEach - test improvements 2.1.0 - Object.create fixes - tweaks to the Object.defineProperties shim 2.0.0 - Separate reliable shims from dubious shims (shams). 1.2.10 - Group-effort Style Cleanup - Took a stab at fixing Object.defineProperty on IE8 without bad side-effects. (@hax) - Object.isExtensible no longer fakes it. (@xavierm) - Date.prototype.toISOString no longer deals with partial ISO dates, per spec (@kitcambridge) - More (mostly from @bryanforbes) 1.2.9 - Corrections to toISOString by @kitcambridge - Fixed three bugs in array methods revealed by Jasmine tests. - Cleaned up Function.prototype.bind with more fixes and tests from @bryanforbes. 1.2.8 - Actually fixed problems with Function.prototype.bind, and regressions from 1.2.7 (@bryanforbes, @jdalton #36) 1.2.7 - REGRESSED - Fixed problems with Function.prototype.bind when called as a constructor. (@jdalton #36) 1.2.6 - Revised Date.parse to match ES 5.1 (kitcambridge) 1.2.5 - Fixed a bug for padding it Date..toISOString (tadfisher issue #33) 1.2.4 - Fixed a descriptor bug in Object.defineProperty (raynos) 1.2.3 - Cleaned up RequireJS and ``` [package-url]: https://npmjs.org/package/es5-shim [npm-version-svg]: https://versionbadg.es/es-shims/es5-shim.svg [deps-svg]: https://david-dm.org/es-shims/es5-shim.svg [deps-url]: https://david-dm.org/es-shims/es5-shim [dev-deps-svg]: https://david-dm.org/es-shims/es5-shim/dev-status.svg [dev-deps-url]: https://david-dm.org/es-shims/es5-shim#info=devDependencies [npm-badge-png]: https://nodei.co/npm/es5-shim.png?downloads=true&stars=true [license-image]: https://img.shields.io/npm/l/es5-shim.svg [license-url]: LICENSE [downloads-image]: https://img.shields.io/npm/dm/es5-shim.svg [downloads-url]: https://npm-stat.com/charts.html?package=es5-shim [codecov-image]: https://codecov.io/gh/es-shims/es5-shim/branch/main/graphs/badge.svg [codecov-url]: https://app.codecov.io/gh/es-shims/es5-shim/ [actions-image]: https://img.shields.io/github/check-runs/es-shims/es5-shim/master [actions-url]: https://github.com/es-shims/es5-shim/actions ================================================ FILE: bower.json ================================================ { "name": "es5-shim", "main": "es5-shim.js", "repository": { "type": "git", "url": "git://github.com/es-shims/es5-shim" }, "homepage": "https://github.com/es-shims/es5-shim", "authors": [ "Kris Kowal (https://github.com/kriskowal/)", "Sami Samhuri (https://samhuri.net/)", "Florian Schäfer (https://github.com/fschaefer)", "Irakli Gozalishvili (https://gozala.io)", "Kit Cambridge (https://github.com/kitcambridge)", "Jordan Harband (https://github.com/ljharb/)" ], "description": "ECMAScript 5 compatibility shims for legacy JavaScript engines", "keywords": [ "shim", "es5", "es5 shim", "javascript", "ecmascript", "polyfill" ], "license": "MIT", "ignore": [ "**/.*", "node_modules", "bower_components", "tests" ] } ================================================ FILE: component.json ================================================ { "name": "es5-shim", "repo": "es-shims/es5-shim", "description": "ECMAScript 5 compatibility shims for legacy JavaScript engines", "version": "v4.5.1", "keywords": [ "shim", "es5", "es5 shim", "javascript", "ecmascript", "polyfill" ], "license": "MIT", "main": "es5-shim.js", "scripts": [ "es5-shim.js" ] } ================================================ FILE: es5-sham.js ================================================ /*! * https://github.com/es-shims/es5-shim * @license es5-shim Copyright 2009-2020 by contributors, MIT License * see https://github.com/es-shims/es5-shim/blob/master/LICENSE */ // vim: ts=4 sts=4 sw=4 expandtab // Add semicolon to prevent IIFE from being passed as argument to concatenated code. ; // eslint-disable-line no-extra-semi // UMD (Universal Module Definition) // see https://github.com/umdjs/umd/blob/master/templates/returnExports.js (function (root, factory) { 'use strict'; /* global define */ if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(factory); } else if (typeof exports === 'object') { // Node. Does not work with strict CommonJS, but // only CommonJS-like enviroments that support module.exports, // like Node. module.exports = factory(); } else { // Browser globals (root is window) root.returnExports = factory(); // eslint-disable-line no-param-reassign } }(this, function () { var call = Function.call; var prototypeOfObject = Object.prototype; var owns = call.bind(prototypeOfObject.hasOwnProperty); var isEnumerable = call.bind(prototypeOfObject.propertyIsEnumerable); var toStr = call.bind(prototypeOfObject.toString); // If JS engine supports accessors creating shortcuts. var defineGetter; var defineSetter; var lookupGetter; var lookupSetter; var supportsAccessors = owns(prototypeOfObject, '__defineGetter__'); if (supportsAccessors) { /* eslint-disable no-underscore-dangle, no-restricted-properties */ defineGetter = call.bind(prototypeOfObject.__defineGetter__); defineSetter = call.bind(prototypeOfObject.__defineSetter__); lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); /* eslint-enable no-underscore-dangle, no-restricted-properties */ } var isPrimitive = function isPrimitive(o) { return o == null || (typeof o !== 'object' && typeof o !== 'function'); }; // ES5 15.2.3.2 // https://es5.github.io/#x15.2.3.2 if (!Object.getPrototypeOf) { // https://github.com/es-shims/es5-shim/issues#issue/2 // https://johnresig.com/blog/objectgetprototypeof/ // recommended by fschaefer on github // // sure, and webreflection says ^_^ // ... this will nerever possibly return null // ... Opera Mini breaks here with infinite loops Object.getPrototypeOf = function getPrototypeOf(object) { // eslint-disable-next-line no-proto var proto = object.__proto__; if (proto || proto == null) { // `undefined` is for pre-proto browsers return proto; } else if (toStr(object.constructor) === '[object Function]') { return object.constructor.prototype; } else if (object instanceof Object) { return prototypeOfObject; } // Correctly return null for Objects created with `Object.create(null)` // (shammed or native) or `{ __proto__: null}`. Also returns null for // cross-realm objects on browsers that lack `__proto__` support (like // IE <11), but that's the best we can do. return null; }; } // ES5 15.2.3.3 // https://es5.github.io/#x15.2.3.3 // check whether getOwnPropertyDescriptor works if it's given. Otherwise, shim partially. if (Object.defineProperty) { var doesGetOwnPropertyDescriptorWork = function doesGetOwnPropertyDescriptorWork(object) { try { object.sentinel = 0; // eslint-disable-line no-param-reassign return Object.getOwnPropertyDescriptor(object, 'sentinel').value === 0; } catch (exception) { return false; } }; var getOwnPropertyDescriptorWorksOnObject = doesGetOwnPropertyDescriptorWork({}); var getOwnPropertyDescriptorWorksOnDom = typeof document === 'undefined' || doesGetOwnPropertyDescriptorWork(document.createElement('div')); if (!getOwnPropertyDescriptorWorksOnDom || !getOwnPropertyDescriptorWorksOnObject) { var getOwnPropertyDescriptorFallback = Object.getOwnPropertyDescriptor; } } if (!Object.getOwnPropertyDescriptor || getOwnPropertyDescriptorFallback) { var ERR_NON_OBJECT = 'Object.getOwnPropertyDescriptor called on a non-object: '; /* eslint-disable no-proto */ Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { if (isPrimitive(object)) { throw new TypeError(ERR_NON_OBJECT + object); } // make a valiant attempt to use the real getOwnPropertyDescriptor // for I8's DOM elements. if (getOwnPropertyDescriptorFallback) { try { return getOwnPropertyDescriptorFallback.call(Object, object, property); } catch (exception) { // try the shim if the real one doesn't work } } var descriptor; // If object does not owns property return undefined immediately. if (!owns(object, property)) { return descriptor; } // If object has a property then it's for sure `configurable`, and // probably `enumerable`. Detect enumerability though. descriptor = { enumerable: isEnumerable(object, property), configurable: true }; // If JS engine supports accessor properties then property may be a // getter or setter. if (supportsAccessors) { // Unfortunately `__lookupGetter__` will return a getter even // if object has own non getter property along with a same named // inherited getter. To avoid misbehavior we temporary remove // `__proto__` so that `__lookupGetter__` will return getter only // if it's owned by an object. var prototype = object.__proto__; var notPrototypeOfObject = object !== prototypeOfObject; // avoid recursion problem, breaking in Opera Mini when // Object.getOwnPropertyDescriptor(Object.prototype, 'toString') // or any other Object.prototype accessor if (notPrototypeOfObject) { object.__proto__ = prototypeOfObject; // eslint-disable-line no-param-reassign } var getter = lookupGetter(object, property); var setter = lookupSetter(object, property); if (notPrototypeOfObject) { // Once we have getter and setter we can put values back. object.__proto__ = prototype; // eslint-disable-line no-param-reassign } if (getter || setter) { if (getter) { descriptor.get = getter; } if (setter) { descriptor.set = setter; } // If it was accessor property we're done and return here // in order to avoid adding `value` to the descriptor. return descriptor; } } // If we got this far we know that object has an own property that is // not an accessor so we set it as a value and return descriptor. descriptor.value = object[property]; descriptor.writable = true; return descriptor; }; /* eslint-enable no-proto */ } // ES5 15.2.3.4 // https://es5.github.io/#x15.2.3.4 if (!Object.getOwnPropertyNames) { Object.getOwnPropertyNames = function getOwnPropertyNames(object) { return Object.keys(object); }; } // ES5 15.2.3.5 // https://es5.github.io/#x15.2.3.5 if (!Object.create) { // Contributed by Brandon Benvie, October, 2012 var createEmpty; var supportsProto = !({ __proto__: null } instanceof Object); // the following produces false positives // in Opera Mini => not a reliable check // Object.prototype.__proto__ === null // Check for document.domain and active x support // No need to use active x approach when document.domain is not set // see https://github.com/es-shims/es5-shim/issues/150 // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346 /* global ActiveXObject */ var shouldUseActiveX = function shouldUseActiveX() { // return early if document.domain not set if (!document.domain) { return false; } try { return !!new ActiveXObject('htmlfile'); } catch (exception) { return false; } }; // This supports IE8 when document.domain is used // see https://github.com/es-shims/es5-shim/issues/150 // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346 var getEmptyViaActiveX = function getEmptyViaActiveX() { var empty; var xDoc; xDoc = new ActiveXObject('htmlfile'); var script = 'script'; xDoc.write('<' + script + '>'); xDoc.close(); empty = xDoc.parentWindow.Object.prototype; xDoc = null; return empty; }; // The original implementation using an iframe // before the activex approach was added // see https://github.com/es-shims/es5-shim/issues/150 var getEmptyViaIFrame = function getEmptyViaIFrame() { var iframe = document.createElement('iframe'); var parent = document.body || document.documentElement; var empty; iframe.style.display = 'none'; parent.appendChild(iframe); // eslint-disable-next-line no-script-url iframe.src = 'javascript:'; empty = iframe.contentWindow.Object.prototype; parent.removeChild(iframe); iframe = null; return empty; }; /* global document */ if (supportsProto || typeof document === 'undefined') { createEmpty = function () { return { __proto__: null }; }; } else { // In old IE __proto__ can't be used to manually set `null`, nor does // any other method exist to make an object that inherits from nothing, // aside from Object.prototype itself. Instead, create a new global // object and *steal* its Object.prototype and strip it bare. This is // used as the prototype to create nullary objects. createEmpty = function () { // Determine which approach to use // see https://github.com/es-shims/es5-shim/issues/150 var empty = shouldUseActiveX() ? getEmptyViaActiveX() : getEmptyViaIFrame(); delete empty.constructor; delete empty.hasOwnProperty; delete empty.propertyIsEnumerable; delete empty.isPrototypeOf; delete empty.toLocaleString; delete empty.toString; delete empty.valueOf; var Empty = function Empty() {}; Empty.prototype = empty; // short-circuit future calls createEmpty = function () { return new Empty(); }; return new Empty(); }; } Object.create = function create(prototype, properties) { var object; var Type = function Type() {}; // An empty constructor. if (prototype === null) { object = createEmpty(); } else if (isPrimitive(prototype)) { // In the native implementation `parent` can be `null` // OR *any* `instanceof Object` (Object|Function|Array|RegExp|etc) // Use `typeof` tho, b/c in old IE, DOM elements are not `instanceof Object` // like they are in modern browsers. Using `Object.create` on DOM elements // is...err...probably inappropriate, but the native version allows for it. throw new TypeError('Object prototype may only be an Object or null'); // same msg as Chrome } else { Type.prototype = prototype; object = new Type(); // IE has no built-in implementation of `Object.getPrototypeOf` // neither `__proto__`, but this manually setting `__proto__` will // guarantee that `Object.getPrototypeOf` will work as expected with // objects created using `Object.create` // eslint-disable-next-line no-proto object.__proto__ = prototype; } if (properties !== void 0) { Object.defineProperties(object, properties); } return object; }; } // ES5 15.2.3.6 // https://es5.github.io/#x15.2.3.6 // Patch for WebKit and IE8 standard mode // Designed by hax // related issue: https://github.com/es-shims/es5-shim/issues#issue/5 // IE8 Reference: // https://msdn.microsoft.com/en-us/library/dd282900.aspx // https://msdn.microsoft.com/en-us/library/dd229916.aspx // WebKit Bugs: // https://bugs.webkit.org/show_bug.cgi?id=36423 var doesDefinePropertyWork = function doesDefinePropertyWork(object) { try { Object.defineProperty(object, 'sentinel', {}); return 'sentinel' in object; } catch (exception) { return false; } }; // check whether defineProperty works if it's given. Otherwise, // shim partially. if (Object.defineProperty) { var definePropertyWorksOnObject = doesDefinePropertyWork({}); var definePropertyWorksOnDom = typeof document === 'undefined' || doesDefinePropertyWork(document.createElement('div')); if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { var definePropertyFallback = Object.defineProperty, definePropertiesFallback = Object.defineProperties; } } if (!Object.defineProperty || definePropertyFallback) { var ERR_NON_OBJECT_DESCRIPTOR = 'Property description must be an object: '; var ERR_NON_OBJECT_TARGET = 'Object.defineProperty called on non-object: '; var ERR_ACCESSORS_NOT_SUPPORTED = 'getters & setters can not be defined on this javascript engine'; Object.defineProperty = function defineProperty(object, property, descriptor) { if (isPrimitive(object)) { throw new TypeError(ERR_NON_OBJECT_TARGET + object); } if (isPrimitive(descriptor)) { throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); } // make a valiant attempt to use the real defineProperty // for I8's DOM elements. if (definePropertyFallback) { try { return definePropertyFallback.call(Object, object, property, descriptor); } catch (exception) { // try the shim if the real one doesn't work } } // If it's a data property. if ('value' in descriptor) { // fail silently if 'writable', 'enumerable', or 'configurable' // are requested but not supported /* // alternate approach: if ( // can't implement these features; allow false but not true ('writable' in descriptor && !descriptor.writable) || ('enumerable' in descriptor && !descriptor.enumerable) || ('configurable' in descriptor && !descriptor.configurable) )) throw new RangeError( 'This implementation of Object.defineProperty does not support configurable, enumerable, or writable.' ); */ if (supportsAccessors && (lookupGetter(object, property) || lookupSetter(object, property))) { // As accessors are supported only on engines implementing // `__proto__` we can safely override `__proto__` while defining // a property to make sure that we don't hit an inherited // accessor. /* eslint-disable no-proto, no-param-reassign */ var prototype = object.__proto__; object.__proto__ = prototypeOfObject; // Deleting a property anyway since getter / setter may be // defined on object itself. delete object[property]; object[property] = descriptor.value; // Setting original `__proto__` back now. object.__proto__ = prototype; /* eslint-enable no-proto, no-param-reassign */ } else { object[property] = descriptor.value; // eslint-disable-line no-param-reassign } } else { var hasGetter = 'get' in descriptor; var hasSetter = 'set' in descriptor; if (!supportsAccessors && (hasGetter || hasSetter)) { throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); } // If we got that far then getters and setters can be defined !! if (hasGetter) { defineGetter(object, property, descriptor.get); } if (hasSetter) { defineSetter(object, property, descriptor.set); } } return object; }; } // ES5 15.2.3.7 // https://es5.github.io/#x15.2.3.7 if (!Object.defineProperties || definePropertiesFallback) { Object.defineProperties = function defineProperties(object, properties) { // make a valiant attempt to use the real defineProperties if (definePropertiesFallback) { try { return definePropertiesFallback.call(Object, object, properties); } catch (exception) { // try the shim if the real one doesn't work } } Object.keys(properties).forEach(function (property) { if (property !== '__proto__') { Object.defineProperty(object, property, properties[property]); } }); return object; }; } // ES5 15.2.3.8 // https://es5.github.io/#x15.2.3.8 if (!Object.seal) { Object.seal = function seal(object) { if (Object(object) !== object) { throw new TypeError('Object.seal can only be called on Objects.'); } // this is misleading and breaks feature-detection, but // allows "securable" code to "gracefully" degrade to working // but insecure code. return object; }; } // ES5 15.2.3.9 // https://es5.github.io/#x15.2.3.9 if (!Object.freeze) { Object.freeze = function freeze(object) { if (Object(object) !== object) { throw new TypeError('Object.freeze can only be called on Objects.'); } // this is misleading and breaks feature-detection, but // allows "securable" code to "gracefully" degrade to working // but insecure code. return object; }; } // detect a Rhino bug and patch it try { Object.freeze(function () {}); } catch (exception) { Object.freeze = (function (freezeObject) { return function freeze(object) { if (typeof object === 'function') { return object; } return freezeObject(object); }; }(Object.freeze)); } // ES5 15.2.3.10 // https://es5.github.io/#x15.2.3.10 if (!Object.preventExtensions) { Object.preventExtensions = function preventExtensions(object) { if (Object(object) !== object) { throw new TypeError('Object.preventExtensions can only be called on Objects.'); } // this is misleading and breaks feature-detection, but // allows "securable" code to "gracefully" degrade to working // but insecure code. return object; }; } // ES5 15.2.3.11 // https://es5.github.io/#x15.2.3.11 if (!Object.isSealed) { Object.isSealed = function isSealed(object) { if (Object(object) !== object) { throw new TypeError('Object.isSealed can only be called on Objects.'); } return false; }; } // ES5 15.2.3.12 // https://es5.github.io/#x15.2.3.12 if (!Object.isFrozen) { Object.isFrozen = function isFrozen(object) { if (Object(object) !== object) { throw new TypeError('Object.isFrozen can only be called on Objects.'); } return false; }; } // ES5 15.2.3.13 // https://es5.github.io/#x15.2.3.13 if (!Object.isExtensible) { Object.isExtensible = function isExtensible(object) { // 1. If Type(O) is not Object throw a TypeError exception. if (Object(object) !== object) { throw new TypeError('Object.isExtensible can only be called on Objects.'); } // 2. Return the Boolean value of the [[Extensible]] internal property of O. var name = ''; while (owns(object, name)) { name += '?'; } object[name] = true; // eslint-disable-line no-param-reassign var returnValue = owns(object, name); delete object[name]; // eslint-disable-line no-param-reassign return returnValue; }; } })); ================================================ FILE: es5-shim.js ================================================ /*! * https://github.com/es-shims/es5-shim * @license es5-shim Copyright 2009-2020 by contributors, MIT License * see https://github.com/es-shims/es5-shim/blob/master/LICENSE */ // vim: ts=4 sts=4 sw=4 expandtab // Add semicolon to prevent IIFE from being passed as argument to concatenated code. ; // eslint-disable-line no-extra-semi // UMD (Universal Module Definition) // see https://github.com/umdjs/umd/blob/master/templates/returnExports.js (function (root, factory) { 'use strict'; /* global define */ if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(factory); } else if (typeof exports === 'object') { // Node. Does not work with strict CommonJS, but // only CommonJS-like enviroments that support module.exports, // like Node. module.exports = factory(); } else { // Browser globals (root is window) root.returnExports = factory(); // eslint-disable-line no-param-reassign } }(this, function () { /** * Brings an environment as close to ECMAScript 5 compliance * as is possible with the facilities of erstwhile engines. * * Annotated ES5: https://es5.github.io/ (specific links below) * ES5 Spec: https://www.ecma-international.org/wp-content/uploads/ECMA-262_5.1_edition_june_2011.pdf * Required reading: https://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/ */ // Shortcut to an often accessed properties, in order to avoid multiple // dereference that costs universally. This also holds a reference to known-good // functions. var $Array = Array; var ArrayPrototype = $Array.prototype; var $Object = Object; var ObjectPrototype = $Object.prototype; var $Function = Function; var FunctionPrototype = $Function.prototype; var $String = String; var StringPrototype = $String.prototype; var $Number = Number; var NumberPrototype = $Number.prototype; var array_slice = ArrayPrototype.slice; var array_splice = ArrayPrototype.splice; var array_push = ArrayPrototype.push; var array_unshift = ArrayPrototype.unshift; var array_concat = ArrayPrototype.concat; var array_join = ArrayPrototype.join; var call = FunctionPrototype.call; var apply = FunctionPrototype.apply; var max = Math.max; var min = Math.min; var floor = Math.floor; var abs = Math.abs; var pow = Math.pow; var round = Math.round; var log = Math.log; var LOG10E = Math.LOG10E; var log10 = Math.log10 || function log10(value) { return log(value) * LOG10E; }; // Having a toString local variable name breaks in Opera so use to_string. var to_string = ObjectPrototype.toString; /* eslint-disable one-var-declaration-per-line, no-redeclare, max-statements-per-line */ var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol'; var isCallable; /* inlined from https://npmjs.com/is-callable */ var fnToStr = Function.prototype.toString, constructorRegex = /^\s*class /, isES6ClassFn = function isES6ClassFn(value) { try { var fnStr = fnToStr.call(value); var singleStripped = fnStr.replace(/\/\/.*\n/g, ''); var multiStripped = singleStripped.replace(/\/\*[.\s\S]*\*\//g, ''); var spaceStripped = multiStripped.replace(/\n/mg, ' ').replace(/ {2}/g, ' '); return constructorRegex.test(spaceStripped); } catch (e) { return false; /* not a function */ } }, tryFunctionObject = function tryFunctionObject(value) { try { if (isES6ClassFn(value)) { return false; } fnToStr.call(value); return true; } catch (e) { return false; } }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]', isCallable = function isCallable(value) { if (!value) { return false; } if (typeof value !== 'function' && typeof value !== 'object') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } if (isES6ClassFn(value)) { return false; } var strClass = to_string.call(value); return strClass === fnClass || strClass === genClass; }; var isRegex; /* inlined from https://npmjs.com/is-regex */ var regexExec = RegExp.prototype.exec, tryRegexExec = function tryRegexExec(value) { try { regexExec.call(value); return true; } catch (e) { return false; } }, regexClass = '[object RegExp]'; isRegex = function isRegex(value) { if (typeof value !== 'object') { return false; } return hasToStringTag ? tryRegexExec(value) : to_string.call(value) === regexClass; }; var isString; /* inlined from https://npmjs.com/is-string */ var strValue = String.prototype.valueOf, tryStringObject = function tryStringObject(value) { try { strValue.call(value); return true; } catch (e) { return false; } }, stringClass = '[object String]'; isString = function isString(value) { if (typeof value === 'string') { return true; } if (typeof value !== 'object') { return false; } return hasToStringTag ? tryStringObject(value) : to_string.call(value) === stringClass; }; /* eslint-enable one-var-declaration-per-line, no-redeclare, max-statements-per-line */ /* inlined from https://npmjs.com/define-properties */ var supportsDescriptors = $Object.defineProperty && (function () { try { var obj = {}; $Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); // eslint-disable-next-line no-unreachable-loop, max-statements-per-line for (var _ in obj) { return false; } // jscs:ignore disallowUnusedVariables return obj.x === obj; } catch (e) { /* this is ES3 */ return false; } }()); var defineProperties = (function (has) { // Define configurable, writable, and non-enumerable props // if they don't exist. var defineProperty; if (supportsDescriptors) { defineProperty = function (object, name, method, forceAssign) { if (!forceAssign && (name in object)) { return; } $Object.defineProperty(object, name, { configurable: true, enumerable: false, writable: true, value: method }); }; } else { defineProperty = function (object, name, method, forceAssign) { if (!forceAssign && (name in object)) { return; } object[name] = method; // eslint-disable-line no-param-reassign }; } return function defineProperties(object, map, forceAssign) { for (var name in map) { if (has.call(map, name)) { defineProperty(object, name, map[name], forceAssign); } } }; }(ObjectPrototype.hasOwnProperty)); // this is needed in Chrome 15 (probably earlier) - 36 // https://bugs.chromium.org/p/v8/issues/detail?id=3334 if ($Object.defineProperty && supportsDescriptors) { var F = function () {}; var toStringSentinel = {}; var sentinel = { toString: toStringSentinel }; $Object.defineProperty(F, 'prototype', { value: sentinel, writable: false }); if ((new F()).toString !== toStringSentinel) { var $dP = $Object.defineProperty; var $gOPD = $Object.getOwnPropertyDescriptor; defineProperties($Object, { defineProperty: function defineProperty(o, k, d) { var key = $String(k); if (typeof o === 'function' && key === 'prototype') { var desc = $gOPD(o, key); if (desc.writable && !d.writable && 'value' in d) { try { o[key] = d.value; // eslint-disable-line no-param-reassign } catch (e) { /**/ } } return $dP(o, key, { configurable: 'configurable' in d ? d.configurable : desc.configurable, enumerable: 'enumerable' in d ? d.enumerable : desc.enumerable, writable: d.writable }); } return $dP(o, key, d); } }, true); } } // // Util // ====== // /* replaceable with https://npmjs.com/package/es-abstract /helpers/isPrimitive */ var isPrimitive = function isPrimitive(input) { var type = typeof input; return input === null || (type !== 'object' && type !== 'function'); }; var isActualNaN = $Number.isNaN || function isActualNaN(x) { return x !== x; }; var ES = { // ES5 9.4 // https://es5.github.io/#x9.4 // http://jsperf.com/to-integer /* replaceable with https://npmjs.com/package/es-abstract ES5.ToInteger */ ToInteger: function ToInteger(num) { var n = +num; if (isActualNaN(n)) { n = 0; } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) { n = (n > 0 || -1) * floor(abs(n)); } return n; }, /* replaceable with https://npmjs.com/package/es-abstract ES5.ToPrimitive */ ToPrimitive: function ToPrimitive(input) { var val, valueOf, toStr; if (isPrimitive(input)) { return input; } valueOf = input.valueOf; if (isCallable(valueOf)) { val = valueOf.call(input); if (isPrimitive(val)) { return val; } } toStr = input.toString; if (isCallable(toStr)) { val = toStr.call(input); if (isPrimitive(val)) { return val; } } throw new TypeError(); }, // ES5 9.9 // https://es5.github.io/#x9.9 /* replaceable with https://npmjs.com/package/es-abstract ES5.ToObject */ ToObject: function (o) { if (o == null) { // this matches both null and undefined throw new TypeError("can't convert " + o + ' to object'); } return $Object(o); }, /* replaceable with https://npmjs.com/package/es-abstract ES5.ToUint32 */ ToUint32: function ToUint32(x) { return x >>> 0; } }; // // Function // ======== // // ES-5 15.3.4.5 // https://es5.github.io/#x15.3.4.5 var Empty = function Empty() {}; defineProperties(FunctionPrototype, { bind: function bind(that) { // .length is 1 // 1. Let Target be the this value. var target = this; // 2. If IsCallable(Target) is false, throw a TypeError exception. if (!isCallable(target)) { throw new TypeError('Function.prototype.bind called on incompatible ' + target); } // 3. Let A be a new (possibly empty) internal list of all of the // argument values provided after thisArg (arg1, arg2 etc), in order. // XXX slicedArgs will stand in for "A" if used var args = array_slice.call(arguments, 1); // for normal call // 4. Let F be a new native ECMAScript object. // 11. Set the [[Prototype]] internal property of F to the standard // built-in Function prototype object as specified in 15.3.3.1. // 12. Set the [[Call]] internal property of F as described in // 15.3.4.5.1. // 13. Set the [[Construct]] internal property of F as described in // 15.3.4.5.2. // 14. Set the [[HasInstance]] internal property of F as described in // 15.3.4.5.3. var bound; var binder = function () { if (this instanceof bound) { // 15.3.4.5.2 [[Construct]] // When the [[Construct]] internal method of a function object, // F that was created using the bind function is called with a // list of arguments ExtraArgs, the following steps are taken: // 1. Let target be the value of F's [[TargetFunction]] // internal property. // 2. If target has no [[Construct]] internal method, a // TypeError exception is thrown. // 3. Let boundArgs be the value of F's [[BoundArgs]] internal // property. // 4. Let args be a new list containing the same values as the // list boundArgs in the same order followed by the same // values as the list ExtraArgs in the same order. // 5. Return the result of calling the [[Construct]] internal // method of target providing args as the arguments. var result = apply.call( target, this, array_concat.call(args, array_slice.call(arguments)) ); if ($Object(result) === result) { return result; } return this; } // 15.3.4.5.1 [[Call]] // When the [[Call]] internal method of a function object, F, // which was created using the bind function is called with a // this value and a list of arguments ExtraArgs, the following // steps are taken: // 1. Let boundArgs be the value of F's [[BoundArgs]] internal // property. // 2. Let boundThis be the value of F's [[BoundThis]] internal // property. // 3. Let target be the value of F's [[TargetFunction]] internal // property. // 4. Let args be a new list containing the same values as the // list boundArgs in the same order followed by the same // values as the list ExtraArgs in the same order. // 5. Return the result of calling the [[Call]] internal method // of target providing boundThis as the this value and // providing args as the arguments. // equiv: target.call(this, ...boundArgs, ...args) return apply.call( target, that, array_concat.call(args, array_slice.call(arguments)) ); }; // 15. If the [[Class]] internal property of Target is "Function", then // a. Let L be the length property of Target minus the length of A. // b. Set the length own property of F to either 0 or L, whichever is // larger. // 16. Else set the length own property of F to 0. var boundLength = max(0, target.length - args.length); // 17. Set the attributes of the length own property of F to the values // specified in 15.3.5.1. var boundArgs = []; for (var i = 0; i < boundLength; i++) { array_push.call(boundArgs, '$' + i); } // XXX Build a dynamic function with desired amount of arguments is the only // way to set the length property of a function. // In environments where Content Security Policies enabled (Chrome extensions, // for ex.) all use of eval or Function costructor throws an exception. // However in all of these environments Function.prototype.bind exists // and so this code will never be executed. bound = $Function('binder', 'return function (' + array_join.call(boundArgs, ',') + '){ return binder.apply(this, arguments); }')(binder); if (target.prototype) { Empty.prototype = target.prototype; bound.prototype = new Empty(); // Clean up dangling references. Empty.prototype = null; } // TODO // 18. Set the [[Extensible]] internal property of F to true. // TODO // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3). // 20. Call the [[DefineOwnProperty]] internal method of F with // arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: // thrower, [[Enumerable]]: false, [[Configurable]]: false}, and // false. // 21. Call the [[DefineOwnProperty]] internal method of F with // arguments "arguments", PropertyDescriptor {[[Get]]: thrower, // [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false}, // and false. // TODO // NOTE Function objects created using Function.prototype.bind do not // have a prototype property or the [[Code]], [[FormalParameters]], and // [[Scope]] internal properties. // XXX can't delete prototype in pure-js. // 22. Return F. return bound; } }); // _Please note: Shortcuts are defined after `Function.prototype.bind` as we // use it in defining shortcuts. var owns = call.bind(ObjectPrototype.hasOwnProperty); var toStr = call.bind(ObjectPrototype.toString); var arraySlice = call.bind(array_slice); var arraySliceApply = apply.bind(array_slice); /* globals document */ if (typeof document === 'object' && document && document.documentElement) { try { arraySlice(document.documentElement.childNodes); } catch (e) { var origArraySlice = arraySlice; var origArraySliceApply = arraySliceApply; arraySlice = function arraySliceIE(arr) { var r = []; var i = arr.length; while (i-- > 0) { r[i] = arr[i]; } return origArraySliceApply(r, origArraySlice(arguments, 1)); }; arraySliceApply = function arraySliceApplyIE(arr, args) { return origArraySliceApply(arraySlice(arr), args); }; } } var strSlice = call.bind(StringPrototype.slice); var strSplit = call.bind(StringPrototype.split); var strIndexOf = call.bind(StringPrototype.indexOf); var pushCall = call.bind(array_push); var isEnum = call.bind(ObjectPrototype.propertyIsEnumerable); var arraySort = call.bind(ArrayPrototype.sort); // // Array // ===== // var isArray = $Array.isArray || function isArray(obj) { return toStr(obj) === '[object Array]'; }; // ES5 15.4.4.12 // https://es5.github.io/#x15.4.4.13 // Return len+argCount. // [bugfix, ielt8] // IE < 8 bug: [].unshift(0) === undefined but should be "1" var hasUnshiftReturnValueBug = [].unshift(0) !== 1; defineProperties(ArrayPrototype, { unshift: function () { array_unshift.apply(this, arguments); return this.length; } }, hasUnshiftReturnValueBug); // ES5 15.4.3.2 // https://es5.github.io/#x15.4.3.2 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray defineProperties($Array, { isArray: isArray }); // The IsCallable() check in the Array functions // has been replaced with a strict check on the // internal class of the object to trap cases where // the provided function was actually a regular // expression literal, which in V8 and // JavaScriptCore is a typeof "function". Only in // V8 are regular expression literals permitted as // reduce parameters, so it is desirable in the // general case for the shim to match the more // strict and common behavior of rejecting regular // expressions. // ES5 15.4.4.18 // https://es5.github.io/#x15.4.4.18 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach // Check failure of by-index access of string characters (IE < 9) // and failure of `0 in boxedString` (Rhino) var boxedString = $Object('a'); var splitString = boxedString[0] !== 'a' || !(0 in boxedString); var properlyBoxesContext = function properlyBoxed(method) { // Check node 0.6.21 bug where third parameter is not boxed var properlyBoxesNonStrict = true; var properlyBoxesStrict = true; var threwException = false; if (method) { try { method.call('foo', function (_, __, context) { if (typeof context !== 'object') { properlyBoxesNonStrict = false; } }); method.call([1], function () { 'use strict'; properlyBoxesStrict = typeof this === 'string'; }, 'x'); } catch (e) { threwException = true; } } return !!method && !threwException && properlyBoxesNonStrict && properlyBoxesStrict; }; defineProperties(ArrayPrototype, { forEach: function forEach(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var i = -1; var length = ES.ToUint32(self.length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.forEach callback must be a function'); } while (++i < length) { if (i in self) { // Invoke the callback function with call, passing arguments: // context, property value, property key, thisArg object if (typeof T === 'undefined') { callbackfn(self[i], i, object); } else { callbackfn.call(T, self[i], i, object); } } } } }, !properlyBoxesContext(ArrayPrototype.forEach)); // ES5 15.4.4.19 // https://es5.github.io/#x15.4.4.19 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map defineProperties(ArrayPrototype, { map: function map(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var result = $Array(length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.map callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self) { if (typeof T === 'undefined') { result[i] = callbackfn(self[i], i, object); } else { result[i] = callbackfn.call(T, self[i], i, object); } } } return result; } }, !properlyBoxesContext(ArrayPrototype.map)); // ES5 15.4.4.20 // https://es5.github.io/#x15.4.4.20 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter defineProperties(ArrayPrototype, { filter: function filter(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var result = []; var value; var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.filter callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self) { value = self[i]; if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) { pushCall(result, value); } } } return result; } }, !properlyBoxesContext(ArrayPrototype.filter)); // ES5 15.4.4.16 // https://es5.github.io/#x15.4.4.16 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every defineProperties(ArrayPrototype, { every: function every(callbackfn/*, thisArg*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.every callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self && !(typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { return false; } } return true; } }, !properlyBoxesContext(ArrayPrototype.every)); // ES5 15.4.4.17 // https://es5.github.io/#x15.4.4.17 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some defineProperties(ArrayPrototype, { some: function some(callbackfn/*, thisArg */) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); var T; if (arguments.length > 1) { T = arguments[1]; } // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.some callback must be a function'); } for (var i = 0; i < length; i++) { if (i in self && (typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) { return true; } } return false; } }, !properlyBoxesContext(ArrayPrototype.some)); // ES5 15.4.4.21 // https://es5.github.io/#x15.4.4.21 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce var reduceCoercesToObject = false; if (ArrayPrototype.reduce) { reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object'; } defineProperties(ArrayPrototype, { reduce: function reduce(callbackfn/*, initialValue*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.reduce callback must be a function'); } // no value to return if no initial value and an empty array if (length === 0 && arguments.length === 1) { throw new TypeError('reduce of empty array with no initial value'); } var i = 0; var result; if (arguments.length >= 2) { result = arguments[1]; } else { do { if (i in self) { result = self[i++]; break; } // if array contains no values, no initial value to return if (++i >= length) { throw new TypeError('reduce of empty array with no initial value'); } } while (true); } for (; i < length; i++) { if (i in self) { result = callbackfn(result, self[i], i, object); } } return result; } }, !reduceCoercesToObject); // ES5 15.4.4.22 // https://es5.github.io/#x15.4.4.22 // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight var reduceRightCoercesToObject = false; if (ArrayPrototype.reduceRight) { reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object'; } defineProperties(ArrayPrototype, { reduceRight: function reduceRight(callbackfn/*, initial*/) { var object = ES.ToObject(this); var self = splitString && isString(this) ? strSplit(this, '') : object; var length = ES.ToUint32(self.length); // If no callback function or if callback is not a callable function if (!isCallable(callbackfn)) { throw new TypeError('Array.prototype.reduceRight callback must be a function'); } // no value to return if no initial value, empty array if (length === 0 && arguments.length === 1) { throw new TypeError('reduceRight of empty array with no initial value'); } var result; var i = length - 1; if (arguments.length >= 2) { result = arguments[1]; } else { do { if (i in self) { result = self[i--]; break; } // if array contains no values, no initial value to return if (--i < 0) { throw new TypeError('reduceRight of empty array with no initial value'); } } while (true); } if (i < 0) { return result; } do { if (i in self) { result = callbackfn(result, self[i], i, object); } } while (i--); return result; } }, !reduceRightCoercesToObject); // ES5 15.4.4.14 // https://es5.github.io/#x15.4.4.14 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf var hasFirefox2IndexOfBug = ArrayPrototype.indexOf && [0, 1].indexOf(1, 2) !== -1; defineProperties(ArrayPrototype, { indexOf: function indexOf(searchElement/*, fromIndex */) { var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); var length = ES.ToUint32(self.length); if (length === 0) { return -1; } var i = 0; if (arguments.length > 1) { i = ES.ToInteger(arguments[1]); } // handle negative indices i = i >= 0 ? i : max(0, length + i); for (; i < length; i++) { if (i in self && self[i] === searchElement) { return i; } } return -1; } }, hasFirefox2IndexOfBug); // ES5 15.4.4.15 // https://es5.github.io/#x15.4.4.15 // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf var hasFirefox2LastIndexOfBug = ArrayPrototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1; defineProperties(ArrayPrototype, { lastIndexOf: function lastIndexOf(searchElement/*, fromIndex */) { var self = splitString && isString(this) ? strSplit(this, '') : ES.ToObject(this); var length = ES.ToUint32(self.length); if (length === 0) { return -1; } var i = length - 1; if (arguments.length > 1) { i = min(i, ES.ToInteger(arguments[1])); } // handle negative indices i = i >= 0 ? i : length - abs(i); for (; i >= 0; i--) { if (i in self && searchElement === self[i]) { return i; } } return -1; } }, hasFirefox2LastIndexOfBug); // ES5 15.4.4.12 // https://es5.github.io/#x15.4.4.12 var spliceNoopReturnsEmptyArray = (function () { var a = [1, 2]; var result = a.splice(); return a.length === 2 && isArray(result) && result.length === 0; }()); defineProperties(ArrayPrototype, { // Safari 5.0 bug where .splice() returns undefined splice: function splice(start, deleteCount) { if (arguments.length === 0) { return []; } return array_splice.apply(this, arguments); } }, !spliceNoopReturnsEmptyArray); var spliceWorksWithEmptyObject = (function () { var obj = {}; ArrayPrototype.splice.call(obj, 0, 0, 1); return obj.length === 1; }()); var hasES6Defaults = [0, 1, 2].splice(0).length === 3; defineProperties(ArrayPrototype, { splice: function splice(start, deleteCount) { if (arguments.length === 0) { return []; } var args = arguments; this.length = max(ES.ToInteger(this.length), 0); if (arguments.length > 0 && typeof deleteCount !== 'number') { args = arraySlice(arguments); if (args.length < 2) { pushCall(args, this.length - start); } else { args[1] = ES.ToInteger(deleteCount); } } return array_splice.apply(this, args); } }, !spliceWorksWithEmptyObject || !hasES6Defaults); var spliceWorksWithLargeSparseArrays = (function () { // Per https://github.com/es-shims/es5-shim/issues/295 // Safari 7/8 breaks with sparse arrays of size 1e5 or greater var arr = new $Array(1e5); // note: the index MUST be 8 or larger or the test will false pass arr[8] = 'x'; arr.splice(1, 1); // note: this test must be defined *after* the indexOf shim // per https://github.com/es-shims/es5-shim/issues/313 return arr.indexOf('x') === 7; }()); var spliceWorksWithSmallSparseArrays = (function () { // Per https://github.com/es-shims/es5-shim/issues/295 // Opera 12.15 breaks on this, no idea why. var n = 256; var arr = []; arr[n] = 'a'; arr.splice(n + 1, 0, 'b'); return arr[n] === 'a'; }()); defineProperties(ArrayPrototype, { splice: function splice(start, deleteCount) { var O = ES.ToObject(this); var A = []; var len = ES.ToUint32(O.length); var relativeStart = ES.ToInteger(start); var actualStart = relativeStart < 0 ? max((len + relativeStart), 0) : min(relativeStart, len); var actualDeleteCount = arguments.length === 0 ? 0 : arguments.length === 1 ? len - actualStart : min(max(ES.ToInteger(deleteCount), 0), len - actualStart); var k = 0; var from; while (k < actualDeleteCount) { from = $String(actualStart + k); if (owns(O, from)) { A[k] = O[from]; } k += 1; } var items = arraySlice(arguments, 2); var itemCount = items.length; var to; if (itemCount < actualDeleteCount) { k = actualStart; var maxK = len - actualDeleteCount; while (k < maxK) { from = $String(k + actualDeleteCount); to = $String(k + itemCount); if (owns(O, from)) { O[to] = O[from]; } else { delete O[to]; } k += 1; } k = len; var minK = len - actualDeleteCount + itemCount; while (k > minK) { delete O[k - 1]; k -= 1; } } else if (itemCount > actualDeleteCount) { k = len - actualDeleteCount; while (k > actualStart) { from = $String(k + actualDeleteCount - 1); to = $String(k + itemCount - 1); if (owns(O, from)) { O[to] = O[from]; } else { delete O[to]; } k -= 1; } } k = actualStart; for (var i = 0; i < items.length; ++i) { O[k] = items[i]; k += 1; } O.length = len - actualDeleteCount + itemCount; return A; } }, !spliceWorksWithLargeSparseArrays || !spliceWorksWithSmallSparseArrays); var originalJoin = ArrayPrototype.join; var hasStringJoinBug; try { hasStringJoinBug = Array.prototype.join.call('123', ',') !== '1,2,3'; } catch (e) { hasStringJoinBug = true; } if (hasStringJoinBug) { defineProperties(ArrayPrototype, { join: function join(separator) { var sep = typeof separator === 'undefined' ? ',' : separator; return originalJoin.call(isString(this) ? strSplit(this, '') : this, sep); } }, hasStringJoinBug); } var hasJoinUndefinedBug = [1, 2].join(undefined) !== '1,2'; if (hasJoinUndefinedBug) { defineProperties(ArrayPrototype, { join: function join(separator) { var sep = typeof separator === 'undefined' ? ',' : separator; return originalJoin.call(this, sep); } }, hasJoinUndefinedBug); } var pushShim = function push(item) { var O = ES.ToObject(this); var n = ES.ToUint32(O.length); var i = 0; while (i < arguments.length) { O[n + i] = arguments[i]; i += 1; } O.length = n + i; return n + i; }; var pushIsNotGeneric = (function () { var obj = {}; var result = Array.prototype.push.call(obj, undefined); return result !== 1 || obj.length !== 1 || typeof obj[0] !== 'undefined' || !owns(obj, 0); }()); defineProperties(ArrayPrototype, { push: function push(item) { if (isArray(this)) { return array_push.apply(this, arguments); } return pushShim.apply(this, arguments); } }, pushIsNotGeneric); // This fixes a very weird bug in Opera 10.6 when pushing `undefined var pushUndefinedIsWeird = (function () { var arr = []; var result = arr.push(undefined); return result !== 1 || arr.length !== 1 || typeof arr[0] !== 'undefined' || !owns(arr, 0); }()); defineProperties(ArrayPrototype, { push: pushShim }, pushUndefinedIsWeird); // ES5 15.2.3.14 // https://es5.github.io/#x15.4.4.10 // Fix boxed string bug defineProperties(ArrayPrototype, { slice: function (start, end) { var arr = isString(this) ? strSplit(this, '') : this; return arraySliceApply(arr, arguments); } }, splitString); var sortIgnoresNonFunctions = (function () { try { [1, 2].sort(null); } catch (e) { try { [1, 2].sort({}); } catch (e2) { return false; } } return true; }()); var sortThrowsOnRegex = (function () { // this is a problem in Firefox 4, in which `typeof /a/ === 'function'` try { [1, 2].sort(/a/); return false; } catch (e) {} return true; }()); var sortIgnoresUndefined = (function () { // applies in IE 8, for one. try { [1, 2].sort(undefined); return true; } catch (e) {} return false; }()); defineProperties(ArrayPrototype, { sort: function sort(compareFn) { if (typeof compareFn === 'undefined') { return arraySort(this); } if (!isCallable(compareFn)) { throw new TypeError('Array.prototype.sort callback must be a function'); } return arraySort(this, compareFn); } }, sortIgnoresNonFunctions || !sortIgnoresUndefined || !sortThrowsOnRegex); // // Object // ====== // // ES5 15.2.3.14 // https://es5.github.io/#x15.2.3.14 // https://web.archive.org/web/20140727042234/http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation // eslint-disable-next-line quote-props var hasDontEnumBug = !isEnum({ 'toString': null }, 'toString'); // jscs:ignore disallowQuotedKeysInObjects var hasProtoEnumBug = isEnum(function () {}, 'prototype'); var hasStringEnumBug = !owns('x', '0'); var equalsConstructorPrototype = function (o) { var ctor = o.constructor; return ctor && ctor.prototype === o; }; var excludedKeys = { $applicationCache: true, $console: true, $external: true, $frame: true, $frameElement: true, $frames: true, $innerHeight: true, $innerWidth: true, $onmozfullscreenchange: true, $onmozfullscreenerror: true, $outerHeight: true, $outerWidth: true, $pageXOffset: true, $pageYOffset: true, $parent: true, $scrollLeft: true, $scrollTop: true, $scrollX: true, $scrollY: true, $self: true, $webkitIndexedDB: true, $webkitStorageInfo: true, $window: true, $width: true, $height: true, $top: true, $localStorage: true }; var hasAutomationEqualityBug = (function () { /* globals window */ if (typeof window === 'undefined') { return false; } for (var k in window) { try { if (!excludedKeys['$' + k] && owns(window, k) && window[k] !== null && typeof window[k] === 'object') { equalsConstructorPrototype(window[k]); } } catch (e) { return true; } } return false; }()); var equalsConstructorPrototypeIfNotBuggy = function (object) { if (typeof window === 'undefined' || !hasAutomationEqualityBug) { return equalsConstructorPrototype(object); } try { return equalsConstructorPrototype(object); } catch (e) { return false; } }; var dontEnums = [ 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ]; var dontEnumsLength = dontEnums.length; // taken directly from https://github.com/ljharb/is-arguments/blob/master/index.js // can be replaced with require('is-arguments') if we ever use a build process instead var isStandardArguments = function isArguments(value) { return toStr(value) === '[object Arguments]'; }; var isLegacyArguments = function isArguments(value) { return value !== null && typeof value === 'object' && typeof value.length === 'number' && value.length >= 0 && !isArray(value) && isCallable(value.callee); }; var isArguments = isStandardArguments(arguments) ? isStandardArguments : isLegacyArguments; defineProperties($Object, { keys: function keys(object) { var isFn = isCallable(object); var isArgs = isArguments(object); var isObject = object !== null && typeof object === 'object'; var isStr = isObject && isString(object); if (!isObject && !isFn && !isArgs) { throw new TypeError('Object.keys called on a non-object'); } var theKeys = []; var skipProto = hasProtoEnumBug && isFn; if ((isStr && hasStringEnumBug) || isArgs) { for (var i = 0; i < object.length; ++i) { pushCall(theKeys, $String(i)); } } if (!isArgs) { for (var name in object) { if (!(skipProto && name === 'prototype') && owns(object, name)) { pushCall(theKeys, $String(name)); } } } if (hasDontEnumBug) { var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); for (var j = 0; j < dontEnumsLength; j++) { var dontEnum = dontEnums[j]; if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) { pushCall(theKeys, dontEnum); } } } return theKeys; } }); var keysWorksWithArguments = $Object.keys && (function () { // Safari 5.0 bug return $Object.keys(arguments).length === 2; }(1, 2)); var keysHasArgumentsLengthBug = $Object.keys && (function () { var argKeys = $Object.keys(arguments); return arguments.length !== 1 || argKeys.length !== 1 || argKeys[0] !== 1; }(1)); var originalKeys = $Object.keys; defineProperties($Object, { keys: function keys(object) { if (isArguments(object)) { return originalKeys(arraySlice(object)); } return originalKeys(object); } }, !keysWorksWithArguments || keysHasArgumentsLengthBug); // // Date // ==== // var hasNegativeMonthYearBug = new Date(-3509827329600292).getUTCMonth() !== 0; var aNegativeTestDate = new Date(-1509842289600292); var aPositiveTestDate = new Date(1449662400000); var hasToUTCStringFormatBug = aNegativeTestDate.toUTCString() !== 'Mon, 01 Jan -45875 11:59:59 GMT'; var hasToDateStringFormatBug; var hasToStringFormatBug; var timeZoneOffset = aNegativeTestDate.getTimezoneOffset(); if (timeZoneOffset < -720) { hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Tue Jan 02 -45875'; hasToStringFormatBug = !(/^Thu Dec 10 2015 \d\d:\d\d:\d\d GMT[-+]\d\d\d\d(?: |$)/).test(String(aPositiveTestDate)); } else { hasToDateStringFormatBug = aNegativeTestDate.toDateString() !== 'Mon Jan 01 -45875'; hasToStringFormatBug = !(/^Wed Dec 09 2015 \d\d:\d\d:\d\d GMT[-+]\d\d\d\d(?: |$)/).test(String(aPositiveTestDate)); } var originalGetFullYear = call.bind(Date.prototype.getFullYear); var originalGetMonth = call.bind(Date.prototype.getMonth); var originalGetDate = call.bind(Date.prototype.getDate); var originalGetUTCFullYear = call.bind(Date.prototype.getUTCFullYear); var originalGetUTCMonth = call.bind(Date.prototype.getUTCMonth); var originalGetUTCDate = call.bind(Date.prototype.getUTCDate); var originalGetUTCDay = call.bind(Date.prototype.getUTCDay); var originalGetUTCHours = call.bind(Date.prototype.getUTCHours); var originalGetUTCMinutes = call.bind(Date.prototype.getUTCMinutes); var originalGetUTCSeconds = call.bind(Date.prototype.getUTCSeconds); var originalGetUTCMilliseconds = call.bind(Date.prototype.getUTCMilliseconds); var dayName = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; var monthName = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; var daysInMonth = function daysInMonth(month, year) { return originalGetDate(new Date(year, month, 0)); }; defineProperties(Date.prototype, { getFullYear: function getFullYear() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetFullYear(this); if (year < 0 && originalGetMonth(this) > 11) { return year + 1; } return year; }, getMonth: function getMonth() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetFullYear(this); var month = originalGetMonth(this); if (year < 0 && month > 11) { return 0; } return month; }, getDate: function getDate() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetFullYear(this); var month = originalGetMonth(this); var date = originalGetDate(this); if (year < 0 && month > 11) { if (month === 12) { return date; } var days = daysInMonth(0, year + 1); return (days - date) + 1; } return date; }, getUTCFullYear: function getUTCFullYear() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetUTCFullYear(this); if (year < 0 && originalGetUTCMonth(this) > 11) { return year + 1; } return year; }, getUTCMonth: function getUTCMonth() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetUTCFullYear(this); var month = originalGetUTCMonth(this); if (year < 0 && month > 11) { return 0; } return month; }, getUTCDate: function getUTCDate() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var year = originalGetUTCFullYear(this); var month = originalGetUTCMonth(this); var date = originalGetUTCDate(this); if (year < 0 && month > 11) { if (month === 12) { return date; } var days = daysInMonth(0, year + 1); return (days - date) + 1; } return date; } }, hasNegativeMonthYearBug); defineProperties(Date.prototype, { toUTCString: function toUTCString() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var day = originalGetUTCDay(this); var date = originalGetUTCDate(this); var month = originalGetUTCMonth(this); var year = originalGetUTCFullYear(this); var hour = originalGetUTCHours(this); var minute = originalGetUTCMinutes(this); var second = originalGetUTCSeconds(this); return dayName[day] + ', ' + (date < 10 ? '0' + date : date) + ' ' + monthName[month] + ' ' + year + ' ' + (hour < 10 ? '0' + hour : hour) + ':' + (minute < 10 ? '0' + minute : minute) + ':' + (second < 10 ? '0' + second : second) + ' GMT'; } }, hasNegativeMonthYearBug || hasToUTCStringFormatBug); // Opera 12 has `,` defineProperties(Date.prototype, { toDateString: function toDateString() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var day = this.getDay(); var date = this.getDate(); var month = this.getMonth(); var year = this.getFullYear(); return dayName[day] + ' ' + monthName[month] + ' ' + (date < 10 ? '0' + date : date) + ' ' + year; } }, hasNegativeMonthYearBug || hasToDateStringFormatBug); // can't use defineProperties here because of toString enumeration issue in IE <= 8 if (hasNegativeMonthYearBug || hasToStringFormatBug) { Date.prototype.toString = function toString() { if (!this || !(this instanceof Date)) { throw new TypeError('this is not a Date object.'); } var day = this.getDay(); var date = this.getDate(); var month = this.getMonth(); var year = this.getFullYear(); var hour = this.getHours(); var minute = this.getMinutes(); var second = this.getSeconds(); var timezoneOffset = this.getTimezoneOffset(); var hoursOffset = floor(abs(timezoneOffset) / 60); var minutesOffset = floor(abs(timezoneOffset) % 60); return dayName[day] + ' ' + monthName[month] + ' ' + (date < 10 ? '0' + date : date) + ' ' + year + ' ' + (hour < 10 ? '0' + hour : hour) + ':' + (minute < 10 ? '0' + minute : minute) + ':' + (second < 10 ? '0' + second : second) + ' GMT' + (timezoneOffset > 0 ? '-' : '+') + (hoursOffset < 10 ? '0' + hoursOffset : hoursOffset) + (minutesOffset < 10 ? '0' + minutesOffset : minutesOffset); }; if (supportsDescriptors) { $Object.defineProperty(Date.prototype, 'toString', { configurable: true, enumerable: false, writable: true }); } } // ES5 15.9.5.43 // https://es5.github.io/#x15.9.5.43 // This function returns a String value represent the instance in time // represented by this Date object. The format of the String is the Date Time // string format defined in 15.9.1.15. All fields are present in the String. // The time zone is always UTC, denoted by the suffix Z. If the time value of // this object is not a finite Number a RangeError exception is thrown. var negativeDate = -62198755200000; var negativeYearString = '-000001'; var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1; // eslint-disable-line max-len var hasSafari51DateBug = Date.prototype.toISOString && new Date(-1).toISOString() !== '1969-12-31T23:59:59.999Z'; var getTime = call.bind(Date.prototype.getTime); defineProperties(Date.prototype, { toISOString: function toISOString() { if (!isFinite(this) || !isFinite(getTime(this))) { // Adope Photoshop requires the second check. throw new RangeError('Date.prototype.toISOString called on non-finite value.'); } var year = originalGetUTCFullYear(this); var month = originalGetUTCMonth(this); // see https://github.com/es-shims/es5-shim/issues/111 year += floor(month / 12); month = ((month % 12) + 12) % 12; // the date time string format is specified in 15.9.1.15. var result = [ month + 1, originalGetUTCDate(this), originalGetUTCHours(this), originalGetUTCMinutes(this), originalGetUTCSeconds(this) ]; year = ( (year < 0 ? '-' : (year > 9999 ? '+' : '')) + strSlice('00000' + abs(year), (0 <= year && year <= 9999) ? -4 : -6) ); for (var i = 0; i < result.length; ++i) { // pad months, days, hours, minutes, and seconds to have two digits. result[i] = strSlice('00' + result[i], -2); } // pad milliseconds to have three digits. return ( year + '-' + arraySlice(result, 0, 2).join('-') + 'T' + arraySlice(result, 2).join(':') + '.' + strSlice('000' + originalGetUTCMilliseconds(this), -3) + 'Z' ); } }, hasNegativeDateBug || hasSafari51DateBug); // ES5 15.9.5.44 // https://es5.github.io/#x15.9.5.44 // This function provides a String representation of a Date object for use by // JSON.stringify (15.12.3). var dateToJSONIsSupported = (function () { try { return Date.prototype.toJSON && new Date(NaN).toJSON() === null && new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 && Date.prototype.toJSON.call({ // generic toISOString: function () { return true; } }); } catch (e) { return false; } }()); if (!dateToJSONIsSupported) { Date.prototype.toJSON = function toJSON(key) { // When the toJSON method is called with argument key, the following // steps are taken: // 1. Let O be the result of calling ToObject, giving it the this // value as its argument. // 2. Let tv be ES.ToPrimitive(O, hint Number). var O = $Object(this); var tv = ES.ToPrimitive(O); // 3. If tv is a Number and is not finite, return null. if (typeof tv === 'number' && !isFinite(tv)) { return null; } // 4. Let toISO be the result of calling the [[Get]] internal method of // O with argument "toISOString". var toISO = O.toISOString; // 5. If IsCallable(toISO) is false, throw a TypeError exception. if (!isCallable(toISO)) { throw new TypeError('toISOString property is not callable'); } // 6. Return the result of calling the [[Call]] internal method of // toISO with O as the this value and an empty argument list. return toISO.call(O); // NOTE 1 The argument is ignored. // NOTE 2 The toJSON function is intentionally generic; it does not // require that its this value be a Date object. Therefore, it can be // transferred to other kinds of objects for use as a method. However, // it does require that any such object have a toISOString method. An // object is free to use the argument key to filter its // stringification. }; } // ES5 15.9.4.2 // https://es5.github.io/#x15.9.4.2 // based on work shared by Daniel Friesen (dantman) // https://gist.github.com/303249 var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15; var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')) || !isNaN(Date.parse('2012-12-31T23:59:60.000Z')); var doesNotParseY2KNewYear = isNaN(Date.parse('2000-01-01T00:00:00.000Z')); if (doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) { // XXX global assignment won't work in embeddings that use // an alternate object for the context. var maxSafeUnsigned32Bit = pow(2, 31) - 1; var hasSafariSignedIntBug = isActualNaN(new Date(1970, 0, 1, 0, 0, 0, maxSafeUnsigned32Bit + 1).getTime()); // eslint-disable-next-line no-implicit-globals, no-global-assign Date = (function (NativeDate) { // Date.length === 7 var DateShim = function Date(Y, M, D, h, m, s, ms) { var length = arguments.length; var date; if (this instanceof NativeDate) { var seconds = s; var millis = ms; if (hasSafariSignedIntBug && length >= 7 && ms > maxSafeUnsigned32Bit) { // work around a Safari 8/9 bug where it treats the seconds as signed var msToShift = floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit; var sToShift = floor(msToShift / 1e3); seconds += sToShift; millis -= sToShift * 1e3; } var parsed = DateShim.parse(Y); var hasNegTimestampParseBug = isNaN(parsed); date = length === 1 && $String(Y) === Y && !hasNegTimestampParseBug // isString(Y) // We explicitly pass it through parse: ? new NativeDate(parsed) // We have to manually make calls depending on argument // length here : length >= 7 ? new NativeDate(Y, M, D, h, m, seconds, millis) : length >= 6 ? new NativeDate(Y, M, D, h, m, seconds) : length >= 5 ? new NativeDate(Y, M, D, h, m) : length >= 4 ? new NativeDate(Y, M, D, h) : length >= 3 ? new NativeDate(Y, M, D) : length >= 2 ? new NativeDate(Y, M) : length >= 1 ? new NativeDate(Y instanceof NativeDate ? +Y : Y) : new NativeDate(); } else { date = NativeDate.apply(this, arguments); } if (!isPrimitive(date)) { // Prevent mixups with unfixed Date object defineProperties(date, { constructor: DateShim }, true); } return date; }; // 15.9.1.15 Date Time String Format. var isoDateExpression = new RegExp('^' + '(\\d{4}|[+-]\\d{6})' // four-digit year capture or sign + 6-digit extended year + '(?:-(\\d{2})' // optional month capture + '(?:-(\\d{2})' // optional day capture + '(?:' // capture hours:minutes:seconds.milliseconds + 'T(\\d{2})' // hours capture + ':(\\d{2})' // minutes capture + '(?:' // optional :seconds.milliseconds + ':(\\d{2})' // seconds capture + '(?:(\\.\\d{1,}))?' // milliseconds capture + ')?' + '(' // capture UTC offset component + 'Z|' // UTC capture + '(?:' // offset specifier +/-hours:minutes + '([-+])' // sign capture + '(\\d{2})' // hours offset capture + ':(\\d{2})' // minutes offset capture + ')' + ')?)?)?)?' + '$'); var months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; var dayFromMonth = function dayFromMonth(year, month) { var t = month > 1 ? 1 : 0; return ( months[month] + floor((year - 1969 + t) / 4) - floor((year - 1901 + t) / 100) + floor((year - 1601 + t) / 400) + (365 * (year - 1970)) ); }; var toUTC = function toUTC(t) { var s = 0; var ms = t; if (hasSafariSignedIntBug && ms > maxSafeUnsigned32Bit) { // work around a Safari 8/9 bug where it treats the seconds as signed var msToShift = floor(ms / maxSafeUnsigned32Bit) * maxSafeUnsigned32Bit; var sToShift = floor(msToShift / 1e3); s += sToShift; ms -= sToShift * 1e3; } return $Number(new NativeDate(1970, 0, 1, 0, 0, s, ms)); }; // Copy any custom methods a 3rd party library may have added for (var key in NativeDate) { if (owns(NativeDate, key)) { DateShim[key] = NativeDate[key]; } } // Copy "native" methods explicitly; they may be non-enumerable defineProperties(DateShim, { now: NativeDate.now, UTC: NativeDate.UTC }, true); DateShim.prototype = NativeDate.prototype; defineProperties(DateShim.prototype, { constructor: DateShim }, true); // Upgrade Date.parse to handle simplified ISO 8601 strings var parseShim = function parse(string) { var match = isoDateExpression.exec(string); if (match) { // parse months, days, hours, minutes, seconds, and milliseconds // provide default values if necessary // parse the UTC offset component var year = $Number(match[1]), month = $Number(match[2] || 1) - 1, day = $Number(match[3] || 1) - 1, hour = $Number(match[4] || 0), minute = $Number(match[5] || 0), second = $Number(match[6] || 0), millisecond = floor($Number(match[7] || 0) * 1000), // When time zone is missed, local offset should be used // (ES 5.1 bug) // see https://bugs.ecmascript.org/show_bug.cgi?id=112 isLocalTime = Boolean(match[4] && !match[8]), signOffset = match[9] === '-' ? 1 : -1, hourOffset = $Number(match[10] || 0), minuteOffset = $Number(match[11] || 0), result; var hasMinutesOrSecondsOrMilliseconds = minute > 0 || second > 0 || millisecond > 0; if ( hour < (hasMinutesOrSecondsOrMilliseconds ? 24 : 25) && minute < 60 && second < 60 && millisecond < 1000 && month > -1 && month < 12 && hourOffset < 24 && minuteOffset < 60 // detect invalid offsets && day > -1 && day < (dayFromMonth(year, month + 1) - dayFromMonth(year, month)) ) { result = ( ((dayFromMonth(year, month) + day) * 24) + hour + (hourOffset * signOffset) ) * 60; result = (( ((result + minute + (minuteOffset * signOffset)) * 60) + second ) * 1000) + millisecond; if (isLocalTime) { result = toUTC(result); } if (-8.64e15 <= result && result <= 8.64e15) { return result; } } return NaN; } return NativeDate.parse.apply(this, arguments); }; defineProperties(DateShim, { parse: parseShim }); return DateShim; }(Date)); } // ES5 15.9.4.4 // https://es5.github.io/#x15.9.4.4 if (!Date.now) { Date.now = function now() { return new Date().getTime(); }; } // // Number // ====== // // ES5.1 15.7.4.5 // https://es5.github.io/#x15.7.4.5 var hasToFixedBugs = NumberPrototype.toFixed && ( (0.00008).toFixed(3) !== '0.000' || (0.9).toFixed(0) !== '1' || (1.255).toFixed(2) !== '1.25' || (1000000000000000128).toFixed(0) !== '1000000000000000128' ); var toFixedHelpers = { base: 1e7, size: 6, data: [0, 0, 0, 0, 0, 0], multiply: function multiply(n, c) { var i = -1; var c2 = c; while (++i < toFixedHelpers.size) { c2 += n * toFixedHelpers.data[i]; toFixedHelpers.data[i] = c2 % toFixedHelpers.base; c2 = floor(c2 / toFixedHelpers.base); } }, divide: function divide(n) { var i = toFixedHelpers.size; var c = 0; while (--i >= 0) { c += toFixedHelpers.data[i]; toFixedHelpers.data[i] = floor(c / n); c = (c % n) * toFixedHelpers.base; } }, numToString: function numToString() { var i = toFixedHelpers.size; var s = ''; while (--i >= 0) { if (s !== '' || i === 0 || toFixedHelpers.data[i] !== 0) { var t = $String(toFixedHelpers.data[i]); if (s === '') { s = t; } else { s += strSlice('0000000', 0, 7 - t.length) + t; } } } return s; }, pow: function pow(x, n, acc) { return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc))); }, log: function log(x) { var n = 0; var x2 = x; while (x2 >= 4096) { n += 12; x2 /= 4096; } while (x2 >= 2) { n += 1; x2 /= 2; } return n; } }; var toFixedShim = function toFixed(fractionDigits) { var f, x, s, m, e, z, j, k; // Test for NaN and round fractionDigits down f = $Number(fractionDigits); f = isActualNaN(f) ? 0 : floor(f); if (f < 0 || f > 20) { throw new RangeError('Number.toFixed called with invalid number of decimals'); } x = $Number(this); if (isActualNaN(x)) { return 'NaN'; } // If it is too big or small, return the string value of the number if (x <= -1e21 || x >= 1e21) { return $String(x); } s = ''; if (x < 0) { s = '-'; x = -x; } m = '0'; if (x > 1e-21) { // 1e-21 < x < 1e21 // -70 < log2(x) < 70 e = toFixedHelpers.log(x * toFixedHelpers.pow(2, 69, 1)) - 69; z = (e < 0 ? x * toFixedHelpers.pow(2, -e, 1) : x / toFixedHelpers.pow(2, e, 1)); z *= 0x10000000000000; // pow(2, 52); e = 52 - e; // -18 < e < 122 // x = z / 2 ^ e if (e > 0) { toFixedHelpers.multiply(0, z); j = f; while (j >= 7) { toFixedHelpers.multiply(1e7, 0); j -= 7; } toFixedHelpers.multiply(toFixedHelpers.pow(10, j, 1), 0); j = e - 1; while (j >= 23) { toFixedHelpers.divide(1 << 23); j -= 23; } toFixedHelpers.divide(1 << j); toFixedHelpers.multiply(1, 1); toFixedHelpers.divide(2); m = toFixedHelpers.numToString(); } else { toFixedHelpers.multiply(0, z); toFixedHelpers.multiply(1 << (-e), 0); m = toFixedHelpers.numToString() + strSlice('0.00000000000000000000', 2, 2 + f); } } if (f > 0) { k = m.length; if (k <= f) { m = s + strSlice('0.0000000000000000000', 0, f - k + 2) + m; } else { m = s + strSlice(m, 0, k - f) + '.' + strSlice(m, k - f); } } else { m = s + m; } return m; }; defineProperties(NumberPrototype, { toFixed: toFixedShim }, hasToFixedBugs); var hasToExponentialRoundingBug = (function () { try { return (-6.9e-11).toExponential(4) !== '-6.9000e-11'; } catch (e) { return false; } }()); var toExponentialAllowsInfiniteDigits = (function () { try { (1).toExponential(Infinity); (1).toExponential(-Infinity); return true; } catch (e) { return false; } }()); var originalToExponential = call.bind(NumberPrototype.toExponential); var numberToString = call.bind(NumberPrototype.toString); var numberValueOf = call.bind(NumberPrototype.valueOf); defineProperties(NumberPrototype, { toExponential: function toExponential(fractionDigits) { // 1: Let x be this Number value. var x = numberValueOf(this); if (typeof fractionDigits === 'undefined') { return originalToExponential(x); } var f = ES.ToInteger(fractionDigits); if (isActualNaN(x)) { return 'NaN'; } if (f < 0 || f > 20) { if (!isFinite(f)) { // IE 6 doesn't throw in the native one throw new RangeError('toExponential() argument must be between 0 and 20'); } // this will probably have thrown already return originalToExponential(x, f); } // only cases left are a finite receiver + in-range fractionDigits // implementation adapted from https://gist.github.com/SheetJSDev/1100ad56b9f856c95299ed0e068eea08 // 4: Let s be the empty string var s = ''; // 5: If x < 0 if (x < 0) { s = '-'; x = -x; } // 6: If x = +Infinity if (x === Infinity) { return s + 'Infinity'; } // 7: If fractionDigits is not undefined and (f < 0 or f > 20), throw a RangeError exception. if (typeof fractionDigits !== 'undefined' && (f < 0 || f > 20)) { throw new RangeError('Fraction digits ' + fractionDigits + ' out of range'); } var m = ''; var e = 0; var c = ''; var d = ''; // 8: If x = 0 then if (x === 0) { e = 0; f = 0; m = '0'; } else { // 9: Else, x != 0 var L = log10(x); e = floor(L); // 10 ** e <= x and x < 10 ** (e+1) var n = 0; if (typeof fractionDigits !== 'undefined') { // eslint-disable-line no-negated-condition var w = pow(10, e - f); // x / 10 ** (f+1) < w and w <= x / 10 ** f n = round(x / w); // 10 ** f <= n and n < 10 ** (f+1) if (2 * x >= (((2 * n) + 1) * w)) { n += 1; // pick larger value } if (n >= pow(10, f + 1)) { // 10e-1 = 1e0 n /= 10; e += 1; } } else { f = 16; // start from Math.ceil(Math.log10(Number.MAX_SAFE_INTEGER)) and loop down var guess_n = round(pow(10, L - e + f)); var target_f = f; while (f-- > 0) { guess_n = round(pow(10, L - e + f)); if ( abs((guess_n * pow(10, e - f)) - x) <= abs((n * pow(10, e - target_f)) - x) ) { target_f = f; n = guess_n; } } } m = numberToString(n, 10); if (typeof fractionDigits === 'undefined') { while (strSlice(m, -1) === '0') { m = strSlice(m, 0, -1); d += 1; } } } // 10: If f != 0, then if (f !== 0) { m = strSlice(m, 0, 1) + '.' + strSlice(m, 1); } // 11: If e = 0, then if (e === 0) { c = '+'; d = '0'; } else { // 12: Else c = e > 0 ? '+' : '-'; d = numberToString(abs(e), 10); } // 13: Let m be the concatenation of the four Strings m, "e", c, and d. m += 'e' + c + d; // 14: Return the concatenation of the Strings s and m. return s + m; } }, hasToExponentialRoundingBug || toExponentialAllowsInfiniteDigits); var hasToPrecisionUndefinedBug = (function () { try { return 1.0.toPrecision(undefined) === '1'; } catch (e) { return true; } }()); var originalToPrecision = call.bind(NumberPrototype.toPrecision); defineProperties(NumberPrototype, { toPrecision: function toPrecision(precision) { return typeof precision === 'undefined' ? originalToPrecision(this) : originalToPrecision(this, precision); } }, hasToPrecisionUndefinedBug); // // String // ====== // // ES5 15.5.4.14 // https://es5.github.io/#x15.5.4.14 // [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers] // Many browsers do not split properly with regular expressions or they // do not perform the split correctly under obscure conditions. // See https://blog.stevenlevithan.com/archives/cross-browser-split // I've tested in many browsers and this seems to cover the deviant ones: // 'ab'.split(/(?:ab)*/) should be ["", ""], not [""] // '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""] // 'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not // [undefined, "t", undefined, "e", ...] // ''.split(/.?/) should be [], not [""] // '.'.split(/()()/) should be ["."], not ["", "", "."] if ( 'ab'.split(/(?:ab)*/).length !== 2 || '.'.split(/(.?)(.?)/).length !== 4 || 'tesst'.split(/(s)*/)[1] === 't' || 'test'.split(/(?:)/, -1).length !== 4 || ''.split(/.?/).length || '.'.split(/()()/).length > 1 ) { (function () { var compliantExecNpcg = typeof (/()??/).exec('')[1] === 'undefined'; // NPCG: nonparticipating capturing group var maxSafe32BitInt = pow(2, 32) - 1; StringPrototype.split = function split(separator, limit) { var string = String(this); if (typeof separator === 'undefined' && limit === 0) { return []; } // If `separator` is not a regex, use native split if (!isRegex(separator)) { return strSplit(this, separator, limit); } var output = []; var flags = (separator.ignoreCase ? 'i' : '') + (separator.multiline ? 'm' : '') + (separator.unicode ? 'u' : '') // in ES6 + (separator.sticky ? 'y' : ''), // Firefox 3+ and ES6 lastLastIndex = 0, // Make `global` and avoid `lastIndex` issues by working with a copy separator2, match, lastIndex, lastLength; var separatorCopy = new RegExp(separator.source, flags + 'g'); if (!compliantExecNpcg) { // Doesn't need flags gy, but they don't hurt separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags); } /* Values for `limit`, per the spec: * If undefined: 4294967295 // maxSafe32BitInt * If 0, Infinity, or NaN: 0 * If positive number: limit = floor(limit); if (limit > 4294967295) limit -= 4294967296; * If negative number: 4294967296 - floor(abs(limit)) * If other: Type-convert, then use the above rules */ var splitLimit = typeof limit === 'undefined' ? maxSafe32BitInt : ES.ToUint32(limit); match = separatorCopy.exec(string); while (match) { // `separatorCopy.lastIndex` is not reliable cross-browser lastIndex = match.index + match[0].length; if (lastIndex > lastLastIndex) { pushCall(output, strSlice(string, lastLastIndex, match.index)); // Fix browsers whose `exec` methods don't consistently return `undefined` for // nonparticipating capturing groups if (!compliantExecNpcg && match.length > 1) { /* eslint-disable no-loop-func */ match[0].replace(separator2, function () { for (var i = 1; i < arguments.length - 2; i++) { if (typeof arguments[i] === 'undefined') { match[i] = void 0; } } }); /* eslint-enable no-loop-func */ } if (match.length > 1 && match.index < string.length) { array_push.apply(output, arraySlice(match, 1)); } lastLength = match[0].length; lastLastIndex = lastIndex; if (output.length >= splitLimit) { break; } } if (separatorCopy.lastIndex === match.index) { separatorCopy.lastIndex++; // Avoid an infinite loop } match = separatorCopy.exec(string); } if (lastLastIndex === string.length) { if (lastLength || !separatorCopy.test('')) { pushCall(output, ''); } } else { pushCall(output, strSlice(string, lastLastIndex)); } return output.length > splitLimit ? arraySlice(output, 0, splitLimit) : output; }; }()); // [bugfix, chrome] // If separator is undefined, then the result array contains just one String, // which is the this value (converted to a String). If limit is not undefined, // then the output array is truncated so that it contains no more than limit // elements. // "0".split(undefined, 0) -> [] } else if ('0'.split(void 0, 0).length) { StringPrototype.split = function split(separator, limit) { if (typeof separator === 'undefined' && limit === 0) { return []; } return strSplit(this, separator, limit); }; } var str_replace = StringPrototype.replace; var replaceReportsGroupsCorrectly = (function () { var groups = []; 'x'.replace(/x(.)?/g, function (match, group) { pushCall(groups, group); }); return groups.length === 1 && typeof groups[0] === 'undefined'; }()); if (!replaceReportsGroupsCorrectly) { StringPrototype.replace = function replace(searchValue, replaceValue) { var isFn = isCallable(replaceValue); var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source); if (!isFn || !hasCapturingGroups) { return str_replace.call(this, searchValue, replaceValue); } var wrappedReplaceValue = function (match) { var length = arguments.length; var originalLastIndex = searchValue.lastIndex; searchValue.lastIndex = 0; // eslint-disable-line no-param-reassign var args = searchValue.exec(match) || []; searchValue.lastIndex = originalLastIndex; // eslint-disable-line no-param-reassign pushCall(args, arguments[length - 2], arguments[length - 1]); return replaceValue.apply(this, args); }; return str_replace.call(this, searchValue, wrappedReplaceValue); }; } // ECMA-262, 3rd B.2.3 // Not an ECMAScript standard, although ECMAScript 3rd Edition has a // non-normative section suggesting uniform semantics and it should be // normalized across all browsers // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE var hasNegativeSubstrBug = ''.substr && '0b'.substr(-1) !== 'b'; var string_substr = hasNegativeSubstrBug && call.bind(StringPrototype.substr); defineProperties(StringPrototype, { substr: function substr(start, length) { var normalizedStart = start; if (start < 0) { normalizedStart = max(this.length + start, 0); } return string_substr(this, normalizedStart, length); } }, hasNegativeSubstrBug); // ES5 15.5.4.20 // whitespace from: https://es5.github.io/#x15.5.4.20 var mvs = '\u180E'; var mvsIsWS = (/\s/).test(mvs); var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF' .replace(/\S/g, ''); // remove the mongolian vowel separator (\u180E) in modern engines var zeroWidth = '\u200b'; var wsRegexChars = '[' + ws + ']'; var trimBeginRegexp = new RegExp('^' + wsRegexChars + wsRegexChars + '*'); var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + '*$'); var hasTrimWhitespaceBug = StringPrototype.trim && ( ws.trim() !== '' // if ws is not considered whitespace || zeroWidth.trim() === '' // if zero-width IS considered whitespace || mvs.trim() !== (mvsIsWS ? '' : mvs) // if MVS is either wrongly considered whitespace, or, wrongly considered NOT whitespace ); defineProperties(StringPrototype, { // https://blog.stevenlevithan.com/archives/faster-trim-javascript // http://perfectionkills.com/whitespace-deviations/ trim: function trim() { 'use strict'; if (typeof this === 'undefined' || this === null) { throw new TypeError("can't convert " + this + ' to object'); } return $String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, ''); } }, hasTrimWhitespaceBug); var trim = call.bind(String.prototype.trim); var hasLastIndexBug = StringPrototype.lastIndexOf && 'abcあい'.lastIndexOf('あい', 2) !== -1; defineProperties(StringPrototype, { lastIndexOf: function lastIndexOf(searchString) { if (typeof this === 'undefined' || this === null) { throw new TypeError("can't convert " + this + ' to object'); } var S = $String(this); var searchStr = $String(searchString); var numPos = arguments.length > 1 ? $Number(arguments[1]) : NaN; var pos = isActualNaN(numPos) ? Infinity : ES.ToInteger(numPos); var start = min(max(pos, 0), S.length); var searchLen = searchStr.length; var k = start + searchLen; while (k > 0) { k = max(0, k - searchLen); var index = strIndexOf(strSlice(S, k, start + searchLen), searchStr); if (index !== -1) { return k + index; } } return -1; } }, hasLastIndexBug); var originalLastIndexOf = StringPrototype.lastIndexOf; defineProperties(StringPrototype, { lastIndexOf: function lastIndexOf(searchString) { return originalLastIndexOf.apply(this, arguments); } }, StringPrototype.lastIndexOf.length !== 1); var hexRegex = /^[-+]?0[xX]/; // ES-5 15.1.2.2 if ( parseInt(ws + '08') !== 8 // eslint-disable-line radix || parseInt(ws + '0x16') !== 22 // eslint-disable-line radix || (mvsIsWS ? parseInt(mvs + 1) !== 1 : !isNaN(parseInt(mvs + 1))) // eslint-disable-line radix ) { // eslint-disable-next-line no-global-assign, no-implicit-globals parseInt = (function (origParseInt) { return function parseInt(str, radix) { if (this instanceof parseInt) { new origParseInt(); } // eslint-disable-line new-cap, no-new, max-statements-per-line var string = trim(String(str)); var defaultedRadix = $Number(radix) || (hexRegex.test(string) ? 16 : 10); return origParseInt(string, defaultedRadix); }; }(parseInt)); } // Edge 15-18 var parseIntFailsToThrowOnBoxedSymbols = (function () { if (typeof Symbol !== 'function') { return false; } try { // eslint-disable-next-line radix parseInt(Object(Symbol.iterator)); return true; } catch (e) { /**/ } try { // eslint-disable-next-line radix parseInt(Symbol.iterator); return true; } catch (e) { /**/ } return false; }()); if (parseIntFailsToThrowOnBoxedSymbols) { var symbolValueOf = Symbol.prototype.valueOf; // eslint-disable-next-line no-global-assign, no-implicit-globals parseInt = (function (origParseInt) { return function parseInt(str, radix) { if (this instanceof parseInt) { new origParseInt(); } // eslint-disable-line new-cap, no-new, max-statements-per-line var isSym = typeof str === 'symbol'; if (!isSym && str && typeof str === 'object') { try { symbolValueOf.call(str); isSym = true; } catch (e) { /**/ } } if (isSym) { // handle Symbols in node 8.3/8.4 // eslint-disable-next-line no-implicit-coercion, no-unused-expressions '' + str; // jscs:ignore disallowImplicitTypeConversion } var string = trim(String(str)); var defaultedRadix = $Number(radix) || (hexRegex.test(string) ? 16 : 10); return origParseInt(string, defaultedRadix); }; }(parseInt)); } // https://es5.github.io/#x15.1.2.3 if (1 / parseFloat('-0') !== -Infinity) { // eslint-disable-next-line no-global-assign, no-implicit-globals, no-native-reassign parseFloat = (function (origParseFloat) { return function parseFloat(string) { var inputString = trim(String(string)); var result = origParseFloat(inputString); return result === 0 && strSlice(inputString, 0, 1) === '-' ? -0 : result; }; }(parseFloat)); } if (String(new RangeError('test')) !== 'RangeError: test') { var errorToStringShim = function toString() { if (typeof this === 'undefined' || this === null) { throw new TypeError("can't convert " + this + ' to object'); } var name = this.name; if (typeof name === 'undefined') { name = 'Error'; } else if (typeof name !== 'string') { name = $String(name); } var msg = this.message; if (typeof msg === 'undefined') { msg = ''; } else if (typeof msg !== 'string') { msg = $String(msg); } if (!name) { return msg; } if (!msg) { return name; } return name + ': ' + msg; }; // can't use defineProperties here because of toString enumeration issue in IE <= 8 Error.prototype.toString = errorToStringShim; } if (supportsDescriptors) { var ensureNonEnumerable = function (obj, prop) { if (isEnum(obj, prop)) { var desc = Object.getOwnPropertyDescriptor(obj, prop); if (desc.configurable) { desc.enumerable = false; Object.defineProperty(obj, prop, desc); } } }; ensureNonEnumerable(Error.prototype, 'message'); if (Error.prototype.message !== '') { Error.prototype.message = ''; } ensureNonEnumerable(Error.prototype, 'name'); } if (String(/a/mig) !== '/a/gim') { var regexToString = function toString() { var str = '/' + this.source + '/'; if (this.global) { str += 'g'; } if (this.ignoreCase) { str += 'i'; } if (this.multiline) { str += 'm'; } return str; }; // can't use defineProperties here because of toString enumeration issue in IE <= 8 RegExp.prototype.toString = regexToString; } })); ================================================ FILE: package.json ================================================ { "name": "es5-shim", "version": "4.6.7", "description": "ECMAScript 5 compatibility shims for legacy JavaScript engines", "homepage": "https://github.com/es-shims/es5-shim/", "contributors": [ "Kris Kowal (https://github.com/kriskowal/)", "Sami Samhuri (https://samhuri.net/)", "Florian Schäfer (https://github.com/fschaefer)", "Irakli Gozalishvili (https://gozala.io)", "Kit Cambridge (https://github.com/kitcambridge)", "Jordan Harband (https://github.com/ljharb/)" ], "bugs": { "mail": "ljharb@gmail.com", "url": "https://github.com/es-shims/es5-shim/issues" }, "license": "MIT", "main": "es5-shim.js", "repository": { "type": "git", "url": "https://github.com/es-shims/es5-shim.git" }, "scripts": { "prepack": "npmignore --auto --commentLines=autogenerated", "prepublish": "not-in-publish || npm run prepublishOnly", "prepublishOnly": "safe-publish-latest && npm run minify", "minify": "npm run --silent minify-shim && npm run --silent minify-sham", "minify-shim": "uglifyjs es5-shim.js --support-ie8 --keep-fnames --comments --source-map=es5-shim.map -m -b ascii_only=true,beautify=false | sed 's/0xde0b6b3a7640080/1000000000000000128/' > es5-shim.min.js", "minify-sham": "uglifyjs es5-sham.js --support-ie8 --keep-fnames --comments --source-map=es5-sham.map -m -b ascii_only=true,beautify=false > es5-sham.min.js", "pretest": "npm run --silent lint", "test": "npm run tests-only", "posttest": "aud --production", "tests-only": "nyc jasmine-node --matchall es5-sh*m.js tests/helpers/ tests/spec/", "tests-native": "jasmine-node --matchall tests/helpers/ tests/spec/", "lint": "eslint ." }, "devDependencies": { "@ljharb/eslint-config": "^21.0.0", "aud": "^2.0.1", "eslint": "=8.8.0", "in-publish": "^2.0.1", "jasmine-node": "^1.16.2", "npmignore": "^0.3.0", "nyc": "^10.3.2", "safe-publish-latest": "^2.0.0", "uglify-js": "2.7.3" }, "engines": { "node": ">=0.4.0" }, "testling": { "browsers": [ "iexplore/6.0..latest", "firefox/3.0..6.0", "firefox/18.0..latest", "firefox/nightly", "chrome/4.0..10.0", "chrome/25.0..latest", "chrome/canary", "opera/10.0..latest", "opera/next", "safari/4.0..latest", "ipad/6.0..latest", "iphone/6.0..latest", "android-browser/4.2" ] }, "keywords": [ "shim", "es5", "es5 shim", "javascript", "ecmascript", "polyfill" ], "publishConfig": { "ignore": [ ".github/workflows" ] } } ================================================ FILE: shims.json ================================================ { "Object": { "prototype": {}, "keys": "object-keys" } } ================================================ FILE: tests/helpers/h-matchers.js ================================================ var has = Object.prototype.hasOwnProperty; var getKeys = function (o) { 'use strict'; var key; var a = []; for (key in o) { if (has.call(o, key)) { a.push(key); } } a.sort(); return a; }; beforeEach(function () { 'use strict'; this.addMatchers({ toExactlyMatch: function (expected) { var a1, a2, l, i, key; var actual = this.actual; a1 = getKeys(actual); a2 = getKeys(expected); l = a1.length; if (l !== a2.length) { return false; } for (i = 0; i < l; i++) { key = a1[i]; expect(key).toEqual(a2[i]); expect(actual[key]).toEqual(expected[key]); } return true; } }); }); ================================================ FILE: tests/index.html ================================================ Jasmine Spec Runner ================================================ FILE: tests/index.min.html ================================================ Jasmine Spec Runner ================================================ FILE: tests/lib/jasmine-html.js ================================================ jasmine.TrivialReporter = function(doc) { this.document = doc || document; this.suiteDivs = {}; this.logRunningSpecs = false; }; jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) { var el = document.createElement(type); for (var i = 2; i < arguments.length; i++) { var child = arguments[i]; if (typeof child === 'string') { el.appendChild(document.createTextNode(child)); } else { if (child) { el.appendChild(child); } } } for (var attr in attrs) { if (attr == "className") { el[attr] = attrs[attr]; } else { el.setAttribute(attr, attrs[attr]); } } return el; }; jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) { var showPassed, showSkipped; this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' }, this.createDom('div', { className: 'banner' }, this.createDom('div', { className: 'logo' }, this.createDom('span', { className: 'title' }, "Jasmine"), this.createDom('span', { className: 'version' }, runner.env.versionString())), this.createDom('div', { className: 'options' }, "Show ", showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }), this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "), showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }), this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped") ) ), this.runnerDiv = this.createDom('div', { className: 'runner running' }, this.createDom('a', { className: 'run_spec', href: '?' }, "run all"), this.runnerMessageSpan = this.createDom('span', {}, "Running..."), this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, "")) ); this.document.body.appendChild(this.outerDiv); var suites = runner.suites(); for (var i = 0; i < suites.length; i++) { var suite = suites[i]; var suiteDiv = this.createDom('div', { className: 'suite' }, this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"), this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description)); this.suiteDivs[suite.id] = suiteDiv; var parentDiv = this.outerDiv; if (suite.parentSuite) { parentDiv = this.suiteDivs[suite.parentSuite.id]; } parentDiv.appendChild(suiteDiv); } this.startedAt = new Date(); var self = this; showPassed.onclick = function(evt) { if (showPassed.checked) { self.outerDiv.className += ' show-passed'; } else { self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, ''); } }; showSkipped.onclick = function(evt) { if (showSkipped.checked) { self.outerDiv.className += ' show-skipped'; } else { self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, ''); } }; }; jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) { var results = runner.results(); var className = (results.failedCount > 0) ? "runner failed" : "runner passed"; this.runnerDiv.setAttribute("class", className); //do it twice for IE this.runnerDiv.setAttribute("className", className); var specs = runner.specs(); var specCount = 0; for (var i = 0; i < specs.length; i++) { if (this.specFilter(specs[i])) { specCount++; } } var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s"); message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"; this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild); this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString())); }; jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) { var results = suite.results(); var status = results.passed() ? 'passed' : 'failed'; if (results.totalCount === 0) { // todo: change this to check results.skipped status = 'skipped'; } this.suiteDivs[suite.id].className += " " + status; }; jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) { if (this.logRunningSpecs) { this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...'); } }; jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) { var results = spec.results(); var status = results.passed() ? 'passed' : 'failed'; if (results.skipped) { status = 'skipped'; } var specDiv = this.createDom('div', { className: 'spec ' + status }, this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"), this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(spec.getFullName()), title: spec.getFullName() }, spec.description)); var resultItems = results.getItems(); var messagesDiv = this.createDom('div', { className: 'messages' }); for (var i = 0; i < resultItems.length; i++) { var result = resultItems[i]; if (result.type == 'log') { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString())); } else if (result.type == 'expect' && result.passed && !result.passed()) { messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message)); if (result.trace.stack) { messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack)); } } } if (messagesDiv.childNodes.length > 0) { specDiv.appendChild(messagesDiv); } this.suiteDivs[spec.suite.id].appendChild(specDiv); }; jasmine.TrivialReporter.prototype.log = function() { var console = jasmine.getGlobal().console; if (console && console.log) { if (console.log.apply) { console.log.apply(console, arguments); } else { console.log(arguments); // ie fix: console.log.apply doesn't exist on ie } } }; jasmine.TrivialReporter.prototype.getLocation = function() { return this.document.location; }; jasmine.TrivialReporter.prototype.specFilter = function(spec) { var paramMap = {}; var params = this.getLocation().search.substring(1).split('&'); for (var i = 0; i < params.length; i++) { var p = params[i].split('='); paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]); } if (!paramMap.spec) { return true; } return spec.getFullName().indexOf(paramMap.spec) === 0; }; ================================================ FILE: tests/lib/jasmine.css ================================================ body { font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; } .jasmine_reporter a:visited, .jasmine_reporter a { color: #303; } .jasmine_reporter a:hover, .jasmine_reporter a:active { color: blue; } .run_spec { float:right; padding-right: 5px; font-size: .8em; text-decoration: none; } .jasmine_reporter { margin: 0 5px; } .banner { color: #303; background-color: #fef; padding: 5px; } .logo { float: left; font-size: 1.1em; padding-left: 5px; } .logo .version { font-size: .6em; padding-left: 1em; } .runner.running { background-color: yellow; } .options { text-align: right; font-size: .8em; } .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; } .suite .suite { margin: 5px; } .suite.passed { background-color: #dfd; } .suite.failed { background-color: #fdd; } .spec { margin: 5px; padding-left: 1em; clear: both; } .spec.failed, .spec.passed, .spec.skipped { padding-bottom: 5px; border: 1px solid gray; } .spec.failed { background-color: #fbb; border-color: red; } .spec.passed { background-color: #bfb; border-color: green; } .spec.skipped { background-color: #bbb; } .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; } .passed { background-color: #cfc; display: none; } .failed { background-color: #fbb; } .skipped { color: #777; background-color: #eee; display: none; } /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ .resultMessage span.result { display: block; line-height: 2em; color: black; } .resultMessage .mismatch { color: black; } .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; } .finished-at { padding-left: 1em; font-size: .6em; } .show-passed .passed, .show-skipped .skipped { display: block; } #jasmine_content { position:fixed; right: 100%; } .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; } ================================================ FILE: tests/lib/jasmine.js ================================================ var isCommonJS = typeof window == "undefined" && typeof exports == "object"; /** * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework. * * @namespace */ var jasmine = {}; if (isCommonJS) exports.jasmine = jasmine; /** * @private */ jasmine.unimplementedMethod_ = function() { throw new Error("unimplemented method"); }; /** * Use jasmine.undefined instead of undefined, since undefined is just * a plain old variable and may be redefined by somebody else. * * @private */ jasmine.undefined = jasmine.___undefined___; /** * Show diagnostic messages in the console if set to true * */ jasmine.VERBOSE = false; /** * Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed. * */ jasmine.DEFAULT_UPDATE_INTERVAL = 250; /** * Maximum levels of nesting that will be included when an object is pretty-printed */ jasmine.MAX_PRETTY_PRINT_DEPTH = 40; /** * Default timeout interval in milliseconds for waitsFor() blocks. */ jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000; /** * By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite. * Set to false to let the exception bubble up in the browser. * */ jasmine.CATCH_EXCEPTIONS = true; jasmine.getGlobal = function() { function getGlobal() { return this; } return getGlobal(); }; /** * Allows for bound functions to be compared. Internal use only. * * @ignore * @private * @param base {Object} bound 'this' for the function * @param name {Function} function to find */ jasmine.bindOriginal_ = function(base, name) { var original = base[name]; if (original.apply) { return function() { return original.apply(base, arguments); }; } else { // IE support return jasmine.getGlobal()[name]; } }; jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout'); jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout'); jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval'); jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval'); jasmine.MessageResult = function(values) { this.type = 'log'; this.values = values; this.trace = new Error(); // todo: test better }; jasmine.MessageResult.prototype.toString = function() { var text = ""; for (var i = 0; i < this.values.length; i++) { if (i > 0) text += " "; if (jasmine.isString_(this.values[i])) { text += this.values[i]; } else { text += jasmine.pp(this.values[i]); } } return text; }; jasmine.ExpectationResult = function(params) { this.type = 'expect'; this.matcherName = params.matcherName; this.passed_ = params.passed; this.expected = params.expected; this.actual = params.actual; this.message = this.passed_ ? 'Passed.' : params.message; var trace = (params.trace || new Error(this.message)); this.trace = this.passed_ ? '' : trace; }; jasmine.ExpectationResult.prototype.toString = function () { return this.message; }; jasmine.ExpectationResult.prototype.passed = function () { return this.passed_; }; /** * Getter for the Jasmine environment. Ensures one gets created */ jasmine.getEnv = function() { var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env(); return env; }; /** * @ignore * @private * @param value * @returns {Boolean} */ jasmine.isArray_ = function(value) { return jasmine.isA_("Array", value); }; /** * @ignore * @private * @param value * @returns {Boolean} */ jasmine.isString_ = function(value) { return jasmine.isA_("String", value); }; /** * @ignore * @private * @param value * @returns {Boolean} */ jasmine.isNumber_ = function(value) { return jasmine.isA_("Number", value); }; /** * @ignore * @private * @param {String} typeName * @param value * @returns {Boolean} */ jasmine.isA_ = function(typeName, value) { return Object.prototype.toString.apply(value) === '[object ' + typeName + ']'; }; /** * Pretty printer for expecations. Takes any object and turns it into a human-readable string. * * @param value {Object} an object to be outputted * @returns {String} */ jasmine.pp = function(value) { var stringPrettyPrinter = new jasmine.StringPrettyPrinter(); stringPrettyPrinter.format(value); return stringPrettyPrinter.string; }; /** * Returns true if the object is a DOM Node. * * @param {Object} obj object to check * @returns {Boolean} */ jasmine.isDomNode = function(obj) { return obj.nodeType > 0; }; /** * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter. * * @example * // don't care about which function is passed in, as long as it's a function * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function)); * * @param {Class} clazz * @returns matchable object of the type clazz */ jasmine.any = function(clazz) { return new jasmine.Matchers.Any(clazz); }; /** * Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the * attributes on the object. * * @example * // don't care about any other attributes than foo. * expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"}); * * @param sample {Object} sample * @returns matchable object for the sample */ jasmine.objectContaining = function (sample) { return new jasmine.Matchers.ObjectContaining(sample); }; /** * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks. * * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine * expectation syntax. Spies can be checked if they were called or not and what the calling params were. * * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs). * * Spies are torn down at the end of every spec. * * Note: Do not call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj. * * @example * // a stub * var myStub = jasmine.createSpy('myStub'); // can be used anywhere * * // spy example * var foo = { * not: function(bool) { return !bool; } * } * * // actual foo.not will not be called, execution stops * spyOn(foo, 'not'); // foo.not spied upon, execution will continue to implementation * spyOn(foo, 'not').andCallThrough(); * * // fake example * var foo = { * not: function(bool) { return !bool; } * } * * // foo.not(val) will return val * spyOn(foo, 'not').andCallFake(function(value) {return value;}); * * // mock example * foo.not(7 == 7); * expect(foo.not).toHaveBeenCalled(); * expect(foo.not).toHaveBeenCalledWith(true); * * @constructor * @see spyOn, jasmine.createSpy, jasmine.createSpyObj * @param {String} name */ jasmine.Spy = function(name) { /** * The name of the spy, if provided. */ this.identity = name || 'unknown'; /** * Is this Object a spy? */ this.isSpy = true; /** * The actual function this spy stubs. */ this.plan = function() { }; /** * Tracking of the most recent call to the spy. * @example * var mySpy = jasmine.createSpy('foo'); * mySpy(1, 2); * mySpy.mostRecentCall.args = [1, 2]; */ this.mostRecentCall = {}; /** * Holds arguments for each call to the spy, indexed by call count * @example * var mySpy = jasmine.createSpy('foo'); * mySpy(1, 2); * mySpy(7, 8); * mySpy.mostRecentCall.args = [7, 8]; * mySpy.argsForCall[0] = [1, 2]; * mySpy.argsForCall[1] = [7, 8]; */ this.argsForCall = []; this.calls = []; }; /** * Tells a spy to call through to the actual implemenatation. * * @example * var foo = { * bar: function() { // do some stuff } * } * * // defining a spy on an existing property: foo.bar * spyOn(foo, 'bar').andCallThrough(); */ jasmine.Spy.prototype.andCallThrough = function() { this.plan = this.originalValue; return this; }; /** * For setting the return value of a spy. * * @example * // defining a spy from scratch: foo() returns 'baz' * var foo = jasmine.createSpy('spy on foo').andReturn('baz'); * * // defining a spy on an existing property: foo.bar() returns 'baz' * spyOn(foo, 'bar').andReturn('baz'); * * @param {Object} value */ jasmine.Spy.prototype.andReturn = function(value) { this.plan = function() { return value; }; return this; }; /** * For throwing an exception when a spy is called. * * @example * // defining a spy from scratch: foo() throws an exception w/ message 'ouch' * var foo = jasmine.createSpy('spy on foo').andThrow('baz'); * * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch' * spyOn(foo, 'bar').andThrow('baz'); * * @param {String} exceptionMsg */ jasmine.Spy.prototype.andThrow = function(exceptionMsg) { this.plan = function() { throw exceptionMsg; }; return this; }; /** * Calls an alternate implementation when a spy is called. * * @example * var baz = function() { * // do some stuff, return something * } * // defining a spy from scratch: foo() calls the function baz * var foo = jasmine.createSpy('spy on foo').andCall(baz); * * // defining a spy on an existing property: foo.bar() calls an anonymnous function * spyOn(foo, 'bar').andCall(function() { return 'baz';} ); * * @param {Function} fakeFunc */ jasmine.Spy.prototype.andCallFake = function(fakeFunc) { this.plan = fakeFunc; return this; }; /** * Resets all of a spy's the tracking variables so that it can be used again. * * @example * spyOn(foo, 'bar'); * * foo.bar(); * * expect(foo.bar.callCount).toEqual(1); * * foo.bar.reset(); * * expect(foo.bar.callCount).toEqual(0); */ jasmine.Spy.prototype.reset = function() { this.wasCalled = false; this.callCount = 0; this.argsForCall = []; this.calls = []; this.mostRecentCall = {}; }; jasmine.createSpy = function(name) { var spyObj = function() { spyObj.wasCalled = true; spyObj.callCount++; var args = jasmine.util.argsToArray(arguments); spyObj.mostRecentCall.object = this; spyObj.mostRecentCall.args = args; spyObj.argsForCall.push(args); spyObj.calls.push({object: this, args: args}); return spyObj.plan.apply(this, arguments); }; var spy = new jasmine.Spy(name); for (var prop in spy) { spyObj[prop] = spy[prop]; } spyObj.reset(); return spyObj; }; /** * Determines whether an object is a spy. * * @param {jasmine.Spy|Object} putativeSpy * @returns {Boolean} */ jasmine.isSpy = function(putativeSpy) { return putativeSpy && putativeSpy.isSpy; }; /** * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something * large in one call. * * @param {String} baseName name of spy class * @param {Array} methodNames array of names of methods to make spies */ jasmine.createSpyObj = function(baseName, methodNames) { if (!jasmine.isArray_(methodNames) || methodNames.length === 0) { throw new Error('createSpyObj requires a non-empty array of method names to create spies for'); } var obj = {}; for (var i = 0; i < methodNames.length; i++) { obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]); } return obj; }; /** * All parameters are pretty-printed and concatenated together, then written to the current spec's output. * * Be careful not to leave calls to jasmine.log in production code. */ jasmine.log = function() { var spec = jasmine.getEnv().currentSpec; spec.log.apply(spec, arguments); }; /** * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy. * * @example * // spy example * var foo = { * not: function(bool) { return !bool; } * } * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops * * @see jasmine.createSpy * @param obj * @param methodName * @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods */ var spyOn = function(obj, methodName) { return jasmine.getEnv().currentSpec.spyOn(obj, methodName); }; if (isCommonJS) exports.spyOn = spyOn; /** * Creates a Jasmine spec that will be added to the current suite. * * // TODO: pending tests * * @example * it('should be true', function() { * expect(true).toEqual(true); * }); * * @param {String} desc description of this specification * @param {Function} func defines the preconditions and expectations of the spec */ var it = function(desc, func) { return jasmine.getEnv().it(desc, func); }; if (isCommonJS) exports.it = it; /** * Creates a disabled Jasmine spec. * * A convenience method that allows existing specs to be disabled temporarily during development. * * @param {String} desc description of this specification * @param {Function} func defines the preconditions and expectations of the spec */ var xit = function(desc, func) { return jasmine.getEnv().xit(desc, func); }; if (isCommonJS) exports.xit = xit; /** * Starts a chain for a Jasmine expectation. * * It is passed an Object that is the actual value and should chain to one of the many * jasmine.Matchers functions. * * @param {Object} actual Actual value to test against and expected value * @return {jasmine.Matchers} */ var expect = function(actual) { return jasmine.getEnv().currentSpec.expect(actual); }; if (isCommonJS) exports.expect = expect; /** * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs. * * @param {Function} func Function that defines part of a jasmine spec. */ var runs = function(func) { jasmine.getEnv().currentSpec.runs(func); }; if (isCommonJS) exports.runs = runs; /** * Waits a fixed time period before moving to the next block. * * @deprecated Use waitsFor() instead * @param {Number} timeout milliseconds to wait */ var waits = function(timeout) { jasmine.getEnv().currentSpec.waits(timeout); }; if (isCommonJS) exports.waits = waits; /** * Waits for the latchFunction to return true before proceeding to the next block. * * @param {Function} latchFunction * @param {String} optional_timeoutMessage * @param {Number} optional_timeout */ var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments); }; if (isCommonJS) exports.waitsFor = waitsFor; /** * A function that is called before each spec in a suite. * * Used for spec setup, including validating assumptions. * * @param {Function} beforeEachFunction */ var beforeEach = function(beforeEachFunction) { jasmine.getEnv().beforeEach(beforeEachFunction); }; if (isCommonJS) exports.beforeEach = beforeEach; /** * A function that is called after each spec in a suite. * * Used for restoring any state that is hijacked during spec execution. * * @param {Function} afterEachFunction */ var afterEach = function(afterEachFunction) { jasmine.getEnv().afterEach(afterEachFunction); }; if (isCommonJS) exports.afterEach = afterEach; /** * Defines a suite of specifications. * * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization * of setup in some tests. * * @example * // TODO: a simple suite * * // TODO: a simple suite with a nested describe block * * @param {String} description A string, usually the class under test. * @param {Function} specDefinitions function that defines several specs. */ var describe = function(description, specDefinitions) { return jasmine.getEnv().describe(description, specDefinitions); }; if (isCommonJS) exports.describe = describe; /** * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development. * * @param {String} description A string, usually the class under test. * @param {Function} specDefinitions function that defines several specs. */ var xdescribe = function(description, specDefinitions) { return jasmine.getEnv().xdescribe(description, specDefinitions); }; if (isCommonJS) exports.xdescribe = xdescribe; // Provide the XMLHttpRequest class for IE 5.x-6.x: jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() { function tryIt(f) { try { return f(); } catch(e) { } return null; } var xhr = tryIt(function() { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }) || tryIt(function() { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }) || tryIt(function() { return new ActiveXObject("Msxml2.XMLHTTP"); }) || tryIt(function() { return new ActiveXObject("Microsoft.XMLHTTP"); }); if (!xhr) throw new Error("This browser does not support XMLHttpRequest."); return xhr; } : XMLHttpRequest; /** * @namespace */ jasmine.util = {}; /** * Declare that a child class inherit it's prototype from the parent class. * * @private * @param {Function} childClass * @param {Function} parentClass */ jasmine.util.inherit = function(childClass, parentClass) { /** * @private */ var subclass = function() { }; subclass.prototype = parentClass.prototype; childClass.prototype = new subclass(); }; jasmine.util.formatException = function(e) { var lineNumber; if (e.line) { lineNumber = e.line; } else if (e.lineNumber) { lineNumber = e.lineNumber; } var file; if (e.sourceURL) { file = e.sourceURL; } else if (e.fileName) { file = e.fileName; } var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString(); if (file && lineNumber) { message += ' in ' + file + ' (line ' + lineNumber + ')'; } return message; }; jasmine.util.htmlEscape = function(str) { if (!str) return str; return str.replace(/&/g, '&') .replace(//g, '>'); }; jasmine.util.argsToArray = function(args) { var arrayOfArgs = []; for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]); return arrayOfArgs; }; jasmine.util.extend = function(destination, source) { for (var property in source) destination[property] = source[property]; return destination; }; /** * Environment for Jasmine * * @constructor */ jasmine.Env = function() { this.currentSpec = null; this.currentSuite = null; this.currentRunner_ = new jasmine.Runner(this); this.reporter = new jasmine.MultiReporter(); this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL; this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL; this.lastUpdate = 0; this.specFilter = function() { return true; }; this.nextSpecId_ = 0; this.nextSuiteId_ = 0; this.equalityTesters_ = []; // wrap matchers this.matchersClass = function() { jasmine.Matchers.apply(this, arguments); }; jasmine.util.inherit(this.matchersClass, jasmine.Matchers); jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass); }; jasmine.Env.prototype.setTimeout = jasmine.setTimeout; jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout; jasmine.Env.prototype.setInterval = jasmine.setInterval; jasmine.Env.prototype.clearInterval = jasmine.clearInterval; /** * @returns an object containing jasmine version build info, if set. */ jasmine.Env.prototype.version = function () { if (jasmine.version_) { return jasmine.version_; } else { throw new Error('Version not set'); } }; /** * @returns string containing jasmine version build info, if set. */ jasmine.Env.prototype.versionString = function() { if (!jasmine.version_) { return "version unknown"; } var version = this.version(); var versionString = version.major + "." + version.minor + "." + version.build; if (version.release_candidate) { versionString += ".rc" + version.release_candidate; } versionString += " revision " + version.revision; return versionString; }; /** * @returns a sequential integer starting at 0 */ jasmine.Env.prototype.nextSpecId = function () { return this.nextSpecId_++; }; /** * @returns a sequential integer starting at 0 */ jasmine.Env.prototype.nextSuiteId = function () { return this.nextSuiteId_++; }; /** * Register a reporter to receive status updates from Jasmine. * @param {jasmine.Reporter} reporter An object which will receive status updates. */ jasmine.Env.prototype.addReporter = function(reporter) { this.reporter.addReporter(reporter); }; jasmine.Env.prototype.execute = function() { this.currentRunner_.execute(); }; jasmine.Env.prototype.describe = function(description, specDefinitions) { var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite); var parentSuite = this.currentSuite; if (parentSuite) { parentSuite.add(suite); } else { this.currentRunner_.add(suite); } this.currentSuite = suite; var declarationError = null; try { specDefinitions.call(suite); } catch(e) { declarationError = e; } if (declarationError) { this.it("encountered a declaration exception", function() { throw declarationError; }); } this.currentSuite = parentSuite; return suite; }; jasmine.Env.prototype.beforeEach = function(beforeEachFunction) { if (this.currentSuite) { this.currentSuite.beforeEach(beforeEachFunction); } else { this.currentRunner_.beforeEach(beforeEachFunction); } }; jasmine.Env.prototype.currentRunner = function () { return this.currentRunner_; }; jasmine.Env.prototype.afterEach = function(afterEachFunction) { if (this.currentSuite) { this.currentSuite.afterEach(afterEachFunction); } else { this.currentRunner_.afterEach(afterEachFunction); } }; jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) { return { execute: function() { } }; }; jasmine.Env.prototype.it = function(description, func) { var spec = new jasmine.Spec(this, this.currentSuite, description); this.currentSuite.add(spec); this.currentSpec = spec; if (func) { spec.runs(func); } return spec; }; jasmine.Env.prototype.xit = function(desc, func) { return { id: this.nextSpecId(), runs: function() { } }; }; jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) { if (a.source != b.source) mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/"); if (a.ignoreCase != b.ignoreCase) mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier"); if (a.global != b.global) mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier"); if (a.multiline != b.multiline) mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier"); if (a.sticky != b.sticky) mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier"); return (mismatchValues.length === 0); }; jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) { if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) { return true; } a.__Jasmine_been_here_before__ = b; b.__Jasmine_been_here_before__ = a; var hasKey = function(obj, keyName) { return obj !== null && obj[keyName] !== jasmine.undefined; }; for (var property in b) { if (!hasKey(a, property) && hasKey(b, property)) { mismatchKeys.push("expected has key '" + property + "', but missing from actual."); } } for (property in a) { if (!hasKey(b, property) && hasKey(a, property)) { mismatchKeys.push("expected missing key '" + property + "', but present in actual."); } } for (property in b) { if (property == '__Jasmine_been_here_before__') continue; if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) { mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual."); } } if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) { mismatchValues.push("arrays were not the same length"); } delete a.__Jasmine_been_here_before__; delete b.__Jasmine_been_here_before__; return (mismatchKeys.length === 0 && mismatchValues.length === 0); }; jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) { mismatchKeys = mismatchKeys || []; mismatchValues = mismatchValues || []; for (var i = 0; i < this.equalityTesters_.length; i++) { var equalityTester = this.equalityTesters_[i]; var result = equalityTester(a, b, this, mismatchKeys, mismatchValues); if (result !== jasmine.undefined) return result; } if (a === b) return true; if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) { return (a == jasmine.undefined && b == jasmine.undefined); } if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) { return a === b; } if (a instanceof Date && b instanceof Date) { return a.getTime() == b.getTime(); } if (a.jasmineMatches) { return a.jasmineMatches(b); } if (b.jasmineMatches) { return b.jasmineMatches(a); } if (a instanceof jasmine.Matchers.ObjectContaining) { return a.matches(b); } if (b instanceof jasmine.Matchers.ObjectContaining) { return b.matches(a); } if (jasmine.isString_(a) && jasmine.isString_(b)) { return (a == b); } if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) { return (a == b); } if (a instanceof RegExp && b instanceof RegExp) { return this.compareRegExps_(a, b, mismatchKeys, mismatchValues); } if (typeof a === "object" && typeof b === "object") { return this.compareObjects_(a, b, mismatchKeys, mismatchValues); } //Straight check return (a === b); }; jasmine.Env.prototype.contains_ = function(haystack, needle) { if (jasmine.isArray_(haystack)) { for (var i = 0; i < haystack.length; i++) { if (this.equals_(haystack[i], needle)) return true; } return false; } return haystack.indexOf(needle) >= 0; }; jasmine.Env.prototype.addEqualityTester = function(equalityTester) { this.equalityTesters_.push(equalityTester); }; /** No-op base class for Jasmine reporters. * * @constructor */ jasmine.Reporter = function() { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.reportRunnerStarting = function(runner) { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.reportRunnerResults = function(runner) { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.reportSuiteResults = function(suite) { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.reportSpecStarting = function(spec) { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.reportSpecResults = function(spec) { }; //noinspection JSUnusedLocalSymbols jasmine.Reporter.prototype.log = function(str) { }; /** * Blocks are functions with executable code that make up a spec. * * @constructor * @param {jasmine.Env} env * @param {Function} func * @param {jasmine.Spec} spec */ jasmine.Block = function(env, func, spec) { this.env = env; this.func = func; this.spec = spec; }; jasmine.Block.prototype.execute = function(onComplete) { if (!jasmine.CATCH_EXCEPTIONS) { this.func.apply(this.spec); } else { try { this.func.apply(this.spec); } catch (e) { this.spec.fail(e); } } onComplete(); }; /** JavaScript API reporter. * * @constructor */ jasmine.JsApiReporter = function() { this.started = false; this.finished = false; this.suites_ = []; this.results_ = {}; }; jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) { this.started = true; var suites = runner.topLevelSuites(); for (var i = 0; i < suites.length; i++) { var suite = suites[i]; this.suites_.push(this.summarize_(suite)); } }; jasmine.JsApiReporter.prototype.suites = function() { return this.suites_; }; jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) { var isSuite = suiteOrSpec instanceof jasmine.Suite; var summary = { id: suiteOrSpec.id, name: suiteOrSpec.description, type: isSuite ? 'suite' : 'spec', children: [] }; if (isSuite) { var children = suiteOrSpec.children(); for (var i = 0; i < children.length; i++) { summary.children.push(this.summarize_(children[i])); } } return summary; }; jasmine.JsApiReporter.prototype.results = function() { return this.results_; }; jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) { return this.results_[specId]; }; //noinspection JSUnusedLocalSymbols jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) { this.finished = true; }; //noinspection JSUnusedLocalSymbols jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) { }; //noinspection JSUnusedLocalSymbols jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) { this.results_[spec.id] = { messages: spec.results().getItems(), result: spec.results().failedCount > 0 ? "failed" : "passed" }; }; //noinspection JSUnusedLocalSymbols jasmine.JsApiReporter.prototype.log = function(str) { }; jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){ var results = {}; for (var i = 0; i < specIds.length; i++) { var specId = specIds[i]; results[specId] = this.summarizeResult_(this.results_[specId]); } return results; }; jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){ var summaryMessages = []; var messagesLength = result.messages.length; for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) { var resultMessage = result.messages[messageIndex]; summaryMessages.push({ text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined, passed: resultMessage.passed ? resultMessage.passed() : true, type: resultMessage.type, message: resultMessage.message, trace: { stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined } }); } return { result : result.result, messages : summaryMessages }; }; /** * @constructor * @param {jasmine.Env} env * @param actual * @param {jasmine.Spec} spec */ jasmine.Matchers = function(env, actual, spec, opt_isNot) { this.env = env; this.actual = actual; this.spec = spec; this.isNot = opt_isNot || false; this.reportWasCalled_ = false; }; // todo: @deprecated as of Jasmine 0.11, remove soon [xw] jasmine.Matchers.pp = function(str) { throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!"); }; // todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw] jasmine.Matchers.prototype.report = function(result, failing_message, details) { throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs"); }; jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) { for (var methodName in prototype) { if (methodName == 'report') continue; var orig = prototype[methodName]; matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig); } }; jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) { return function() { var matcherArgs = jasmine.util.argsToArray(arguments); var result = matcherFunction.apply(this, arguments); if (this.isNot) { result = !result; } if (this.reportWasCalled_) return result; var message; if (!result) { if (this.message) { message = this.message.apply(this, arguments); if (jasmine.isArray_(message)) { message = message[this.isNot ? 1 : 0]; } } else { var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate; if (matcherArgs.length > 0) { for (var i = 0; i < matcherArgs.length; i++) { if (i > 0) message += ","; message += " " + jasmine.pp(matcherArgs[i]); } } message += "."; } } var expectationResult = new jasmine.ExpectationResult({ matcherName: matcherName, passed: result, expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0], actual: this.actual, message: message }); this.spec.addMatcherResult(expectationResult); return jasmine.undefined; }; }; /** * toBe: compares the actual to the expected using === * @param expected */ jasmine.Matchers.prototype.toBe = function(expected) { return this.actual === expected; }; /** * toNotBe: compares the actual to the expected using !== * @param expected * @deprecated as of 1.0. Use not.toBe() instead. */ jasmine.Matchers.prototype.toNotBe = function(expected) { return this.actual !== expected; }; /** * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc. * * @param expected */ jasmine.Matchers.prototype.toEqual = function(expected) { return this.env.equals_(this.actual, expected); }; /** * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual * @param expected * @deprecated as of 1.0. Use not.toEqual() instead. */ jasmine.Matchers.prototype.toNotEqual = function(expected) { return !this.env.equals_(this.actual, expected); }; /** * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes * a pattern or a String. * * @param expected */ jasmine.Matchers.prototype.toMatch = function(expected) { return new RegExp(expected).test(this.actual); }; /** * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch * @param expected * @deprecated as of 1.0. Use not.toMatch() instead. */ jasmine.Matchers.prototype.toNotMatch = function(expected) { return !(new RegExp(expected).test(this.actual)); }; /** * Matcher that compares the actual to jasmine.undefined. */ jasmine.Matchers.prototype.toBeDefined = function() { return (this.actual !== jasmine.undefined); }; /** * Matcher that compares the actual to jasmine.undefined. */ jasmine.Matchers.prototype.toBeUndefined = function() { return (this.actual === jasmine.undefined); }; /** * Matcher that compares the actual to null. */ jasmine.Matchers.prototype.toBeNull = function() { return (this.actual === null); }; /** * Matcher that compares the actual to NaN. */ jasmine.Matchers.prototype.toBeNaN = function() { this.message = function() { return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ]; }; return (this.actual !== this.actual); }; /** * Matcher that boolean not-nots the actual. */ jasmine.Matchers.prototype.toBeTruthy = function() { return !!this.actual; }; /** * Matcher that boolean nots the actual. */ jasmine.Matchers.prototype.toBeFalsy = function() { return !this.actual; }; /** * Matcher that checks to see if the actual, a Jasmine spy, was called. */ jasmine.Matchers.prototype.toHaveBeenCalled = function() { if (arguments.length > 0) { throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith'); } if (!jasmine.isSpy(this.actual)) { throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); } this.message = function() { return [ "Expected spy " + this.actual.identity + " to have been called.", "Expected spy " + this.actual.identity + " not to have been called." ]; }; return this.actual.wasCalled; }; /** @deprecated Use expect(xxx).toHaveBeenCalled() instead */ jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled; /** * Matcher that checks to see if the actual, a Jasmine spy, was not called. * * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead */ jasmine.Matchers.prototype.wasNotCalled = function() { if (arguments.length > 0) { throw new Error('wasNotCalled does not take arguments'); } if (!jasmine.isSpy(this.actual)) { throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); } this.message = function() { return [ "Expected spy " + this.actual.identity + " to not have been called.", "Expected spy " + this.actual.identity + " to have been called." ]; }; return !this.actual.wasCalled; }; /** * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters. * * @example * */ jasmine.Matchers.prototype.toHaveBeenCalledWith = function() { var expectedArgs = jasmine.util.argsToArray(arguments); if (!jasmine.isSpy(this.actual)) { throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); } this.message = function() { var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was."; var positiveMessage = ""; if (this.actual.callCount === 0) { positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called."; } else { positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '') } return [positiveMessage, invertedMessage]; }; return this.env.contains_(this.actual.argsForCall, expectedArgs); }; /** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */ jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith; /** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */ jasmine.Matchers.prototype.wasNotCalledWith = function() { var expectedArgs = jasmine.util.argsToArray(arguments); if (!jasmine.isSpy(this.actual)) { throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.'); } this.message = function() { return [ "Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was", "Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was" ]; }; return !this.env.contains_(this.actual.argsForCall, expectedArgs); }; /** * Matcher that checks that the expected item is an element in the actual Array. * * @param {Object} expected */ jasmine.Matchers.prototype.toContain = function(expected) { return this.env.contains_(this.actual, expected); }; /** * Matcher that checks that the expected item is NOT an element in the actual Array. * * @param {Object} expected * @deprecated as of 1.0. Use not.toContain() instead. */ jasmine.Matchers.prototype.toNotContain = function(expected) { return !this.env.contains_(this.actual, expected); }; jasmine.Matchers.prototype.toBeLessThan = function(expected) { return this.actual < expected; }; jasmine.Matchers.prototype.toBeGreaterThan = function(expected) { return this.actual > expected; }; /** * Matcher that checks that the expected item is equal to the actual item * up to a given level of decimal precision (default 2). * * @param {Number} expected * @param {Number} precision, as number of decimal places */ jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) { if (!(precision === 0)) { precision = precision || 2; } return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2); }; /** * Matcher that checks that the expected exception was thrown by the actual. * * @param {String} [expected] */ jasmine.Matchers.prototype.toThrow = function(expected) { var result = false; var exception; if (typeof this.actual != 'function') { throw new Error('Actual is not a function'); } try { this.actual(); } catch (e) { exception = e; } if (exception) { result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected)); } var not = this.isNot ? "not " : ""; this.message = function() { if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) { return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' '); } else { return "Expected function to throw an exception."; } }; return result; }; jasmine.Matchers.Any = function(expectedClass) { this.expectedClass = expectedClass; }; jasmine.Matchers.Any.prototype.jasmineMatches = function(other) { if (this.expectedClass == String) { return typeof other == 'string' || other instanceof String; } if (this.expectedClass == Number) { return typeof other == 'number' || other instanceof Number; } if (this.expectedClass == Function) { return typeof other == 'function' || other instanceof Function; } if (this.expectedClass == Object) { return typeof other == 'object'; } return other instanceof this.expectedClass; }; jasmine.Matchers.Any.prototype.jasmineToString = function() { return ''; }; jasmine.Matchers.ObjectContaining = function (sample) { this.sample = sample; }; jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) { mismatchKeys = mismatchKeys || []; mismatchValues = mismatchValues || []; var env = jasmine.getEnv(); var hasKey = function(obj, keyName) { return obj != null && obj[keyName] !== jasmine.undefined; }; for (var property in this.sample) { if (!hasKey(other, property) && hasKey(this.sample, property)) { mismatchKeys.push("expected has key '" + property + "', but missing from actual."); } else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) { mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual."); } } return (mismatchKeys.length === 0 && mismatchValues.length === 0); }; jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () { return ""; }; // Mock setTimeout, clearTimeout // Contributed by Pivotal Computer Systems, www.pivotalsf.com jasmine.FakeTimer = function() { this.reset(); var self = this; self.setTimeout = function(funcToCall, millis) { self.timeoutsMade++; self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false); return self.timeoutsMade; }; self.setInterval = function(funcToCall, millis) { self.timeoutsMade++; self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true); return self.timeoutsMade; }; self.clearTimeout = function(timeoutKey) { self.scheduledFunctions[timeoutKey] = jasmine.undefined; }; self.clearInterval = function(timeoutKey) { self.scheduledFunctions[timeoutKey] = jasmine.undefined; }; }; jasmine.FakeTimer.prototype.reset = function() { this.timeoutsMade = 0; this.scheduledFunctions = {}; this.nowMillis = 0; }; jasmine.FakeTimer.prototype.tick = function(millis) { var oldMillis = this.nowMillis; var newMillis = oldMillis + millis; this.runFunctionsWithinRange(oldMillis, newMillis); this.nowMillis = newMillis; }; jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) { var scheduledFunc; var funcsToRun = []; for (var timeoutKey in this.scheduledFunctions) { scheduledFunc = this.scheduledFunctions[timeoutKey]; if (scheduledFunc != jasmine.undefined && scheduledFunc.runAtMillis >= oldMillis && scheduledFunc.runAtMillis <= nowMillis) { funcsToRun.push(scheduledFunc); this.scheduledFunctions[timeoutKey] = jasmine.undefined; } } if (funcsToRun.length > 0) { funcsToRun.sort(function(a, b) { return a.runAtMillis - b.runAtMillis; }); for (var i = 0; i < funcsToRun.length; ++i) { try { var funcToRun = funcsToRun[i]; this.nowMillis = funcToRun.runAtMillis; funcToRun.funcToCall(); if (funcToRun.recurring) { this.scheduleFunction(funcToRun.timeoutKey, funcToRun.funcToCall, funcToRun.millis, true); } } catch(e) { } } this.runFunctionsWithinRange(oldMillis, nowMillis); } }; jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) { this.scheduledFunctions[timeoutKey] = { runAtMillis: this.nowMillis + millis, funcToCall: funcToCall, recurring: recurring, timeoutKey: timeoutKey, millis: millis }; }; /** * @namespace */ jasmine.Clock = { defaultFakeTimer: new jasmine.FakeTimer(), reset: function() { jasmine.Clock.assertInstalled(); jasmine.Clock.defaultFakeTimer.reset(); }, tick: function(millis) { jasmine.Clock.assertInstalled(); jasmine.Clock.defaultFakeTimer.tick(millis); }, runFunctionsWithinRange: function(oldMillis, nowMillis) { jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis); }, scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) { jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring); }, useMock: function() { if (!jasmine.Clock.isInstalled()) { var spec = jasmine.getEnv().currentSpec; spec.after(jasmine.Clock.uninstallMock); jasmine.Clock.installMock(); } }, installMock: function() { jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer; }, uninstallMock: function() { jasmine.Clock.assertInstalled(); jasmine.Clock.installed = jasmine.Clock.real; }, real: { setTimeout: jasmine.getGlobal().setTimeout, clearTimeout: jasmine.getGlobal().clearTimeout, setInterval: jasmine.getGlobal().setInterval, clearInterval: jasmine.getGlobal().clearInterval }, assertInstalled: function() { if (!jasmine.Clock.isInstalled()) { throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()"); } }, isInstalled: function() { return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer; }, installed: null }; jasmine.Clock.installed = jasmine.Clock.real; //else for IE support jasmine.getGlobal().setTimeout = function(funcToCall, millis) { if (jasmine.Clock.installed.setTimeout.apply) { return jasmine.Clock.installed.setTimeout.apply(this, arguments); } else { return jasmine.Clock.installed.setTimeout(funcToCall, millis); } }; jasmine.getGlobal().setInterval = function(funcToCall, millis) { if (jasmine.Clock.installed.setInterval.apply) { return jasmine.Clock.installed.setInterval.apply(this, arguments); } else { return jasmine.Clock.installed.setInterval(funcToCall, millis); } }; jasmine.getGlobal().clearTimeout = function(timeoutKey) { if (jasmine.Clock.installed.clearTimeout.apply) { return jasmine.Clock.installed.clearTimeout.apply(this, arguments); } else { return jasmine.Clock.installed.clearTimeout(timeoutKey); } }; jasmine.getGlobal().clearInterval = function(timeoutKey) { if (jasmine.Clock.installed.clearTimeout.apply) { return jasmine.Clock.installed.clearInterval.apply(this, arguments); } else { return jasmine.Clock.installed.clearInterval(timeoutKey); } }; /** * @constructor */ jasmine.MultiReporter = function() { this.subReporters_ = []; }; jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter); jasmine.MultiReporter.prototype.addReporter = function(reporter) { this.subReporters_.push(reporter); }; (function() { var functionNames = [ "reportRunnerStarting", "reportRunnerResults", "reportSuiteResults", "reportSpecStarting", "reportSpecResults", "log" ]; for (var i = 0; i < functionNames.length; i++) { var functionName = functionNames[i]; jasmine.MultiReporter.prototype[functionName] = (function(functionName) { return function() { for (var j = 0; j < this.subReporters_.length; j++) { var subReporter = this.subReporters_[j]; if (subReporter[functionName]) { subReporter[functionName].apply(subReporter, arguments); } } }; })(functionName); } })(); /** * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults * * @constructor */ jasmine.NestedResults = function() { /** * The total count of results */ this.totalCount = 0; /** * Number of passed results */ this.passedCount = 0; /** * Number of failed results */ this.failedCount = 0; /** * Was this suite/spec skipped? */ this.skipped = false; /** * @ignore */ this.items_ = []; }; /** * Roll up the result counts. * * @param result */ jasmine.NestedResults.prototype.rollupCounts = function(result) { this.totalCount += result.totalCount; this.passedCount += result.passedCount; this.failedCount += result.failedCount; }; /** * Adds a log message. * @param values Array of message parts which will be concatenated later. */ jasmine.NestedResults.prototype.log = function(values) { this.items_.push(new jasmine.MessageResult(values)); }; /** * Getter for the results: message & results. */ jasmine.NestedResults.prototype.getItems = function() { return this.items_; }; /** * Adds a result, tracking counts (total, passed, & failed) * @param {jasmine.ExpectationResult|jasmine.NestedResults} result */ jasmine.NestedResults.prototype.addResult = function(result) { if (result.type != 'log') { if (result.items_) { this.rollupCounts(result); } else { this.totalCount++; if (result.passed()) { this.passedCount++; } else { this.failedCount++; } } } this.items_.push(result); }; /** * @returns {Boolean} True if everything below passed */ jasmine.NestedResults.prototype.passed = function() { return this.passedCount === this.totalCount; }; /** * Base class for pretty printing for expectation results. */ jasmine.PrettyPrinter = function() { this.ppNestLevel_ = 0; }; /** * Formats a value in a nice, human-readable string. * * @param value */ jasmine.PrettyPrinter.prototype.format = function(value) { this.ppNestLevel_++; try { if (value === jasmine.undefined) { this.emitScalar('undefined'); } else if (value === null) { this.emitScalar('null'); } else if (value === jasmine.getGlobal()) { this.emitScalar(''); } else if (value.jasmineToString) { this.emitScalar(value.jasmineToString()); } else if (typeof value === 'string') { this.emitString(value); } else if (jasmine.isSpy(value)) { this.emitScalar("spy on " + value.identity); } else if (value instanceof RegExp) { this.emitScalar(value.toString()); } else if (typeof value === 'function') { this.emitScalar('Function'); } else if (typeof value.nodeType === 'number') { this.emitScalar('HTMLNode'); } else if (value instanceof Date) { this.emitScalar('Date(' + value + ')'); } else if (value.__Jasmine_been_here_before__) { this.emitScalar(''); } else if (jasmine.isArray_(value) || typeof value == 'object') { value.__Jasmine_been_here_before__ = true; if (jasmine.isArray_(value)) { this.emitArray(value); } else { this.emitObject(value); } delete value.__Jasmine_been_here_before__; } else { this.emitScalar(value.toString()); } } finally { this.ppNestLevel_--; } }; jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) { for (var property in obj) { if (!obj.hasOwnProperty(property)) continue; if (property == '__Jasmine_been_here_before__') continue; fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined && obj.__lookupGetter__(property) !== null) : false); } }; jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_; jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_; jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_; jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_; jasmine.StringPrettyPrinter = function() { jasmine.PrettyPrinter.call(this); this.string = ''; }; jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter); jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) { this.append(value); }; jasmine.StringPrettyPrinter.prototype.emitString = function(value) { this.append("'" + value + "'"); }; jasmine.StringPrettyPrinter.prototype.emitArray = function(array) { if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { this.append("Array"); return; } this.append('[ '); for (var i = 0; i < array.length; i++) { if (i > 0) { this.append(', '); } this.format(array[i]); } this.append(' ]'); }; jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) { if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) { this.append("Object"); return; } var self = this; this.append('{ '); var first = true; this.iterateObject(obj, function(property, isGetter) { if (first) { first = false; } else { self.append(', '); } self.append(property); self.append(' : '); if (isGetter) { self.append(''); } else { self.format(obj[property]); } }); this.append(' }'); }; jasmine.StringPrettyPrinter.prototype.append = function(value) { this.string += value; }; jasmine.Queue = function(env) { this.env = env; // parallel to blocks. each true value in this array means the block will // get executed even if we abort this.ensured = []; this.blocks = []; this.running = false; this.index = 0; this.offset = 0; this.abort = false; }; jasmine.Queue.prototype.addBefore = function(block, ensure) { if (ensure === jasmine.undefined) { ensure = false; } this.blocks.unshift(block); this.ensured.unshift(ensure); }; jasmine.Queue.prototype.add = function(block, ensure) { if (ensure === jasmine.undefined) { ensure = false; } this.blocks.push(block); this.ensured.push(ensure); }; jasmine.Queue.prototype.insertNext = function(block, ensure) { if (ensure === jasmine.undefined) { ensure = false; } this.ensured.splice((this.index + this.offset + 1), 0, ensure); this.blocks.splice((this.index + this.offset + 1), 0, block); this.offset++; }; jasmine.Queue.prototype.start = function(onComplete) { this.running = true; this.onComplete = onComplete; this.next_(); }; jasmine.Queue.prototype.isRunning = function() { return this.running; }; jasmine.Queue.LOOP_DONT_RECURSE = true; jasmine.Queue.prototype.next_ = function() { var self = this; var goAgain = true; while (goAgain) { goAgain = false; if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) { var calledSynchronously = true; var completedSynchronously = false; var onComplete = function () { if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) { completedSynchronously = true; return; } if (self.blocks[self.index].abort) { self.abort = true; } self.offset = 0; self.index++; var now = new Date().getTime(); if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) { self.env.lastUpdate = now; self.env.setTimeout(function() { self.next_(); }, 0); } else { if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) { goAgain = true; } else { self.next_(); } } }; self.blocks[self.index].execute(onComplete); calledSynchronously = false; if (completedSynchronously) { onComplete(); } } else { self.running = false; if (self.onComplete) { self.onComplete(); } } } }; jasmine.Queue.prototype.results = function() { var results = new jasmine.NestedResults(); for (var i = 0; i < this.blocks.length; i++) { if (this.blocks[i].results) { results.addResult(this.blocks[i].results()); } } return results; }; /** * Runner * * @constructor * @param {jasmine.Env} env */ jasmine.Runner = function(env) { var self = this; self.env = env; self.queue = new jasmine.Queue(env); self.before_ = []; self.after_ = []; self.suites_ = []; }; jasmine.Runner.prototype.execute = function() { var self = this; if (self.env.reporter.reportRunnerStarting) { self.env.reporter.reportRunnerStarting(this); } self.queue.start(function () { self.finishCallback(); }); }; jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) { beforeEachFunction.typeName = 'beforeEach'; this.before_.splice(0,0,beforeEachFunction); }; jasmine.Runner.prototype.afterEach = function(afterEachFunction) { afterEachFunction.typeName = 'afterEach'; this.after_.splice(0,0,afterEachFunction); }; jasmine.Runner.prototype.finishCallback = function() { this.env.reporter.reportRunnerResults(this); }; jasmine.Runner.prototype.addSuite = function(suite) { this.suites_.push(suite); }; jasmine.Runner.prototype.add = function(block) { if (block instanceof jasmine.Suite) { this.addSuite(block); } this.queue.add(block); }; jasmine.Runner.prototype.specs = function () { var suites = this.suites(); var specs = []; for (var i = 0; i < suites.length; i++) { specs = specs.concat(suites[i].specs()); } return specs; }; jasmine.Runner.prototype.suites = function() { return this.suites_; }; jasmine.Runner.prototype.topLevelSuites = function() { var topLevelSuites = []; for (var i = 0; i < this.suites_.length; i++) { if (!this.suites_[i].parentSuite) { topLevelSuites.push(this.suites_[i]); } } return topLevelSuites; }; jasmine.Runner.prototype.results = function() { return this.queue.results(); }; /** * Internal representation of a Jasmine specification, or test. * * @constructor * @param {jasmine.Env} env * @param {jasmine.Suite} suite * @param {String} description */ jasmine.Spec = function(env, suite, description) { if (!env) { throw new Error('jasmine.Env() required'); } if (!suite) { throw new Error('jasmine.Suite() required'); } var spec = this; spec.id = env.nextSpecId ? env.nextSpecId() : null; spec.env = env; spec.suite = suite; spec.description = description; spec.queue = new jasmine.Queue(env); spec.afterCallbacks = []; spec.spies_ = []; spec.results_ = new jasmine.NestedResults(); spec.results_.description = description; spec.matchersClass = null; }; jasmine.Spec.prototype.getFullName = function() { return this.suite.getFullName() + ' ' + this.description + '.'; }; jasmine.Spec.prototype.results = function() { return this.results_; }; /** * All parameters are pretty-printed and concatenated together, then written to the spec's output. * * Be careful not to leave calls to jasmine.log in production code. */ jasmine.Spec.prototype.log = function() { return this.results_.log(arguments); }; jasmine.Spec.prototype.runs = function (func) { var block = new jasmine.Block(this.env, func, this); this.addToQueue(block); return this; }; jasmine.Spec.prototype.addToQueue = function (block) { if (this.queue.isRunning()) { this.queue.insertNext(block); } else { this.queue.add(block); } }; /** * @param {jasmine.ExpectationResult} result */ jasmine.Spec.prototype.addMatcherResult = function(result) { this.results_.addResult(result); }; jasmine.Spec.prototype.expect = function(actual) { var positive = new (this.getMatchersClass_())(this.env, actual, this); positive.not = new (this.getMatchersClass_())(this.env, actual, this, true); return positive; }; /** * Waits a fixed time period before moving to the next block. * * @deprecated Use waitsFor() instead * @param {Number} timeout milliseconds to wait */ jasmine.Spec.prototype.waits = function(timeout) { var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this); this.addToQueue(waitsFunc); return this; }; /** * Waits for the latchFunction to return true before proceeding to the next block. * * @param {Function} latchFunction * @param {String} optional_timeoutMessage * @param {Number} optional_timeout */ jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) { var latchFunction_ = null; var optional_timeoutMessage_ = null; var optional_timeout_ = null; for (var i = 0; i < arguments.length; i++) { var arg = arguments[i]; switch (typeof arg) { case 'function': latchFunction_ = arg; break; case 'string': optional_timeoutMessage_ = arg; break; case 'number': optional_timeout_ = arg; break; } } var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this); this.addToQueue(waitsForFunc); return this; }; jasmine.Spec.prototype.fail = function (e) { var expectationResult = new jasmine.ExpectationResult({ passed: false, message: e ? jasmine.util.formatException(e) : 'Exception', trace: { stack: e.stack } }); this.results_.addResult(expectationResult); }; jasmine.Spec.prototype.getMatchersClass_ = function() { return this.matchersClass || this.env.matchersClass; }; jasmine.Spec.prototype.addMatchers = function(matchersPrototype) { var parent = this.getMatchersClass_(); var newMatchersClass = function() { parent.apply(this, arguments); }; jasmine.util.inherit(newMatchersClass, parent); jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass); this.matchersClass = newMatchersClass; }; jasmine.Spec.prototype.finishCallback = function() { this.env.reporter.reportSpecResults(this); }; jasmine.Spec.prototype.finish = function(onComplete) { this.removeAllSpies(); this.finishCallback(); if (onComplete) { onComplete(); } }; jasmine.Spec.prototype.after = function(doAfter) { if (this.queue.isRunning()) { this.queue.add(new jasmine.Block(this.env, doAfter, this), true); } else { this.afterCallbacks.unshift(doAfter); } }; jasmine.Spec.prototype.execute = function(onComplete) { var spec = this; if (!spec.env.specFilter(spec)) { spec.results_.skipped = true; spec.finish(onComplete); return; } this.env.reporter.reportSpecStarting(this); spec.env.currentSpec = spec; spec.addBeforesAndAftersToQueue(); spec.queue.start(function () { spec.finish(onComplete); }); }; jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() { var runner = this.env.currentRunner(); var i; for (var suite = this.suite; suite; suite = suite.parentSuite) { for (i = 0; i < suite.before_.length; i++) { this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this)); } } for (i = 0; i < runner.before_.length; i++) { this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this)); } for (i = 0; i < this.afterCallbacks.length; i++) { this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true); } for (suite = this.suite; suite; suite = suite.parentSuite) { for (i = 0; i < suite.after_.length; i++) { this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true); } } for (i = 0; i < runner.after_.length; i++) { this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true); } }; jasmine.Spec.prototype.explodes = function() { throw 'explodes function should not have been called'; }; jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) { if (obj == jasmine.undefined) { throw "spyOn could not find an object to spy upon for " + methodName + "()"; } if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) { throw methodName + '() method does not exist'; } if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) { throw new Error(methodName + ' has already been spied upon'); } var spyObj = jasmine.createSpy(methodName); this.spies_.push(spyObj); spyObj.baseObj = obj; spyObj.methodName = methodName; spyObj.originalValue = obj[methodName]; obj[methodName] = spyObj; return spyObj; }; jasmine.Spec.prototype.removeAllSpies = function() { for (var i = 0; i < this.spies_.length; i++) { var spy = this.spies_[i]; spy.baseObj[spy.methodName] = spy.originalValue; } this.spies_ = []; }; /** * Internal representation of a Jasmine suite. * * @constructor * @param {jasmine.Env} env * @param {String} description * @param {Function} specDefinitions * @param {jasmine.Suite} parentSuite */ jasmine.Suite = function(env, description, specDefinitions, parentSuite) { var self = this; self.id = env.nextSuiteId ? env.nextSuiteId() : null; self.description = description; self.queue = new jasmine.Queue(env); self.parentSuite = parentSuite; self.env = env; self.before_ = []; self.after_ = []; self.children_ = []; self.suites_ = []; self.specs_ = []; }; jasmine.Suite.prototype.getFullName = function() { var fullName = this.description; for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) { fullName = parentSuite.description + ' ' + fullName; } return fullName; }; jasmine.Suite.prototype.finish = function(onComplete) { this.env.reporter.reportSuiteResults(this); this.finished = true; if (typeof(onComplete) == 'function') { onComplete(); } }; jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) { beforeEachFunction.typeName = 'beforeEach'; this.before_.unshift(beforeEachFunction); }; jasmine.Suite.prototype.afterEach = function(afterEachFunction) { afterEachFunction.typeName = 'afterEach'; this.after_.unshift(afterEachFunction); }; jasmine.Suite.prototype.results = function() { return this.queue.results(); }; jasmine.Suite.prototype.add = function(suiteOrSpec) { this.children_.push(suiteOrSpec); if (suiteOrSpec instanceof jasmine.Suite) { this.suites_.push(suiteOrSpec); this.env.currentRunner().addSuite(suiteOrSpec); } else { this.specs_.push(suiteOrSpec); } this.queue.add(suiteOrSpec); }; jasmine.Suite.prototype.specs = function() { return this.specs_; }; jasmine.Suite.prototype.suites = function() { return this.suites_; }; jasmine.Suite.prototype.children = function() { return this.children_; }; jasmine.Suite.prototype.execute = function(onComplete) { var self = this; this.queue.start(function () { self.finish(onComplete); }); }; jasmine.WaitsBlock = function(env, timeout, spec) { this.timeout = timeout; jasmine.Block.call(this, env, null, spec); }; jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block); jasmine.WaitsBlock.prototype.execute = function (onComplete) { if (jasmine.VERBOSE) { this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...'); } this.env.setTimeout(function () { onComplete(); }, this.timeout); }; /** * A block which waits for some condition to become true, with timeout. * * @constructor * @extends jasmine.Block * @param {jasmine.Env} env The Jasmine environment. * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true. * @param {Function} latchFunction A function which returns true when the desired condition has been met. * @param {String} message The message to display if the desired condition hasn't been met within the given time period. * @param {jasmine.Spec} spec The Jasmine spec. */ jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) { this.timeout = timeout || env.defaultTimeoutInterval; this.latchFunction = latchFunction; this.message = message; this.totalTimeSpentWaitingForLatch = 0; jasmine.Block.call(this, env, null, spec); }; jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block); jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10; jasmine.WaitsForBlock.prototype.execute = function(onComplete) { if (jasmine.VERBOSE) { this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen')); } var latchFunctionResult; try { latchFunctionResult = this.latchFunction.apply(this.spec); } catch (e) { this.spec.fail(e); onComplete(); return; } if (latchFunctionResult) { onComplete(); } else if (this.totalTimeSpentWaitingForLatch >= this.timeout) { var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen'); this.spec.fail({ name: 'timeout', message: message }); this.abort = true; onComplete(); } else { this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT; var self = this; this.env.setTimeout(function() { self.execute(onComplete); }, jasmine.WaitsForBlock.TIMEOUT_INCREMENT); } }; jasmine.version_= { "major": 1, "minor": 3, "build": 1, "revision": 1354556913 }; ================================================ FILE: tests/native.html ================================================ Jasmine Spec Runner ================================================ FILE: tests/spec/s-array.js ================================================ /* globals document */ var toStr = Object.prototype.toString; var canDistinguishSparseFromUndefined = 0 in [undefined]; // IE 6 - 8 have a bug where this returns false. var ifHasDenseUndefinedsIt = canDistinguishSparseFromUndefined ? it : xit; var undefinedIfNoSparseBug = canDistinguishSparseFromUndefined ? undefined : { valueOf: function () { return 0; } }; var hasStrictMode = (function () { 'use strict'; return !this; }()); var ifHasStrictIt = hasStrictMode ? it : xit; describe('Array', function () { var testSubject; beforeEach(function () { testSubject = [2, 3, undefinedIfNoSparseBug, true, 'hej', null, false, 0]; delete testSubject[1]; }); var createArrayLikeFromArray = function createArrayLikeFromArray(arr) { var o = {}; Array.prototype.forEach.call(arr, function (e, i) { o[i] = e; }); o.length = arr.length; return o; }; describe('#forEach()', function () { var expected, actual; beforeEach(function () { expected = { 0: 2, 2: undefinedIfNoSparseBug, 3: true, 4: 'hej', 5: null, 6: false, 7: 0 }; actual = {}; }); it('should pass the right parameters', function () { var callback = jasmine.createSpy('callback'); var array = ['1']; array.forEach(callback); expect(callback).toHaveBeenCalledWith('1', 0, array); }); it('should not affect elements added to the array after it has begun', function () { var arr = [1, 2, 3]; var i = 0; arr.forEach(function (a) { i += 1; arr.push(a + 3); }); expect(arr).toEqual([1, 2, 3, 4, 5, 6]); expect(i).toBe(3); }); it('should set the right context when given none', function () { var context; [1].forEach(function () { context = this; }); expect(context).toBe(function () { return this; }.call()); }); it('should iterate all', function () { testSubject.forEach(function (obj, index) { actual[index] = obj; }); expect(actual).toExactlyMatch(expected); }); it('should iterate all using a context', function () { var o = { a: actual }; testSubject.forEach(function (obj, index) { this.a[index] = obj; }, o); expect(actual).toExactlyMatch(expected); }); it('should iterate all in an array-like object', function () { var ts = createArrayLikeFromArray(testSubject); Array.prototype.forEach.call(ts, function (obj, index) { actual[index] = obj; }); expect(actual).toExactlyMatch(expected); }); it('should iterate all in an array-like object using a context', function () { var ts = createArrayLikeFromArray(testSubject); var o = { a: actual }; Array.prototype.forEach.call(ts, function (obj, index) { this.a[index] = obj; }, o); expect(actual).toExactlyMatch(expected); }); describe('strings', function () { var str = 'Hello, World!'; it('should iterate all in a string', function () { actual = []; Array.prototype.forEach.call(str, function (item, index) { actual[index] = item; }); expect(actual).toExactlyMatch(str.split('')); }); it('should iterate all in a string using a context', function () { actual = []; var o = { a: actual }; Array.prototype.forEach.call(str, function (item, index) { this.a[index] = item; }, o); expect(actual).toExactlyMatch(str.split('')); }); }); it('should have a boxed object as list argument of callback', function () { var listArg; Array.prototype.forEach.call('foo', function (item, index, list) { listArg = list; }); expect(typeof listArg).toBe('object'); expect(toStr.call(listArg)).toBe('[object String]'); }); ifHasStrictIt('does not autobox the content in strict mode', function () { var context; [1].forEach(function () { 'use strict'; context = this; }, 'x'); expect(typeof context).toBe('string'); }); }); describe('#some()', function () { var actual, expected, numberOfRuns; beforeEach(function () { expected = { 0: 2, 2: undefinedIfNoSparseBug, 3: true }; actual = {}; numberOfRuns = 0; }); it('should pass the correct values along to the callback', function () { var callback = jasmine.createSpy('callback'); var array = ['1']; array.some(callback); expect(callback).toHaveBeenCalledWith('1', 0, array); }); it('should not affect elements added to the array after it has begun', function () { var arr = [1, 2, 3]; var i = 0; arr.some(function (a) { i += 1; arr.push(a + 3); return i > 3; }); expect(arr).toEqual([1, 2, 3, 4, 5, 6]); expect(i).toBe(3); }); it('should set the right context when given none', function () { /* eslint-disable array-callback-return */ var context; [1].some(function () { context = this; }); expect(context).toBe(function () { return this; }.call()); }); it('should return false if it runs to the end', function () { /* eslint-disable array-callback-return */ actual = testSubject.some(function () {}); expect(actual).toBeFalsy(); }); it('should return true if it is stopped somewhere', function () { actual = testSubject.some(function () { return true; }); expect(actual).toBeTruthy(); }); it('should return false if there are no elements', function () { actual = [].some(function () { return true; }); expect(actual).toBeFalsy(); }); it('should stop after 3 elements', function () { testSubject.some(function (obj, index) { actual[index] = obj; numberOfRuns += 1; return numberOfRuns === 3; }); expect(actual).toExactlyMatch(expected); }); it('should stop after 3 elements using a context', function () { var o = { a: actual }; testSubject.some(function (obj, index) { this.a[index] = obj; numberOfRuns += 1; return numberOfRuns === 3; }, o); expect(actual).toExactlyMatch(expected); }); it('should stop after 3 elements in an array-like object', function () { var ts = createArrayLikeFromArray(testSubject); Array.prototype.some.call(ts, function (obj, index) { actual[index] = obj; numberOfRuns += 1; return numberOfRuns === 3; }); expect(actual).toExactlyMatch(expected); }); it('should stop after 3 elements in an array-like object using a context', function () { var ts = createArrayLikeFromArray(testSubject); var o = { a: actual }; Array.prototype.some.call(ts, function (obj, index) { this.a[index] = obj; numberOfRuns += 1; return numberOfRuns === 3; }, o); expect(actual).toExactlyMatch(expected); }); it('should have a boxed object as list argument of callback', function () { var listArg; Array.prototype.some.call('foo', function (item, index, list) { listArg = list; }); expect(typeof listArg).toBe('object'); expect(toStr.call(listArg)).toBe('[object String]'); }); }); describe('#every()', function () { var actual, expected, numberOfRuns; beforeEach(function () { expected = { 0: 2, 2: undefinedIfNoSparseBug, 3: true }; actual = {}; numberOfRuns = 0; }); it('should pass the correct values along to the callback', function () { var callback = jasmine.createSpy('callback'); var array = ['1']; array.every(callback); expect(callback).toHaveBeenCalledWith('1', 0, array); }); it('should not affect elements added to the array after it has begun', function () { var arr = [1, 2, 3]; var i = 0; arr.every(function (a) { i += 1; arr.push(a + 3); return i <= 3; }); expect(arr).toEqual([1, 2, 3, 4, 5, 6]); expect(i).toBe(3); }); it('should set the right context when given none', function () { /* eslint-disable array-callback-return */ var context; [1].every(function () { context = this; }); expect(context).toBe(function () { return this; }.call()); }); it('should return true if the array is empty', function () { actual = [].every(function () { return true; }); expect(actual).toBeTruthy(); actual = [].every(function () { return false; }); expect(actual).toBeTruthy(); }); it('should return true if it runs to the end', function () { actual = [1, 2, 3].every(function () { return true; }); expect(actual).toBeTruthy(); }); it('should return false if it is stopped before the end', function () { actual = [1, 2, 3].every(function () { return false; }); expect(actual).toBeFalsy(); }); it('should return after 3 elements', function () { testSubject.every(function (obj, index) { actual[index] = obj; numberOfRuns += 1; return numberOfRuns !== 3; }); expect(actual).toExactlyMatch(expected); }); it('should stop after 3 elements using a context', function () { var o = { a: actual }; testSubject.every(function (obj, index) { this.a[index] = obj; numberOfRuns += 1; return numberOfRuns !== 3; }, o); expect(actual).toExactlyMatch(expected); }); it('should stop after 3 elements in an array-like object', function () { var ts = createArrayLikeFromArray(testSubject); Array.prototype.every.call(ts, function (obj, index) { actual[index] = obj; numberOfRuns += 1; return numberOfRuns !== 3; }); expect(actual).toExactlyMatch(expected); }); it('should stop after 3 elements in an array-like object using a context', function () { var ts = createArrayLikeFromArray(testSubject); var o = { a: actual }; Array.prototype.every.call(ts, function (obj, index) { this.a[index] = obj; numberOfRuns += 1; return numberOfRuns !== 3; }, o); expect(actual).toExactlyMatch(expected); }); it('should have a boxed object as list argument of callback', function () { var listArg; Array.prototype.every.call('foo', function (item, index, list) { listArg = list; }); expect(typeof listArg).toBe('object'); expect(toStr.call(listArg)).toBe('[object String]'); }); }); describe('#indexOf()', function () { 'use strict'; var actual, expected; beforeEach(function () { testSubject = [2, 3, undefinedIfNoSparseBug, true, 'hej', null, 2, false, 0]; delete testSubject[1]; }); it('should find the element', function () { expected = 4; actual = testSubject.indexOf('hej'); expect(actual).toBe(expected); }); it('should not find the element', function () { expected = -1; actual = testSubject.indexOf('mus'); expect(actual).toBe(expected); }); ifHasDenseUndefinedsIt('should find undefined as well', function () { expected = -1; actual = testSubject.indexOf(undefined); expect(actual).not.toBe(expected); }); ifHasDenseUndefinedsIt('should skip unset indexes', function () { expected = 2; actual = testSubject.indexOf(undefined); expect(actual).toBe(expected); }); it('should use a strict test', function () { actual = testSubject.indexOf(null); expect(actual).toBe(5); actual = testSubject.indexOf('2'); expect(actual).toBe(-1); }); it('should skip the first if fromIndex is set', function () { expect(testSubject.indexOf(2, 2)).toBe(6); expect(testSubject.indexOf(2, 0)).toBe(0); expect(testSubject.indexOf(2, 6)).toBe(6); }); it('should work with negative fromIndex', function () { expect(testSubject.indexOf(2, -3)).toBe(6); expect(testSubject.indexOf(2, -9)).toBe(0); }); it('should work with fromIndex being greater than the length', function () { expect(testSubject.indexOf(0, 20)).toBe(-1); }); it('should work with fromIndex being negative and greater than the length', function () { expect(testSubject.indexOf('hej', -20)).toBe(4); }); describe('Array-like', function ArrayLike() { var indexOf = Array.prototype.indexOf; var testAL; beforeEach(function beforeEach() { testAL = {}; testSubject = [2, 3, undefinedIfNoSparseBug, true, 'hej', null, 2, false, 0]; testSubject.forEach(function (o, i) { testAL[i] = o; }); testAL.length = testSubject.length; }); it('should find the element (array-like)', function () { expected = 4; actual = indexOf.call(testAL, 'hej'); expect(actual).toBe(expected); }); it('should not find the element (array-like)', function () { expected = -1; actual = indexOf.call(testAL, 'mus'); expect(actual).toBe(expected); }); ifHasDenseUndefinedsIt('should find undefined as well (array-like)', function () { expected = -1; actual = indexOf.call(testAL, undefined); expect(actual).not.toBe(expected); }); ifHasDenseUndefinedsIt('should skip unset indexes (array-like)', function () { expected = 2; actual = indexOf.call(testAL, undefined); expect(actual).toBe(expected); }); it('should use a strict test (array-like)', function () { actual = Array.prototype.indexOf.call(testAL, null); expect(actual).toBe(5); actual = Array.prototype.indexOf.call(testAL, '2'); expect(actual).toBe(-1); }); it('should skip the first if fromIndex is set (array-like)', function () { expect(indexOf.call(testAL, 2, 2)).toBe(6); expect(indexOf.call(testAL, 2, 0)).toBe(0); expect(indexOf.call(testAL, 2, 6)).toBe(6); }); it('should work with negative fromIndex (array-like)', function () { expect(indexOf.call(testAL, 2, -3)).toBe(6); expect(indexOf.call(testAL, 2, -9)).toBe(0); }); it('should work with fromIndex being greater than the length (array-like)', function () { expect(indexOf.call(testAL, 0, 20)).toBe(-1); }); it('should work with fromIndex being negative and greater than the length (array-like)', function () { expect(indexOf.call(testAL, 'hej', -20)).toBe(4); }); }); }); describe('#lastIndexOf()', function () { 'use strict'; var actual, expected; beforeEach(function () { testSubject = [2, 3, undefinedIfNoSparseBug, true, 'hej', null, 2, 3, false, 0]; delete testSubject[1]; delete testSubject[7]; }); describe('Array', function () { it('should find the element', function () { expected = 4; actual = testSubject.lastIndexOf('hej'); expect(actual).toBe(expected); }); it('should not find the element', function () { expected = -1; actual = testSubject.lastIndexOf('mus'); expect(actual).toBe(expected); }); ifHasDenseUndefinedsIt('should find undefined as well', function () { expected = -1; actual = testSubject.lastIndexOf(undefined); expect(actual).not.toBe(expected); }); ifHasDenseUndefinedsIt('should skip unset indexes', function () { expected = 2; actual = testSubject.lastIndexOf(undefined); expect(actual).toBe(expected); }); it('should use a strict test', function () { actual = testSubject.lastIndexOf(null); expect(actual).toBe(5); actual = testSubject.lastIndexOf('2'); expect(actual).toBe(-1); }); it('should skip the first if fromIndex is set', function () { expect(testSubject.lastIndexOf(2, 2)).toBe(0); expect(testSubject.lastIndexOf(2, 0)).toBe(0); expect(testSubject.lastIndexOf(2, 6)).toBe(6); }); it('should work with negative fromIndex', function () { expect(testSubject.lastIndexOf(2, -3)).toBe(6); expect(testSubject.lastIndexOf(2, -9)).toBe(0); }); it('should work with fromIndex being greater than the length', function () { expect(testSubject.lastIndexOf(2, 20)).toBe(6); }); it('should work with fromIndex being negative and greater than the length', function () { expect(testSubject.lastIndexOf(2, -20)).toBe(-1); }); }); describe('Array like', function () { var lastIndexOf = Array.prototype.lastIndexOf; var testAL; beforeEach(function () { testAL = {}; testSubject.forEach(function (o, i) { testAL[i] = o; }); testAL.length = testSubject.length; }); it('should find the element (array-like)', function () { expected = 4; actual = lastIndexOf.call(testAL, 'hej'); expect(actual).toBe(expected); }); it('should not find the element (array-like)', function () { expected = -1; actual = lastIndexOf.call(testAL, 'mus'); expect(actual).toBe(expected); }); ifHasDenseUndefinedsIt('should find undefined as well (array-like)', function () { expected = -1; actual = lastIndexOf.call(testAL, undefined); expect(actual).not.toBe(expected); }); ifHasDenseUndefinedsIt('should skip unset indexes (array-like)', function () { expected = 2; actual = lastIndexOf.call(testAL, undefined); expect(actual).toBe(expected); }); it('should use a strict test (array-like)', function () { actual = lastIndexOf.call(testAL, null); expect(actual).toBe(5); actual = lastIndexOf.call(testAL, '2'); expect(actual).toBe(-1); }); it('should skip the first if fromIndex is set', function () { expect(lastIndexOf.call(testAL, 2, 2)).toBe(0); expect(lastIndexOf.call(testAL, 2, 0)).toBe(0); expect(lastIndexOf.call(testAL, 2, 6)).toBe(6); }); it('should work with negative fromIndex', function () { expect(lastIndexOf.call(testAL, 2, -3)).toBe(6); expect(lastIndexOf.call(testAL, 2, -9)).toBe(0); }); it('should work with fromIndex being greater than the length', function () { expect(lastIndexOf.call(testAL, 2, 20)).toBe(6); }); it('should work with fromIndex being negative and greater than the length', function () { expect(lastIndexOf.call(testAL, 2, -20)).toBe(-1); }); }); }); describe('#filter()', function () { var filteredArray; var callback = function callback(o, i) { return i !== 3 && i !== 5; }; beforeEach(function () { testSubject = [2, 3, undefinedIfNoSparseBug, true, 'hej', 3, null, false, 0]; delete testSubject[1]; filteredArray = [2, undefinedIfNoSparseBug, 'hej', null, false, 0]; }); describe('Array object', function () { it('should call the callback with the proper arguments', function () { var predicate = jasmine.createSpy('predicate'); var arr = ['1']; arr.filter(predicate); expect(predicate).toHaveBeenCalledWith('1', 0, arr); }); it('should not affect elements added to the array after it has begun', function () { var arr = [1, 2, 3]; var i = 0; arr.filter(function (a) { i += 1; if (i <= 4) { arr.push(a + 3); } return true; }); expect(arr).toEqual([1, 2, 3, 4, 5, 6]); expect(i).toBe(3); }); ifHasDenseUndefinedsIt('should skip unset values', function () { var passedValues = {}; testSubject = [1, 2, 3, 4]; delete testSubject[1]; testSubject.filter(function (o, i) { passedValues[i] = o; return true; }); expect(passedValues).toExactlyMatch(testSubject); }); it('should pass the right context to the filter', function () { var passedValues = {}; testSubject = [1, 2, 3, 4]; delete testSubject[1]; testSubject.filter(function (o, i) { this[i] = o; return true; }, passedValues); expect(passedValues).toExactlyMatch(testSubject); }); it('should set the right context when given none', function () { /* eslint-disable array-callback-return */ var context; [1].filter(function () { context = this; }); expect(context).toBe(function () { return this; }.call()); }); it('should remove only the values for which the callback returns false', function () { var result = testSubject.filter(callback); expect(result).toExactlyMatch(filteredArray); }); it('should leave the original array untouched', function () { var copy = testSubject.slice(); expect(copy).toNotBe(testSubject); testSubject.filter(callback); expect(testSubject).toExactlyMatch(copy); }); it('should not be affected by same-index mutation', function () { var results = [1, 2, 3].filter(function (value, index, array) { array[index] = 'a'; // eslint-disable-line no-param-reassign return true; }); expect(results).toEqual([1, 2, 3]); }); }); describe('Array like', function () { beforeEach(function () { testSubject = createArrayLikeFromArray(testSubject); }); it('should call the predicate with the proper arguments', function () { var predicate = jasmine.createSpy('predicate'); var arr = createArrayLikeFromArray(['1']); Array.prototype.filter.call(arr, predicate); expect(predicate).toHaveBeenCalledWith('1', 0, arr); }); it('should not affect elements added to the array after it has begun', function () { var arr = createArrayLikeFromArray([1, 2, 3]); var i = 0; Array.prototype.filter.call(arr, function (a) { i += 1; if (i <= 4) { arr[i + 2] = a + 3; arr.length += 1; } return true; }); expect(Array.prototype.slice.call(arr)).toEqual([1, 2, 3, 4, 5, 6]); expect(i).toBe(3); }); it('should skip non-set values', function () { var passedValues = createArrayLikeFromArray([]); testSubject = createArrayLikeFromArray([1, 2, 3, 4]); delete testSubject[1]; Array.prototype.filter.call(testSubject, function (o, i) { passedValues[i] = o; passedValues.length = i + 1; return true; }); expect(passedValues).toEqual(testSubject); }); it('should set the right context when given none', function () { var context; Array.prototype.filter.call(createArrayLikeFromArray([1]), function () { context = this; }, undefined); expect(context).toBe(function () { return this; }.call()); }); it('should pass the right context to the filter', function () { var passedValues = {}; testSubject = createArrayLikeFromArray([1, 2, 3, 4]); delete testSubject[1]; Array.prototype.filter.call(testSubject, function (o, i) { this[i] = o; this.length = i + 1; return true; }, passedValues); expect(passedValues).toEqual(testSubject); }); it('should remove only the values for which the callback returns false', function () { var result = Array.prototype.filter.call(testSubject, callback); expect(result).toExactlyMatch(filteredArray); }); it('should leave the original array untouched', function () { var copy = createArrayLikeFromArray(testSubject); Array.prototype.filter.call(testSubject, callback); expect(testSubject).toExactlyMatch(copy); }); }); it('should have a boxed object as list argument of callback', function () { var actual; Array.prototype.filter.call('foo', function (item, index, list) { actual = list; }); expect(typeof actual).toBe('object'); expect(toStr.call(actual)).toBe('[object String]'); }); }); describe('#map()', function () { var callback; beforeEach(function () { var i = 0; callback = function () { return i++; }; }); describe('Array object', function () { it('should call mapper with the right parameters', function () { var mapper = jasmine.createSpy('mapper'); var array = [1]; array.map(mapper); expect(mapper).toHaveBeenCalledWith(1, 0, array); }); it('should set the context correctly', function () { var context = {}; testSubject.map(function (o, i) { this[i] = o; }, context); expect(context).toExactlyMatch(testSubject); }); it('should set the right context when given none', function () { var context; [1].map(function () { context = this; }); expect(context).toBe(function () { return this; }.call()); }); it('should not change the array it is called on', function () { var copy = testSubject.slice(); testSubject.map(callback); expect(testSubject).toExactlyMatch(copy); }); it('should only run for the number of objects in the array when it started', function () { var arr = [1, 2, 3]; var i = 0; arr.map(function (o) { arr.push(o + 3); i += 1; return o; }); expect(arr).toExactlyMatch([1, 2, 3, 4, 5, 6]); expect(i).toBe(3); }); it('should properly translate the values as according to the callback', function () { var result = testSubject.map(callback); var expected = [0, 0, 1, 2, 3, 4, 5, 6]; delete expected[1]; expect(result).toExactlyMatch(expected); }); it('should skip non-existing values', function () { var array = [1, 2, 3, 4]; var i = 0; delete array[2]; array.map(function () { i += 1; }); expect(i).toBe(3); }); }); describe('Array-like', function () { beforeEach(function () { testSubject = createArrayLikeFromArray(testSubject); }); it('should call mapper with the right parameters', function () { var mapper = jasmine.createSpy('mapper'); var array = createArrayLikeFromArray([1]); Array.prototype.map.call(array, mapper); expect(mapper).toHaveBeenCalledWith(1, 0, array); }); it('should set the context correctly', function () { var context = {}; Array.prototype.map.call(testSubject, function (o, i) { this[i] = o; this.length = i + 1; }, context); expect(context).toEqual(testSubject); }); it('should set the right context when given none', function () { var context; Array.prototype.map.call(createArrayLikeFromArray([1]), function () { context = this; }); expect(context).toBe(function () { return this; }.call()); }); it('should not change the array it is called on', function () { var copy = createArrayLikeFromArray(testSubject); Array.prototype.map.call(testSubject, callback); expect(testSubject).toExactlyMatch(copy); }); it('should only run for the number of objects in the array when it started', function () { var arr = createArrayLikeFromArray([1, 2, 3]); var i = 0; Array.prototype.map.call(arr, function (o) { Array.prototype.push.call(arr, o + 3); i += 1; return o; }); expect(Array.prototype.slice.call(arr)).toEqual([1, 2, 3, 4, 5, 6]); expect(i).toBe(3); }); it('should properly translate the values as according to the callback', function () { var result = Array.prototype.map.call(testSubject, callback); var expected = [0, 0, 1, 2, 3, 4, 5, 6]; delete expected[1]; expect(result).toExactlyMatch(expected); }); it('should skip non-existing values', function () { var array = createArrayLikeFromArray([1, 2, 3, 4]); var i = 0; delete array[2]; Array.prototype.map.call(array, function () { i += 1; }); expect(i).toBe(3); }); }); it('should have a boxed object as list argument of callback', function () { var actual; Array.prototype.map.call('foo', function (item, index, list) { actual = list; }); expect(typeof actual).toBe('object'); expect(toStr.call(actual)).toBe('[object String]'); }); }); describe('#reduce()', function () { beforeEach(function () { testSubject = [1, 2, 3]; }); describe('Array', function () { it('should pass the correct arguments to the callback', function () { var spy = jasmine.createSpy().andReturn(0); testSubject.reduce(spy); expect(spy.calls[0].args).toExactlyMatch([1, 2, 1, testSubject]); }); it('should start with the right initialValue', function () { var spy = jasmine.createSpy().andReturn(0); testSubject.reduce(spy, 0); expect(spy.calls[0].args).toExactlyMatch([0, 1, 0, testSubject]); }); it('should not affect elements added to the array after it has begun', function () { var arr = [1, 2, 3]; var i = 0; arr.reduce(function (a, b) { i += 1; if (i <= 4) { arr.push(a + 3); } return b; }); expect(arr).toEqual([1, 2, 3, 4, 5]); expect(i).toBe(2); }); it('should work as expected for empty arrays', function () { var spy = jasmine.createSpy(); expect(function () { [].reduce(spy); }).toThrow(); expect(spy).not.toHaveBeenCalled(); }); it('should throw correctly if no callback is given', function () { expect(function () { testSubject.reduce(); }).toThrow(); }); it('should return the expected result', function () { expect(testSubject.reduce(function (a, b) { return String(a || '') + String(b || ''); })).toBe(testSubject.join('')); }); it('should not directly affect the passed array', function () { var copy = testSubject.slice(); testSubject.reduce(function (a, b) { return a + b; }); expect(testSubject).toEqual(copy); }); it('should skip non-set values', function () { delete testSubject[1]; var visited = {}; testSubject.reduce(function (a, b) { if (a) { visited[a] = true; } if (b) { visited[b] = true; } return 0; }); expect(visited).toEqual({ 1: true, 3: true }); }); it('should have the right length', function () { expect(testSubject.reduce.length).toBe(1); }); }); describe('Array-like objects', function () { beforeEach(function () { testSubject = createArrayLikeFromArray(testSubject); testSubject.reduce = Array.prototype.reduce; }); it('should pass the correct arguments to the callback', function () { var spy = jasmine.createSpy().andReturn(0); testSubject.reduce(spy); expect(spy.calls[0].args).toExactlyMatch([1, 2, 1, testSubject]); }); it('should start with the right initialValue', function () { var spy = jasmine.createSpy().andReturn(0); testSubject.reduce(spy, 0); expect(spy.calls[0].args).toExactlyMatch([0, 1, 0, testSubject]); }); it('should not affect elements added to the array after it has begun', function () { var arr = createArrayLikeFromArray([1, 2, 3]); var i = 0; Array.prototype.reduce.call(arr, function (a, b) { i += 1; if (i <= 4) { arr[i + 2] = a + 3; } return b; }); expect(arr).toEqual({ 0: 1, 1: 2, 2: 3, 3: 4, 4: 5, length: 3 }); expect(i).toBe(2); }); it('should work as expected for empty arrays', function () { var spy = jasmine.createSpy(); expect(function () { Array.prototype.reduce.call({ length: 0 }, spy); }).toThrow(); expect(spy).not.toHaveBeenCalled(); }); it('should throw correctly if no callback is given', function () { expect(function () { testSubject.reduce(); }).toThrow(); }); it('should return the expected result', function () { expect(testSubject.reduce(function (a, b) { return String(a || '') + String(b || ''); })).toBe('123'); }); it('should not directly affect the passed array', function () { var copy = createArrayLikeFromArray(testSubject); testSubject.reduce(function (a, b) { return a + b; }); delete testSubject.reduce; expect(testSubject).toEqual(copy); }); it('should skip non-set values', function () { delete testSubject[1]; var visited = {}; testSubject.reduce(function (a, b) { if (a) { visited[a] = true; } if (b) { visited[b] = true; } return 0; }); expect(visited).toEqual({ 1: true, 3: true }); }); it('should have the right length', function () { expect(testSubject.reduce.length).toBe(1); }); }); it('should have a boxed object as list argument of callback', function () { var actual; Array.prototype.reduce.call('foo', function (accumulator, item, index, list) { actual = list; }); expect(typeof actual).toBe('object'); expect(toStr.call(actual)).toBe('[object String]'); }); }); describe('#reduceRight()', function () { beforeEach(function () { testSubject = [1, 2, 3]; }); describe('Array', function () { it('should pass the correct arguments to the callback', function () { var spy = jasmine.createSpy().andReturn(0); testSubject.reduceRight(spy); expect(spy.calls[0].args).toExactlyMatch([3, 2, 1, testSubject]); }); it('should start with the right initialValue', function () { var spy = jasmine.createSpy().andReturn(0); testSubject.reduceRight(spy, 0); expect(spy.calls[0].args).toExactlyMatch([0, 3, 2, testSubject]); }); it('should not affect elements added to the array after it has begun', function () { var arr = [1, 2, 3]; var i = 0; arr.reduceRight(function (a, b) { i += 1; if (i <= 4) { arr.push(a + 3); } return b; }); expect(arr).toEqual([1, 2, 3, 6, 5]); expect(i).toBe(2); }); it('should work as expected for empty arrays', function () { var spy = jasmine.createSpy(); expect(function () { [].reduceRight(spy); }).toThrow(); expect(spy).not.toHaveBeenCalled(); }); it('should work as expected for empty arrays with an initial value', function () { var spy = jasmine.createSpy(); var result; result = [].reduceRight(spy, ''); expect(spy).not.toHaveBeenCalled(); expect(result).toBe(''); }); it('should throw correctly if no callback is given', function () { expect(function () { testSubject.reduceRight(); }).toThrow(); }); it('should return the expected result', function () { expect(testSubject.reduceRight(function (a, b) { return String(a || '') + String(b || ''); })).toBe('321'); }); it('should not directly affect the passed array', function () { var copy = testSubject.slice(); testSubject.reduceRight(function (a, b) { return a + b; }); expect(testSubject).toEqual(copy); }); it('should skip non-set values', function () { delete testSubject[1]; var visited = {}; testSubject.reduceRight(function (a, b) { if (a) { visited[a] = true; } if (b) { visited[b] = true; } return 0; }); expect(visited).toEqual({ 1: true, 3: true }); }); it('should have the right length', function () { expect(testSubject.reduceRight.length).toBe(1); }); }); describe('Array-like objects', function () { beforeEach(function () { testSubject = createArrayLikeFromArray(testSubject); testSubject.reduceRight = Array.prototype.reduceRight; }); it('should pass the correct arguments to the callback', function () { var spy = jasmine.createSpy().andReturn(0); testSubject.reduceRight(spy); expect(spy.calls[0].args).toExactlyMatch([3, 2, 1, testSubject]); }); it('should start with the right initialValue', function () { var spy = jasmine.createSpy().andReturn(0); testSubject.reduceRight(spy, 0); expect(spy.calls[0].args).toExactlyMatch([0, 3, 2, testSubject]); }); it('should not affect elements added to the array after it has begun', function () { var arr = createArrayLikeFromArray([1, 2, 3]); var i = 0; Array.prototype.reduceRight.call(arr, function (a, b) { i += 1; if (i <= 4) { arr[i + 2] = a + 3; } return b; }); expect(arr).toEqual({ 0: 1, 1: 2, 2: 3, 3: 6, 4: 5, length: 3 // does not get updated on property assignment }); expect(i).toBe(2); }); it('should work as expected for empty arrays', function () { var spy = jasmine.createSpy(); expect(function () { Array.prototype.reduceRight.call({ length: 0 }, spy); }).toThrow(); expect(spy).not.toHaveBeenCalled(); }); it('should throw correctly if no callback is given', function () { expect(function () { testSubject.reduceRight(); }).toThrow(); }); it('should return the expected result', function () { expect(testSubject.reduceRight(function (a, b) { return String(a || '') + String(b || ''); })).toBe('321'); }); it('should not directly affect the passed array', function () { var copy = createArrayLikeFromArray(testSubject); testSubject.reduceRight(function (a, b) { return a + b; }); delete testSubject.reduceRight; expect(testSubject).toEqual(copy); }); it('should skip non-set values', function () { delete testSubject[1]; var visited = {}; testSubject.reduceRight(function (a, b) { if (a) { visited[a] = true; } if (b) { visited[b] = true; } return 0; }); expect(visited).toEqual({ 1: true, 3: true }); }); it('should have the right length', function () { expect(testSubject.reduceRight.length).toBe(1); }); }); it('should have a boxed object as list argument of callback', function () { var actual; Array.prototype.reduceRight.call('foo', function (accumulator, item, index, list) { actual = list; }); expect(typeof actual).toBe('object'); expect(toStr.call(actual)).toBe('[object String]'); }); }); describe('.isArray()', function () { it('should be true for Array', function () { expect(Array.isArray([])).toBe(true); }); it('should be false for primitives', function () { var primitives = [ 'foo', true, false, 42, 0, -0, NaN, Infinity, -Infinity ]; primitives.forEach(function (v) { expect(Array.isArray(v)).toBe(false); }); }); it('should fail for other objects', function () { var objects = [ {}, /foo/, arguments ]; if (Object.create) { objects.push(Object.create(null)); } objects.forEach(function (v) { expect(Array.isArray(v)).toBe(false); }); }); if (typeof document !== 'undefined') { it('should be false for an HTML element', function () { var el = document.getElementsByTagName('div'); expect(Array.isArray(el)).toBe(false); }); } }); describe('#shift()', function () { it('works on arrays', function () { var arr = [1, 2]; var result = arr.shift(); expect(result).toBe(1); expect(arr.length).toBe(1); expect(Object.prototype.hasOwnProperty.call(arr, 0)).toBe(true); expect(Object.prototype.hasOwnProperty.call(arr, 1)).toBe(false); expect(arr[0]).toBe(2); expect(arr[1]).toBeUndefined(); }); it('is generic', function () { var obj = { 0: 1, 1: 2, length: 2 }; var result = Array.prototype.shift.call(obj); expect(result).toBe(1); expect(obj.length).toBe(1); expect(Object.prototype.hasOwnProperty.call(obj, 0)).toBe(true); expect(Object.prototype.hasOwnProperty.call(obj, 1)).toBe(false); expect(obj[0]).toBe(2); expect(obj[1]).toBeUndefined(); }); }); describe('#unshift()', function () { it('should return length', function () { expect([].unshift(0)).toBe(1); }); it('works on arrays', function () { var arr = [1]; var result = arr.unshift(undefined); expect(result).toBe(2); expect(arr.length).toBe(2); expect(Object.prototype.hasOwnProperty.call(arr, 0)).toBe(true); expect(Object.prototype.hasOwnProperty.call(arr, 1)).toBe(true); expect(arr[0]).toBeUndefined(); expect(arr[1]).toBe(1); }); it('is generic', function () { var obj = { 0: 1, length: 1 }; var result = Array.prototype.unshift.call(obj, undefined); expect(result).toBe(2); expect(obj.length).toBe(2); expect(Object.prototype.hasOwnProperty.call(obj, 0)).toBe(true); expect(Object.prototype.hasOwnProperty.call(obj, 1)).toBe(true); expect(obj[0]).toBeUndefined(); expect(obj[1]).toBe(1); }); }); describe('#splice()', function () { var b = ['b']; var a = [1, 'a', b]; var test; var makeArray = function (l, givenPrefix) { var prefix = givenPrefix || ''; var length = l; var arr = []; while (length--) { arr.unshift(prefix + Array(length + 1).join(' ') + length); } return arr; }; beforeEach(function () { test = a.slice(0); }); it('has the right length', function () { expect(Array.prototype.splice.length).toBe(2); }); /* This test is disabled, because ES6 normalizes actual * browser behavior, contradicting ES5. */ xit('treats undefined deleteCount as 0', function () { expect(test.splice(0).length).toBe(0); expect(test.splice(0)).toEqual(test.splice(0, 0)); }); // ES6 introduced a proper default value it('defaults deleteCount to length - start if there is only 1 argument', function () { expect([0, 1, 2].splice(0).length).toBe(3); expect([0, 1, 2].splice(1).length).toBe(2); }); it('basic implementation test 1', function () { expect(test.splice(0, 0)).toEqual([]); }); it('basic implementation test 2', function () { test.splice(0, 2); expect(test).toEqual([b]); }); it('should return right result 1', function () { var array = []; array.splice(0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20); array.splice(1, 0, 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24', 'F25', 'F26'); array.splice(5, 0, 'XXX'); expect(array).toEqual([1, 'F1', 'F2', 'F3', 'F4', 'XXX', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24', 'F25', 'F26', 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]); }); it('should return right result 2', function () { var array = makeArray(6); array.splice(array.length - 1, 1, ''); array.splice(0, 1, 1, 2, 3, 4); array.splice(0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45); array.splice(4, 0, '99999999999999'); expect(array).toEqual([1, 2, 3, 4, '99999999999999', 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 1, 2, 3, 4, ' 1', ' 2', ' 3', ' 4', '']); }); it('should return right result 3', function () { var array = [1, 2, 3]; array.splice(0, array.length); array.splice(0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); array.splice(1, 1, 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24', 'F25', 'F26'); array.splice(5, 1, 'YYY', 'XXX'); array.splice(0, 1); array.splice(0, 2); array.pop(); array.push.apply(array, makeArray(10, '-')); array.splice(array.length - 2, 10); array.splice(); array.splice(1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9); array.splice(1, 1, 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24', 'F25', 'F26', 1, 23, 4, 5, 6, 7, 8); array.splice(30, 10); array.splice(30, 1); array.splice(30, 0); array.splice(2, 5, 1, 2, 3, 'P', 'LLL', 'CCC', 'YYY', 'XXX'); array.push(1, 2, 3, 4, 5, 6); array.splice(1, 6, 1, 2, 3, 4, 5, 6, 7, 8, 9, 4, 5, 6, 7, 8, 9); array.splice(3, 7); array.unshift(7, 8, 9, 10, 11); array.pop(); array.splice(5, 2); array.pop(); array.unshift.apply(array, makeArray(8, '~')); array.pop(); array.splice(3, 1, 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24', 'F25', 'F26', 1, 23, 4, 5, 6, 7, 8); array.splice(4, 5, 'P', 'LLL', 'CCC', 'YYY', 'XXX'); expect(array).toEqual(['~0', '~ 1', '~ 2', 'F1', 'P', 'LLL', 'CCC', 'YYY', 'XXX', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24', 'F25', 'F26', 1, 23, 4, 5, 6, 7, 8, '~ 4', '~ 5', '~ 6', '~ 7', 7, 8, 9, 10, 11, 2, 4, 5, 6, 7, 8, 9, 'CCC', 'YYY', 'XXX', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24', 'F25', 'F26', 1, 23, 4, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 'YYY', 'XXX', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'F20', 'F21', 'F22', 'F23', 'F24', 'F25', 'F26', 3, 4, 5, 6, 7, 8, 9, '-0', '- 1', '- 2', '- 3', '- 4', '- 5', '- 6', '- 7', 1, 2, 3]); }); it('should do nothing if method called with no arguments', function () { expect(test.splice()).toEqual([]); expect(test).toEqual(a); }); it('should set first argument to 0 if first argument is set but undefined', function () { var test2 = test.slice(0); expect(test.splice(void 0, 2)).toEqual(test2.splice(0, 2)); expect(test).toEqual(test2); }); it('should work with objects - adding 1', function () { var obj = {}; Array.prototype.splice.call(obj, 0, 0, 1, 2, 3); expect(obj.length).toBe(3); }); it('should work with objects - adding 2', function () { var obj = { 0: 1, length: 1 }; Array.prototype.splice.call(obj, 1, 0, 2, 3); expect(obj.length).toBe(3); }); it('should work with objects - removing', function () { var obj = { 0: 1, 1: 2, 2: 3, length: 3 }; Array.prototype.splice.call(obj, 0, 3); expect(obj.length).toBe(0); }); it('should work with objects - replacing', function () { var obj = { 0: 99, length: 1 }; Array.prototype.splice.call(obj, 0, 1, 1, 2, 3); expect(obj.length).toBe(3); expect(obj[0]).toBe(1); }); ifHasDenseUndefinedsIt('should not break on sparse arrays in Opera', function () { // test from https://github.com/wikimedia/VisualEditor/blob/d468b00311e69c2095b9da360c5745153342a5c3/src/ve.utils.js#L182-L196 var n = 256; var arr = []; arr[n] = 'a'; arr.splice(n + 1, 0, 'b'); expect(arr[n]).toBe('a'); }); ifHasDenseUndefinedsIt('should not break on sparse arrays in Safari 7/8', function () { // test from https://github.com/wikimedia/VisualEditor/blob/d468b00311e69c2095b9da360c5745153342a5c3/src/ve.utils.js#L182-L196 var justFine = new Array(1e5 - 1); justFine[10] = 'x'; var tooBig = new Array(1e5); tooBig[8] = 'x'; justFine.splice(1, 1); expect(8 in justFine).toBe(false); expect(justFine.indexOf('x')).toBe(9); tooBig.splice(1, 1); expect(6 in tooBig).toBe(false); expect(tooBig.indexOf('x')).toBe(7); }); }); describe('#join()', function () { it('defaults to a comma separator when none is provided', function () { expect([1, 2].join()).toBe('1,2'); }); it('defaults to a comma separator when undefined is provided', function () { expect([1, 2].join(undefined)).toBe('1,2'); }); it('works, extended', function () { expect([].join()).toBe(''); expect([undefined].join()).toBe(''); expect([undefined, undefined].join()).toBe(','); expect([null, null].join()).toBe(','); expect([undefined, undefined].join('|')).toBe('|'); expect([null, null].join('|')).toBe('|'); expect([1, 2, 3].join('|')).toBe('1|2|3'); expect([1, 2, 3].join(null)).toBe('1null2null3'); expect([1, 2, 3].join({})).toBe('1[object Object]2[object Object]3'); expect([1, 2, 3].join('')).toBe('123'); }); it('is generic', function () { var obj = { 0: 1, 1: 2, 2: 3, 3: 4, length: 3 }; expect(Array.prototype.join.call(obj, ',')).toBe('1,2,3'); }); it('works with a string literal', function () { var str = '123'; expect(Array.prototype.join.call(str, ',')).toBe('1,2,3'); }); it('works with `arguments`', function () { var args = (function () { return arguments; }(1, 2, 3)); expect(Array.prototype.join.call(args, ',')).toBe('1,2,3'); }); }); describe('#push()', function () { it('works on arrays', function () { var arr = []; var result = arr.push(undefined); expect(result).toBe(1); expect(arr.length).toBe(1); expect(Object.prototype.hasOwnProperty.call(arr, 0)).toBe(true); expect(arr[0]).toBeUndefined(); }); it('is generic', function () { var obj = {}; var result = Array.prototype.push.call(obj, undefined); expect(result).toBe(1); expect(obj.length).toBe(1); expect(Object.prototype.hasOwnProperty.call(obj, 0)).toBe(true); expect(obj[0]).toBeUndefined(); }); }); describe('#pop()', function () { it('works on arrays', function () { var arr = [1, 2, 3]; var result = arr.pop(); expect(result).toBe(3); expect(arr.length).toBe(2); expect(Object.prototype.hasOwnProperty.call(arr, 2)).toBe(false); expect(arr[2]).toBeUndefined(); }); it('is generic', function () { var obj = { 0: 1, 1: 2, 2: 3, length: 3 }; var result = Array.prototype.pop.call(obj); expect(result).toBe(3); expect(obj.length).toBe(2); expect(Object.prototype.hasOwnProperty.call(obj, 2)).toBe(false); expect(obj[2]).toBeUndefined(); }); }); describe('#slice()', function () { it('works on arrays', function () { var arr = [1, 2, 3, 4]; var result = arr.slice(1, 3); expect(result).toEqual([2, 3]); }); it('is generic', function () { var obj = { 0: 1, 1: 2, 2: 3, 3: 4, length: 4 }; var result = Array.prototype.slice.call(obj, 1, 3); expect(result).toEqual([2, 3]); }); it('works with `arguments`', function () { var obj = (function () { return arguments; }(1, 2, 3, 4)); var result = Array.prototype.slice.call(obj, 1, 3); expect(result).toEqual([2, 3]); }); it('boxed string access', function () { var obj = '1234'; var result = Array.prototype.slice.call(obj, 1, 3); expect(result).toEqual(['2', '3']); }); if (typeof document !== 'undefined') { it('should be able to slice a NodeList', function () { var nodes = document.getElementsByTagName('div'); expect(Array.isArray(Array.prototype.slice.call(nodes))).toBe(true); }); } }); describe('#sort()', function () { describe('usage', function () { it('requires a function or undefined as first argument', function () { var actual = [1, 2]; expect(actual.sort()).toBe(actual); expect(actual.sort(undefined)).toBe(actual); expect(actual.sort(function () { return 0; })).toBe(actual); }); it('requires a non-function or non-undefined to throw a `TypeError`', function () { expect(function () { [1, 2].sort(null); }).toThrow(); expect(function () { [1, 2].sort(1); }).toThrow(); expect(function () { [1, 2].sort(''); }).toThrow(); expect(function () { [1, 2].sort(true); }).toThrow(); expect(function () { [1, 2].sort({}); }).toThrow(); expect(function () { [1, 2].sort([]); }).toThrow(); expect(function () { [1, 2].sort(new Date()); }).toThrow(); expect(function () { [1, 2].sort(/pattern/); }).toThrow(); }); }); describe('ascending', function () { it('[5,2,4,6,1,3] should result in [1,2,3,4,5,6]', function () { var actual = [5, 2, 4, 6, 1, 3]; var expected = [1, 2, 3, 4, 5, 6]; actual.sort(); expect(actual).toEqual(expected); }); it('[5,2,2,6,1,3] should result in [1,2,2,3,5,6]', function () { var actual = [5, 2, 2, 6, 1, 3]; var expected = [1, 2, 2, 3, 5, 6]; actual.sort(); expect(actual).toEqual(expected); }); it('[0,0,0,0,0,1] should result in [0,0,0,0,0,1]', function () { var actual = [0, 0, 0, 0, 0, 1]; var expected = [0, 0, 0, 0, 0, 1]; actual.sort(); expect(actual).toEqual(expected); }); it('[0,0,0,0,0,-1] should result in [-1,0,0,0,0,0]', function () { var actual = [0, 0, 0, 0, 0, -1]; var expected = [-1, 0, 0, 0, 0, 0]; actual.sort(); expect(actual).toEqual(expected); }); it('[f,e,d,a,c,b] should result in [a,b,c,d,e,f]', function () { var actual = ['f', 'e', 'd', 'a', 'c', 'b']; var expected = ['a', 'b', 'c', 'd', 'e', 'f']; actual.sort(); expect(actual).toEqual(expected); }); it('[f,e,d,,,,a,c,b] should result in [a,b,c,d,e,f,,,]', function () { var actual = ['f', 'e', 'd', 1, 2, 'a', 'c', 'b']; delete actual[3]; delete actual[4]; var expected = ['a', 'b', 'c', 'd', 'e', 'f']; expected.length = 8; actual.sort(); expect(actual).toEqual(expected); }); it('[f,e,d,,null,,a,c,b] should result in [a,b,c,d,e,f,null,,,]', function () { var actual = ['f', 'e', 'd', 1, null, 2, 'a', 'c', 'b']; delete actual[3]; delete actual[5]; var expected = ['a', 'b', 'c', 'd', 'e', 'f', null]; expected.length = 9; actual.sort(); expect(actual).toEqual(expected); }); it('[f,e,d,,null,undefined,a,c,b] should result in [a,b,c,d,e,f,null,undefined,,]', function () { var actual = ['f', 'e', 'd', 1, null, undefined, 'a', 'c', 'b']; delete actual[3]; var expected = ['a', 'b', 'c', 'd', 'e', 'f', null, undefined]; expected.length = 9; actual.sort(); expect(actual).toEqual(expected); }); it('[] should result in []', function () { var actual = []; var expected = []; actual.sort(); expect(actual).toEqual(expected); }); it('[1] should result in [1]', function () { var actual = [1]; var expected = [1]; actual.sort(); expect(actual).toEqual(expected); }); it('result should find only greater or equal values', function () { var actual = []; var i; for (i = 0; i < 100; i += 1) { actual.push(('00' + (Math.random() * 100).toFixed(0)).slice(-3)); } actual.sort(); for (i = 0; i < actual.length - 1; i += 1) { expect(actual[i] <= actual[i + 1]).toBe(true); } }); }); describe('descending', function () { var descending = function (left, right) { var leftS = String(left); var rightS = String(right); if (leftS === rightS) { return +0; } if (leftS < rightS) { return 1; } return -1; }; it('[5,2,4,6,1,3] should result in [6,5,4,3,2,1]', function () { var actual = [5, 2, 4, 6, 1, 3]; var expected = [6, 5, 4, 3, 2, 1]; actual.sort(descending); expect(actual).toEqual(expected); }); it('[5,2,2,6,1,3] should result in [6,5,4,2,2,1]', function () { var actual = [5, 2, 2, 6, 1, 3]; var expected = [6, 5, 3, 2, 2, 1]; actual.sort(descending); expect(actual).toEqual(expected); }); it('[0,0,0,0,0,1] should result in [1,0,0,0,0,0]', function () { var actual = [0, 0, 0, 0, 0, 1]; var expected = [1, 0, 0, 0, 0, 0]; actual.sort(descending); expect(actual).toEqual(expected); }); it('[0,0,0,0,0,-1] should result in [0,0,0,0,0,-1]', function () { var actual = [0, 0, 0, 0, 0, -1]; var expected = [0, 0, 0, 0, 0, -1]; actual.sort(descending); expect(actual).toEqual(expected); }); it('[f,e,d,a,c,b] should result in [f,e,d,c,b,a]', function () { var actual = ['f', 'e', 'd', 'a', 'c', 'b']; var expected = ['f', 'e', 'd', 'c', 'b', 'a']; actual.sort(descending); expect(actual).toEqual(expected); }); it('[f,e,d,,,a,c,b] should result in [f,e,d,c,b,a,,,]', function () { var actual = ['f', 'e', 'd', 1, 2, 'a', 'c', 'b']; delete actual[3]; delete actual[4]; var expected = ['f', 'e', 'd', 'c', 'b', 'a']; expected.length = 8; actual.sort(descending); expect(actual).toEqual(expected); }); it('[f,e,d,,null,,a,c,b] should result in [null,f,e,d,c,b,a,,,]', function () { var actual = ['f', 'e', 'd', 1, null, 2, 'a', 'c', 'b']; delete actual[3]; delete actual[5]; var expected = [null, 'f', 'e', 'd', 'c', 'b', 'a']; expected.length = 9; actual.sort(descending); expect(actual).toEqual(expected); }); it('[f,e,d,undefined,null,,a,c,b] should result in [null,f,e,d,c,b,a,undefined,,]', function () { var actual = ['f', 'e', 'd', undefined, null, 2, 'a', 'c', 'b']; delete actual[5]; var expected = [null, 'f', 'e', 'd', 'c', 'b', 'a', undefined]; expected.length = 9; actual.sort(descending); expect(actual).toEqual(expected); }); it('[] should result in []', function () { var actual = []; var expected = []; actual.sort(descending); expect(actual).toEqual(expected); }); it('[1] should result in [1]', function () { var actual = [1]; var expected = [1]; actual.sort(descending); expect(actual).toEqual(expected); }); it('result should find only lesser or equal values', function () { var actual = []; var i; for (i = 0; i < 100; i += 1) { actual.push(('00' + (Math.random() * 100).toFixed(0)).slice(-3)); } actual.sort(descending); for (i = 0; i < actual.length - 1; i += 1) { expect(actual[i] >= actual[i + 1]).toBe(true); } }); }); describe('returned value', function () { it('should be the source object', function () { var actual = [1, 3, 2]; expect(actual.sort()).toBe(actual); }); }); describe('when used generically', function () { var descending = function (left, right) { var leftS = String(left); var rightS = String(right); if (leftS === rightS) { return +0; } if (leftS < rightS) { return 1; } return -1; }; var args = function () { return arguments; }; it('should not sort objects without length', function () { var actual = { 0: 5, 1: 2, 2: 4, 3: 6, 4: 1, 5: 3 }; var expected = { 0: 5, 1: 2, 2: 4, 3: 6, 4: 1, 5: 3 }; Array.prototype.sort.call(actual); expect(actual).toEqual(expected); Array.prototype.sort.call(actual, descending); expect(actual).toEqual(expected); }); it('should sort objects ascending with length', function () { var actual = { 0: 5, 1: 2, 2: 4, 3: 6, 4: 1, 5: 3, length: 6 }; var expected = { 0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, length: 6 }; Array.prototype.sort.call(actual); expect(actual).toEqual(expected); }); it('should sort objects descending with length', function () { var actual = { 0: 5, 1: 2, 2: 4, 3: 6, 4: 1, 5: 3, length: 6 }; var expected = { 0: 6, 1: 5, 2: 4, 3: 3, 4: 2, 5: 1, length: 6 }; Array.prototype.sort.call(actual, descending); expect(actual).toEqual(expected); }); it('should sort objects descending with mixed content types and with length', function () { var actual = { 0: 5, 1: 2, 2: 4, 4: null, 6: 1, 7: 3, length: 8 }; var expected = { 0: null, 1: 5, 2: 4, 3: 3, 4: 2, 5: 1, length: 8 }; Array.prototype.sort.call(actual, descending); expect(actual).toEqual(expected); }); it('should sort `arguments` object ascending', function () { var actual = args(5, 2, 4, 6, 1, 3); var expected = args(1, 2, 3, 4, 5, 6); Array.prototype.sort.call(actual); expect(actual).toEqual(expected); }); it('should sort `arguments` object ascending with mixed content types', function () { var actual = args(5, 2, 4, null, 1, 3); var expected = args(1, 2, 3, 4, 5, null); Array.prototype.sort.call(actual); expect(actual).toEqual(expected); }); it('should sort `arguments` object descending', function () { var actual = args(5, 2, 4, 6, 1, 3); var expected = args(6, 5, 4, 3, 2, 1); Array.prototype.sort.call(actual, descending); expect(actual).toEqual(expected); }); it('should sort `arguments` object descending with mixed content types', function () { var actual = args(5, 2, 4, null, 1, 3); var expected = args(null, 5, 4, 3, 2, 1); Array.prototype.sort.call(actual, descending); expect(actual).toEqual(expected); }); }); }); }); ================================================ FILE: tests/spec/s-date.js ================================================ describe('Date', function () { 'use strict'; var supportsDescriptors = Object.defineProperty && (function () { try { var obj = {}; Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); // eslint-disable-next-line no-unreachable-loop for (var _ in obj) { return false; } // jscs:ignore disallowUnusedVariables return obj.x === obj; } catch (e) { /* this is ES3 */ return false; } }()); var ifSupportsDescriptorsIt = supportsDescriptors ? it : xit; var has = Object.prototype.hasOwnProperty; var negativeDate; beforeEach(function () { var negativeCanned = [ { getTime: -3509827329600292, getUTCDay: 4, getDay: 4, dim: 31 }, { getTime: -3509824651200292, getUTCDay: 0, getDay: 0, dim: 29 }, { getTime: -3509822145600292, getUTCDay: 1, getDay: 1, dim: 31 }, { getTime: -3509819467200292, getUTCDay: 4, getDay: 4, dim: 30 }, { getTime: -3509816875200292, getUTCDay: 6, getDay: 6, dim: 31 }, { getTime: -3509814196800292, getUTCDay: 2, getDay: 2, dim: 30 }, { getTime: -3509811604800292, getUTCDay: 4, getDay: 4, dim: 31 }, { getTime: -3509808926400292, getUTCDay: 0, getDay: 0, dim: 31 }, { getTime: -3509806248000292, getUTCDay: 3, getDay: 3, dim: 30 }, { getTime: -3509803656000292, getUTCDay: 5, getDay: 5, dim: 31 }, { getTime: -3509800977600292, getUTCDay: 1, getDay: 1, dim: 30 }, { getTime: -3509798385600292, getUTCDay: 3, getDay: 3, dim: 31 } ]; negativeDate = negativeCanned.map(function (item) { var dateFirst = new Date(item.getTime); var dateLast = new Date(item.getTime + ((item.dim - 1) * 86400000)); return { dates: [dateFirst, dateLast], days: [1, item.dim], getUTCDay: [item.getUTCDay, (item.getUTCDay + item.dim - 1) % 7], getDay: [item.getDay, (item.getDay + item.dim - 1) % 7] }; }); }); describe('.now()', function () { it('should be the current time', function () { var before = (new Date()).getTime(); var middle = Date.now(); var after = (new Date()).getTime(); expect(middle).not.toBeLessThan(before); expect(middle).not.toBeGreaterThan(after); }); }); describe('constructor', function () { it('works with standard formats', function () { // Chrome 19 Opera 12 Firefox 11 IE 9 Safari 5.1.1 expect(+new Date('2012-12-31T23:59:59.000Z')).toBe(1356998399000); // 1356998399000 1356998399000 1356998399000 1356998399000 1356998399000 expect(+new Date('2012-04-04T05:02:02.170Z')).toBe(1333515722170); // 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 expect(+new Date('2012-04-04T05:02:02.170999Z')).toBe(1333515722170); // 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 expect(+new Date('2012-04-04T05:02:02.17Z')).toBe(1333515722170); // 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 expect(+new Date('2012-04-04T05:02:02.1Z')).toBe(1333515722100); // 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 expect(+new Date('2012-04-04T24:00:00.000Z')).toBe(1333584000000); // NaN 1333584000000 1333584000000 1333584000000 1333584000000 expect(+new Date('2012-02-29T12:00:00.000Z')).toBe(1330516800000); // 1330516800000 1330516800000 1330516800000 1330516800000 1330516800000 expect(+new Date('2011-03-01T12:00:00.000Z')).toBe(1298980800000); // 1298980800000 1298980800000 1298980800000 1298980800000 1298980800000 // https://github.com/es-shims/es5-shim/issues/80 Safari bug with leap day expect(new Date('2034-03-01T00:00:00.000Z') - new Date('2034-02-27T23:59:59.999Z')).toBe(86400001); // 86400001 86400001 86400001 86400001 1 }); ifSupportsDescriptorsIt('is not enumerable', function () { expect(Object.keys(new Date())).not.toContain('constructor'); }); it('works as a function', function () { var zeroDate = Date(0); expect(zeroDate).toBe(String(zeroDate)); var value = Date(1441705534578); expect(value).toBe(String(value)); }); it('fixes this Safari 8/9 bug', function () { var offset = new Date(1970).getTimezoneOffset() * 60e3; var timestamp = 2147483647; // Math.pow(2, 31) - 1 var date = new Date(1970, 0, 1, 0, 0, 0, timestamp); var expectedTimestamp = timestamp + offset; expect(date.getTime()).toBe(expectedTimestamp); var brokenTimestamp = 2147483648; // Math.pow(2, 31) var brokenDate = new Date(1970, 0, 1, 0, 0, 0, brokenTimestamp); var expectedBrokenTimestamp = brokenTimestamp + offset; expect(brokenDate.getTime()).toBe(expectedBrokenTimestamp); // NaN in Safari 8/9 var veryBrokenTS = 1435734000000; var veryBrokenDate = new Date(1970, 0, 1, 0, 0, 0, veryBrokenTS); var largeDate = new Date('Wed Jul 01 2015 07:00:00 GMT-0700 (PDT)'); var expectedVeryBrokenTS = veryBrokenTS + (largeDate.getTimezoneOffset() * 60e3); expect(veryBrokenDate.getTime()).toBe(expectedVeryBrokenTS); // NaN in Safari 8/9 }); it('works with a Date object', function () { var date = new Date(1456297712984); var copiedDate = new Date(date); expect(date).not.toBe(copiedDate); expect(copiedDate.getTime()).toBe(date.getTime()); expect(+copiedDate).toBe(+date); expect(String(copiedDate)).toBe(String(date)); }); }); describe('.parse()', function () { // TODO: Write the rest of the test. ifSupportsDescriptorsIt('is not enumerable', function () { expect(Object.getOwnPropertyDescriptor(Date, 'parse').enumerable).toBe(false); }); it('should be an invalid date', function () { // Chrome 19 Opera 12 Firefox 11 IE 9 Safari 5.1.1 expect(Date.parse('2012-11-31T23:59:59.000Z')).toBeFalsy(); // 1354406399000 NaN NaN 1354406399000 NaN expect(Date.parse('2012-12-31T23:59:60.000Z')).toBeFalsy(); // NaN NaN NaN NaN 1356998400000 expect(Date.parse('2012-04-04T24:00:00.500Z')).toBeFalsy(); // NaN NaN 1333584000500 1333584000500 NaN expect(Date.parse('2012-12-31T10:08:60.000Z')).toBeFalsy(); // NaN NaN NaN NaN 1356948540000 expect(Date.parse('2012-13-01T12:00:00.000Z')).toBeFalsy(); // NaN NaN NaN NaN NaN expect(Date.parse('2012-12-32T12:00:00.000Z')).toBeFalsy(); // NaN NaN NaN NaN NaN expect(Date.parse('2012-12-31T25:00:00.000Z')).toBeFalsy(); // NaN NaN NaN NaN NaN expect(Date.parse('2012-12-31T24:01:00.000Z')).toBeFalsy(); // NaN NaN NaN 1356998460000 NaN expect(Date.parse('2012-12-31T12:60:00.000Z')).toBeFalsy(); // NaN NaN NaN NaN NaN expect(Date.parse('2012-12-31T12:00:60.000Z')).toBeFalsy(); // NaN NaN NaN NaN 1356955260000 expect(Date.parse('2012-00-31T23:59:59.000Z')).toBeFalsy(); // NaN NaN NaN NaN NaN expect(Date.parse('2012-12-00T23:59:59.000Z')).toBeFalsy(); // NaN NaN NaN NaN NaN expect(Date.parse('2011-02-29T12:00:00.000Z')).toBeFalsy(); // 1298980800000 NaN NaN 1298980800000 NaN }); it('should work', function () { var dates = { // Chrome 19 Opera 12 Firefox 11 IE 9 Safari 5.1.1 Safari 8 '2012-12-31T23:59:59.000Z': 1356998399000, // 1356998399000 1356998399000 1356998399000 1356998399000 1356998399000 1356998399000 '2012-04-04T05:02:02.170Z': 1333515722170, // 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 '2012-04-04T05:02:02.170999Z': 1333515722170, // 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170.999 '2012-04-04T05:02:02.17Z': 1333515722170, // 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 '2012-04-04T05:02:02.1Z': 1333515722100, // 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 1333515722170 '2012-04-04T24:00:00.000Z': 1333584000000, // NaN 1333584000000 1333584000000 1333584000000 1333584000000 1333584000000 '2012-02-29T12:00:00.000Z': 1330516800000, // 1330516800000 1330516800000 1330516800000 1330516800000 1330516800000 1330516800000 '2011-03-01T12:00:00.000Z': 1298980800000 // 1298980800000 1298980800000 1298980800000 1298980800000 1298980800000 1298980800000 }; for (var str in dates) { if (has.call(dates, str)) { expect(Math.floor(Date.parse(str))).toBe(dates[str]); } } // https://github.com/es-shims/es5-shim/issues/80 Safari bug with leap day expect(Date.parse('2034-03-01T00:00:00.000Z') - Date.parse('2034-02-27T23:59:59.999Z')).toBe(86400001); // 86400001 86400001 86400001 86400001 1 }); it('fixes a Safari 8/9 bug with parsing in UTC instead of local time', function () { var offset = new Date('2015-07-01').getTimezoneOffset() * 60e3; expect(Date.parse('2015-07-01T00:00:00')).toBe(1435708800000 + offset); // Safari 8/9 give NaN }); it('should support extended years', function () { // Chrome 19 Opera 12 Firefox 11 IE 9 Safari 5.1.1 expect(Date.parse('0000-01-01T00:00:00.000Z')).toBe(-621672192e5); // -621672192e5 -621672192e5 -621672192e5 -621672192e5 -621672192e5 expect(Date.parse('0001-01-01T00:00:00Z')).toBe(-621355968e5); // -621355968e5 -621355968e5 -621355968e5 8.64e15 -621355968e5 expect(Date.parse('+275760-09-13T00:00:00.000Z')).toBe(8.64e15); // 8.64e15 NaN 8.64e15 8.64e15 8.64e15 expect(Date.parse('-271821-04-20T00:00:00.000Z')).toBe(-8.64e15); // -8.64e15 NaN -8.64e15 -8.64e15 -8.6400000864e15 expect(Date.parse('+275760-09-13T00:00:00.001Z')).toBeFalsy(); // NaN NaN NaN 8.64e15 + 1 8.64e15 + 1 expect(Date.parse('-271821-04-19T23:59:59.999Z')).toBeFalsy(); // NaN NaN NaN -8.64e15 - 1 -8.6400000864e15 - 1 expect(Date.parse('+033658-09-27T01:46:40.000Z')).toBe(1e15); // 1e15 NaN 1e15 1e15 9999999136e5 expect(Date.parse('-000001-01-01T00:00:00Z')).toBe(-621987552e5); // -621987552e5 NaN -621987552e5 -621987552e5 -621987552e5 expect(Date.parse('+002009-12-15T00:00:00Z')).toBe(12608352e5); // 12608352e5 NaN 12608352e5 12608352e5 12608352e5 }); it('works with timezone offsets', function () { // Chrome 19 Opera 12 Firefox 11 IE 9 Safari 5.1.1 expect(Date.parse('2012-01-29T12:00:00.000+01:00')).toBe(132783480e4); // 132783480e4 132783480e4 132783480e4 132783480e4 132783480e4 expect(Date.parse('2012-01-29T12:00:00.000-00:00')).toBe(132783840e4); // 132783840e4 132783840e4 132783840e4 132783840e4 132783840e4 expect(Date.parse('2012-01-29T12:00:00.000+00:00')).toBe(132783840e4); // 132783840e4 132783840e4 132783840e4 132783840e4 132783840e4 expect(Date.parse('2012-01-29T12:00:00.000+23:59')).toBe(132775206e4); // 132775206e4 132775206e4 132775206e4 132775206e4 132775206e4 expect(Date.parse('2012-01-29T12:00:00.000-23:59')).toBe(132792474e4); // 132792474e4 132792474e4 132792474e4 132792474e4 132792474e4 expect(Date.parse('2012-01-29T12:00:00.000+24:00')).toBeFalsy(); // NaN 1327752e6 NaN 1327752000000 1327752000000 expect(Date.parse('2012-01-29T12:00:00.000+24:01')).toBeFalsy(); // NaN NaN NaN 1327751940000 1327751940000 expect(Date.parse('2012-01-29T12:00:00.000+24:59')).toBeFalsy(); // NaN NaN NaN 1327748460000 1327748460000 expect(Date.parse('2012-01-29T12:00:00.000+25:00')).toBeFalsy(); // NaN NaN NaN NaN NaN expect(Date.parse('2012-01-29T12:00:00.000+00:60')).toBeFalsy(); // NaN NaN NaN NaN NaN expect(Date.parse('-271821-04-20T00:00:00.000+00:01')).toBeFalsy(); // NaN NaN NaN -864000000006e4 -864000008646e4 expect(Date.parse('-271821-04-20T00:01:00.000+00:01')).toBe(-8.64e15); // -8.64e15 NaN -8.64e15 -8.64e15 -864000008640e4 // When time zone is missed, local offset should be used (ES 5.1 bug) // see https://bugs.ecmascript.org/show_bug.cgi?id=112 var tzOffset = Number(new Date(1970, 0)); // same as (new Date().getTimezoneOffset() * 60000) expect(Date.parse('1970-01-01T00:00:00')).toBe(tzOffset); // tzOffset 0 0 0 NaN }); it('should be able to coerce to a number', function () { var actual = Number(new Date(1970, 0)); var expected = parseInt(actual, 10); expect(actual).toBeDefined(); expect(actual).toBe(expected); expect(isNaN(actual)).toBeFalsy(); }); it('matches web reality', function () { var actual = Number(new Date('1900-01-01T00:00:00.000')); var upperBound = -2208988800000; // safari 6.2 - 13.1 var expected = -2208960000000; expect(actual).toBeDefined(); expect(actual).toBeGreaterThan(upperBound - 1); expect(actual).toBeLessThan(expected + 1); // expect(actual).toBe(expected); // TODO: figure out if `upperBound` is a bug or just a difference expect(isNaN(actual)).toBeFalsy(); }); }); describe('#toString()', function () { var actual; beforeEach(function () { actual = (new Date(1970, 0)).toString(); }); it('should show correct date info for ' + actual, function () { expect(actual).toMatch(/1970/); expect(actual).toMatch(/jan/i); expect(actual).toMatch(/thu/i); expect(actual).toMatch(/00:00:00/); }); }); describe('#valueOf()', function () { // Note that new Date(1970, 0).valueOf() is 0 in UTC timezone. // Check check that it's a number (and an int), not that it's "truthy". var actual; beforeEach(function () { actual = (new Date(1970, 0)).valueOf(); }); it('should give a numeric value', function () { expect(typeof actual).toBe('number'); }); it('should not be NaN', function () { expect(isNaN(actual)).toBe(false); }); it('should give an int value', function () { expect(actual).toBe(Math.floor(actual)); }); }); describe('#getUTCDate()', function () { it('should return the right value for negative dates', function () { // Opera 10.6/11.61/Opera 12 bug negativeDate.forEach(function (item) { item.dates.forEach(function (date, index) { expect(date.getUTCDate()).toBe(item.days[index], date); }); }); }); }); describe('#getUTCDay()', function () { it('should return the right value for negative dates', function () { negativeDate.forEach(function (item) { item.dates.forEach(function (date, index) { expect(date.getUTCDay()).toBe(item.getUTCDay[index]); }); }); }); }); describe('#getUTCFullYear()', function () { it('should return the right value for negative dates', function () { // Opera 10.6/11.61/Opera 12 bug negativeDate.forEach(function (item) { item.dates.forEach(function (date) { expect(date.getUTCFullYear()).toBe(-109252); }); }); }); }); describe('#getUTCMonth()', function () { it('should return the right value for negative dates', function () { // Opera 10.6/11.61/Opera 12 bug negativeDate.forEach(function (item, index) { item.dates.forEach(function (date) { expect(date.getUTCMonth()).toBe(index); }); }); }); it('should return correct values', function () { expect(new Date(8.64e15).getUTCMonth()).toBe(8); expect(new Date(0).getUTCMonth()).toBe(0); }); }); describe('#getUTCHours()', function () { it('should return the right value for negative dates', function () { negativeDate.forEach(function (item) { item.dates.forEach(function (date) { expect(date.getUTCHours()).toBe(11); }); }); }); }); describe('#getUTCMinutes()', function () { it('should return the right value for negative dates', function () { negativeDate.forEach(function (item) { item.dates.forEach(function (date) { expect(date.getUTCMinutes()).toBe(59); }); }); }); }); describe('#getUTCSeconds()', function () { it('should return the right value for negative dates', function () { negativeDate.forEach(function (item) { item.dates.forEach(function (date) { expect(date.getUTCSeconds()).toBe(59); }); }); }); }); describe('#getUTCMilliseconds()', function () { it('should return the right value for negative dates', function () { // Opera 10.6/11.61/Opera 12 bug negativeDate.forEach(function (item) { item.dates.forEach(function (date) { expect(date.getUTCMilliseconds()).toBe(708); }); }); }); }); describe('#getDate()', function () { it('should return the right value for negative dates', function () { negativeDate.forEach(function (item) { item.dates.forEach(function (date, index) { expect(date.getDate()).toBe(item.days[index]); }); }); }); }); describe('#getDay()', function () { it('should return the right value for negative dates', function () { negativeDate.forEach(function (item) { item.dates.forEach(function (date, index) { expect(date.getDay()).toBe(item.getDay[index]); }); }); }); }); describe('#getFullYear()', function () { it('should return the right value for negative dates', function () { // Opera 10.6/11.61/Opera 12 bug negativeDate.forEach(function (item) { item.dates.forEach(function (date) { expect(date.getFullYear()).toBe(-109252); }); }); }); }); describe('#getMonth()', function () { it('should return the right value for negative dates', function () { // Opera 10.6/11.61/Opera 12 bug negativeDate.forEach(function (item, index) { item.dates.forEach(function (date) { expect(date.getMonth()).toBe(index); }); }); }); }); describe('#getHours()', function () { it('should return the right value for negative dates', function () { negativeDate.forEach(function (item) { item.dates.forEach(function (date) { expect(date.getHours() + Math.floor(date.getTimezoneOffset() / 60)).toBe(11); }); }); }); }); describe('#getMinutes()', function () { it('should return the right value for negative dates', function () { negativeDate.forEach(function (item) { item.dates.forEach(function (date) { var off = date.getTimezoneOffset(); var offHours = Math.floor(off / 60); var offMins = off - (offHours * 60); var result = date.getMinutes() + offMins; // ceil/floor is for Firefox expect(result < 0 ? Math.ceil(result) : Math.floor(result)).toBe(59); }); }); }); }); describe('#getSeconds()', function () { it('should return the right value for negative dates', function () { negativeDate.forEach(function (item) { item.dates.forEach(function (date, i) { // the regex here is because in UTC, it's 59, but with TZData applied, // which can have fractional hour offsets, it'll be 1. expect(i + ':' + date.getSeconds()).toMatch(new RegExp(i + ':(?:' + 59 + '|' + 1 + ')')); }); }); }); }); describe('#getMilliseconds()', function () { it('should return the right value for negative dates', function () { // Opera 10.6/11.61/Opera 12 bug negativeDate.forEach(function (item) { item.dates.forEach(function (date) { expect(date.getMilliseconds()).toBe(708); }); }); }); }); describe('#toISOString()', function () { // TODO: write the rest of the test. it('should support extended years', function () { expect(new Date(-62198755200000).toISOString().indexOf('-000001-01-01')).toBe(0); expect(new Date(8.64e15).toISOString().indexOf('+275760-09-13')).toBe(0); }); it('should return correct dates', function () { expect(new Date(-1).toISOString()).toBe('1969-12-31T23:59:59.999Z'); // Safari 5.1.5 "1969-12-31T23:59:59.-01Z" negativeDate.forEach(function (item, index) { var m = index + 1; item.dates.forEach(function (date, idx) { var d = item.days[idx]; expect(date.toISOString()).toBe('-109252-' + (m < 10 ? '0' + m : m) + '-' + (d < 10 ? '0' + d : d) + 'T11:59:59.708Z'); // Opera 11.61/Opera 12 bug with Date#getUTCMonth }); }); }); }); describe('#toUTCString()', function () { it('should return correct dates', function () { expect(new Date(-1509842289600292).toUTCString()).toBe('Mon, 01 Jan -45875 11:59:59 GMT'); }); }); describe('#toDateString()', function () { it('should return correct dates', function () { expect(new Date(-1509842289600292).toDateString()).toBe('Mon Jan 01 -45875'); }); }); describe('#toString()', function () { it('should return correct dates', function () { var actual = new Date(1449662400000).toString(); var re = /^Wed Dec 09 2015 \d\d:\d\d:\d\d GMT[-+]\d\d\d\d(?: |$)/; expect(re.test(actual)).toBe(true, actual); }); }); describe('#toJSON()', function () { // Opera 11.6x/12 bug it('should call toISOString', function () { var date = new Date(0); date.toISOString = function () { return 1; }; expect(date.toJSON()).toBe(1); }); it('should return null for not finite dates', function () { var date = new Date(NaN), json; try { json = date.toJSON(); } catch (e) { /* invalid json */ expect(e).not.toEqual(jasmine.any(Error)); } expect(json).toBe(null); }); it('should return the isoString when stringified', function () { var date = new Date(); expect(JSON.stringify(date.toISOString())).toBe(JSON.stringify(date)); }); }); }); ================================================ FILE: tests/spec/s-error.js ================================================ describe('Error', function () { 'use strict'; var supportsDescriptors = Object.defineProperty && (function () { try { var obj = {}; Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); // eslint-disable-next-line no-unreachable-loop for (var _ in obj) { return false; } // jscs:ignore disallowUnusedVariables return obj.x === obj; } catch (e) { /* this is ES3 */ return false; } }()); var ifSupportsDescriptorsIt = supportsDescriptors ? it : xit; describe('#toString()', function () { it('stringifies a newed error properly', function () { var msg = 'test'; var error = new RangeError(msg); expect(error.name).toBe('RangeError'); expect(error.message).toBe(msg); expect(String(error)).toBe(error.name + ': ' + msg); }); it('stringifies a thrown error properly', function () { var msg = 'test'; var error; try { throw new RangeError(msg); } catch (e) { error = e; } expect(error.name).toBe('RangeError'); expect(error.message).toBe(msg); expect(String(error)).toBe(error.name + ': ' + msg); }); }); describe('enumerability of prototype properties', function () { ifSupportsDescriptorsIt('#message', function () { expect(Object.prototype.propertyIsEnumerable.call(Error.prototype, 'message')).toBe(false); }); ifSupportsDescriptorsIt('#name', function () { expect(Object.prototype.propertyIsEnumerable.call(Error.prototype, 'name')).toBe(false); }); }); }); ================================================ FILE: tests/spec/s-function.js ================================================ describe('Function', function () { 'use strict'; describe('#apply()', function () { it('works with arraylike objects', function () { var arrayLike = { length: 4, 0: 1, 2: 4, 3: true }; var expectedArray = [1, undefined, 4, true]; var actualArray = (function () { return Array.prototype.slice.apply(arguments); }.apply(null, arrayLike)); expect(actualArray).toEqual(expectedArray); }); }); describe('#bind()', function () { var actual; var testSubject = { push: function (o) { this.a.push(o); } }; var func = function func() { Array.prototype.forEach.call(arguments, function (a) { this.push(a); }, this); return this; }; beforeEach(function () { actual = []; testSubject.a = []; }); it('binds properly without a context', function () { var context; testSubject.func = function () { context = this; }.bind(); testSubject.func(); expect(context).toBe(function () { return this; }.call()); }); it('binds properly without a context, and still supplies bound arguments', function () { var a, context; testSubject.func = function () { a = Array.prototype.slice.call(arguments); context = this; }.bind(undefined, 1, 2, 3); testSubject.func(1, 2, 3); expect(a).toEqual([1, 2, 3, 1, 2, 3]); expect(context).toBe(function () { return this; }.call()); }); it('binds a context properly', function () { testSubject.func = func.bind(actual); testSubject.func(1, 2, 3); expect(actual).toEqual([1, 2, 3]); expect(testSubject.a).toEqual([]); }); it('binds a context and supplies bound arguments', function () { testSubject.func = func.bind(actual, 1, 2, 3); testSubject.func(4, 5, 6); expect(actual).toEqual([1, 2, 3, 4, 5, 6]); expect(testSubject.a).toEqual([]); }); it('returns properly without binding a context', function () { testSubject.func = function () { return this; }.bind(); var context = testSubject.func(); expect(context).toBe(function () { return this; }.call()); }); it('returns properly without binding a context, and still supplies bound arguments', function () { var context; testSubject.func = function () { context = this; return Array.prototype.slice.call(arguments); }.bind(undefined, 1, 2, 3); actual = testSubject.func(1, 2, 3); expect(context).toBe(function () { return this; }.call()); expect(actual).toEqual([1, 2, 3, 1, 2, 3]); }); it('returns properly while binding a context properly', function () { var ret; testSubject.func = func.bind(actual); ret = testSubject.func(1, 2, 3); expect(ret).toBe(actual); expect(ret).not.toBe(testSubject); }); it('returns properly while binding a context and supplies bound arguments', function () { var ret; testSubject.func = func.bind(actual, 1, 2, 3); ret = testSubject.func(4, 5, 6); expect(ret).toBe(actual); expect(ret).not.toBe(testSubject); }); it('has the new instance\'s context as a constructor', function () { var actualContext; var expectedContext = { foo: 'bar' }; testSubject.Func = function () { actualContext = this; }.bind(expectedContext); var result = new testSubject.Func(); expect(result).toBeTruthy(); expect(actualContext).not.toBe(expectedContext); }); it('passes the correct arguments as a constructor', function () { var expected = { name: 'Correct' }; testSubject.Func = function (arg) { expect(Object.prototype.hasOwnProperty.call(this, 'name')).toBe(false); return arg; }.bind({ name: 'Incorrect' }); var ret = new testSubject.Func(expected); expect(ret).toBe(expected); }); it('returns the return value of the bound function when called as a constructor', function () { var oracle = [1, 2, 3]; var Subject = function () { expect(this).not.toBe(oracle); return oracle; }.bind(null); var result = new Subject(); expect(result).toBe(oracle); }); it('returns the correct value if constructor returns primitive', function () { var Subject = function (oracle) { expect(this).not.toBe(oracle); return oracle; }.bind(null); var primitives = ['asdf', null, true, 1]; for (var i = 0; i < primitives.length; ++i) { expect(new Subject(primitives[i])).not.toBe(primitives[i]); } var objects = [[1, 2, 3], {}, function () {}]; for (var j = 0; j < objects.length; ++j) { expect(new Subject(objects[j])).toBe(objects[j]); } }); it('returns the value that instance of original "class" when called as a constructor', function () { var ClassA = function (x) { this.name = x || 'A'; }; var ClassB = ClassA.bind(null, 'B'); var result = new ClassB(); expect(result instanceof ClassA).toBe(true); expect(result instanceof ClassB).toBe(true); }); it('sets a correct length without thisArg', function () { var Subject = function (a, b, c) { return a + b + c; }.bind(); expect(Subject.length).toBe(3); }); it('sets a correct length with thisArg', function () { var Subject = function (a, b, c) { return a + b + c + this.d; }.bind({ d: 1 }); expect(Subject.length).toBe(3); }); it('sets a correct length with thisArg and first argument', function () { var Subject = function (a, b, c) { return a + b + c + this.d; }.bind({ d: 1 }, 1); expect(Subject.length).toBe(2); }); it('sets a correct length without thisArg and first argument', function () { var Subject = function (a, b, c) { return a + b + c; }.bind(undefined, 1); expect(Subject.length).toBe(2); }); it('sets a correct length without thisArg and too many argument', function () { var Subject = function (a, b, c) { return a + b + c; }.bind(undefined, 1, 2, 3, 4); expect(Subject.length).toBe(0); }); }); }); ================================================ FILE: tests/spec/s-global.js ================================================ describe('global methods', function () { 'use strict'; var foo = function foo() {}; var functionsHaveNames = foo.name === 'foo'; var ifFunctionsHaveNamesIt = functionsHaveNames ? it : xit; var hasSymbols = typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol'; var ifSymbolsIt = hasSymbols ? it : xit; var is = function (x, y) { if (x === 0 && y === 0) { return 1 / x === 1 / y; } return x === y; }; describe('parseInt', function () { /* eslint-disable radix */ ifFunctionsHaveNamesIt('has the right name', function () { expect(parseInt.name).toBe('parseInt'); }); it('accepts a radix', function () { for (var i = 2; i <= 36; ++i) { expect(parseInt('10', i)).toBe(i); } }); it('defaults the radix to 10 when the number does not start with 0x or 0X', function () { [ '01', '08', '10', '42' ].forEach(function (str) { expect(parseInt(str)).toBe(parseInt(str, 10)); }); }); it('defaults the radix to 16 when the number starts with 0x or 0X', function () { expect(parseInt('0x16')).toBe(parseInt('0x16', 16)); expect(parseInt('0X16')).toBe(parseInt('0X16', 16)); }); it('ignores leading whitespace', function () { expect(parseInt(' 0x16')).toBe(parseInt('0x16', 16)); expect(parseInt(' 42')).toBe(parseInt('42', 10)); expect(parseInt(' 08')).toBe(parseInt('08', 10)); var mvsIsWS = (/\s/).test('\u180E'); if (mvsIsWS) { expect(parseInt('\u180E' + 1)).toBe(1); } else { expect(parseInt('\u180E' + 1)).toBeNaN(); } var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF' .replace(/\S/g, ''); // remove the mongolian vowel separator (/u180E) on modern engines expect(parseInt(ws + '08')).toBe(parseInt('08', 10)); expect(parseInt(ws + '0x16')).toBe(parseInt('0x16', 16)); }); it('defaults the radix properly when not a true number', function () { var fakeZero = { valueOf: function () { return 0; } }; expect(parseInt('08', fakeZero)).toBe(parseInt('08', 10)); expect(parseInt('0x16', fakeZero)).toBe(parseInt('0x16', 16)); }); it('allows sign-prefixed hex values', function () { expect(parseInt('-0xF')).toBe(-15); expect(parseInt('-0xF', 16)).toBe(-15); expect(parseInt('+0xF')).toBe(15); expect(parseInt('+0xF', 16)).toBe(15); }); it('NaN parsing', function () { expect(parseInt()).toBeNaN(); expect(parseInt(undefined)).toBeNaN(); expect(parseInt(null)).toBeNaN(); expect(parseInt(NaN)).toBeNaN(); }); ifSymbolsIt('throws on symbols', function () { expect(function () { parseInt(Symbol('')); }).toThrow(); expect(function () { parseInt(Object(Symbol(''))); }).toThrow(); }); /* eslint-enable radix */ }); describe('parseFloat()', function () { it('works with zeroes', function () { expect(is(parseFloat('0'), 0) ? '+0' : '-0').toBe('+0'); expect(is(parseFloat(' 0'), 0) ? '+0' : '-0').toBe('+0'); expect(is(parseFloat('+0'), 0) ? '+0' : '-0').toBe('+0'); expect(is(parseFloat(' +0'), 0) ? '+0' : '-0').toBe('+0'); expect(is(parseFloat('-0'), -0) ? '-0' : '+0').toBe('-0'); expect(is(parseFloat(' -0'), -0) ? '-0' : '+0').toBe('-0'); }); it('NaN parsing', function () { expect(parseFloat(undefined)).toBeNaN(); expect(parseFloat(null)).toBeNaN(); expect(parseFloat(NaN)).toBeNaN(); }); }); }); ================================================ FILE: tests/spec/s-number.js ================================================ describe('Number', function () { 'use strict'; describe('#toExponential()', function () { // the spec allows for this test to fail. it('throws a RangeError when < 0 or > 20 (or > 100 in ES2018+)', function () { expect(function () { return 1.0.toExponential(-1); }).toThrow(); expect(function () { return 1.0.toExponential(-Infinity); }).toThrow(); expect(function () { return 1.0.toExponential(Infinity); }).toThrow(); expect(function () { return [ (0.9).toExponential(21), // ES2018 increased the limit from 21 to 100 (0.9).toExponential(101) ]; }).toThrow(); }); it('works for NaN receiver', function () { expect(NaN.toExponential(NaN)).toBe('NaN'); expect(NaN.toExponential('abc')).toBe('NaN'); }); it('works for non-finite receivers', function () { expect(Infinity.toExponential()).toBe('Infinity'); expect((-Infinity).toExponential()).toBe('-Infinity'); }); it('should round properly', function () { expect(1.0.toExponential()).toBe('1e+0'); expect(1.0.toExponential(0)).toBe('1e+0'); expect(1.0.toExponential(1)).toBe('1.0e+0'); expect(1.0.toExponential(2)).toBe('1.00e+0'); expect(1.2345.toExponential()).toBe('1.2345e+0'); expect(1.2345.toExponential(0)).toBe('1e+0'); expect(1.2345.toExponential(1)).toBe('1.2e+0'); expect(1.2345.toExponential(2)).toBe('1.23e+0'); expect(1.2345.toExponential(3)).toMatch(/^1.23[45]e\+0$/); expect(1.2345.toExponential(4)).toBe('1.2345e+0'); expect(1.2345.toExponential(5)).toBe('1.23450e+0'); expect((-6.9e-11).toExponential(4)).toBe('-6.9000e-11'); }); }); describe('#toFixed()', function () { it('should convert numbers correctly', function () { expect((0.00008).toFixed(3)).toBe('0.000'); expect((0.9).toFixed(0)).toBe('1'); expect((1.255).toFixed(2)).toBe('1.25'); expect((1843654265.0774949).toFixed(5)).toBe('1843654265.07749'); expect((1000000000000000128).toFixed(0)).toBe('1000000000000000128'); }); }); describe('#toPrecision()', function () { // the spec allows for this test to fail. it('throws a RangeError when < 1 or > 21 (or > 100 in ES2018+)', function () { expect(function () { return (0.9).toPrecision(0); }).toThrow(); expect(function () { return [ (0.9).toPrecision(22), // ES2018 increased the limit from 21 to 100 (0.9).toPrecision(101) ]; }).toThrow(); }); it('works as expected', function () { expect((0.00008).toPrecision(3)).toBe('0.0000800'); expect((1.255).toPrecision(2)).toBe('1.3'); expect((1843654265.0774949).toPrecision(13)).toBe('1843654265.077'); expect(NaN.toPrecision(1)).toBe('NaN'); }); it('works with an undefined precision', function () { var num = 123.456; expect(num.toPrecision()).toBe(String(num)); expect(num.toPrecision(undefined)).toBe(String(num)); }); }); describe('constants', function () { it('should have MAX_VALUE', function () { expect(Number.MAX_VALUE).toBe(1.7976931348623157e308); }); it('should have MIN_VALUE', function () { expect(Number.MIN_VALUE).toBe(5e-324); }); it('should have NaN', function () { expect(Number.NaN).not.toBe(Number.NaN); }); it('should have POSITIVE_INFINITY', function () { expect(Number.POSITIVE_INFINITY).toBe(Infinity); }); it('should have NEGATIVE_INFINITY', function () { expect(Number.NEGATIVE_INFINITY).toBe(-Infinity); }); }); }); ================================================ FILE: tests/spec/s-object.js ================================================ /* global window */ var has = Object.prototype.hasOwnProperty; var supportsDescriptors = Object.defineProperty && (function () { try { var obj = {}; Object.defineProperty(obj, 'x', { enumerable: false, value: obj }); // eslint-disable-next-line no-unreachable-loop for (var _ in obj) { return false; } // jscs:ignore disallowUnusedVariables return obj.x === obj; } catch (e) { /* this is ES3 */ return false; } }()); var ifSupportsDescriptorsIt = supportsDescriptors ? it : xit; var ifWindowIt = typeof window === 'undefined' ? xit : it; var extensionsPreventible = typeof Object.preventExtensions === 'function' && (function () { var obj = {}; Object.preventExtensions(obj); obj.a = 3; return obj.a !== 3; }()); var ifExtensionsPreventibleIt = extensionsPreventible ? it : xit; var canSeal = typeof Object.seal === 'function' && (function () { var obj = { a: 3 }; Object.seal(obj); delete obj.a; return obj.a === 3; }()); var ifCanSealIt = canSeal ? it : xit; var canFreeze = typeof Object.freeze === 'function' && (function () { var obj = {}; Object.freeze(obj); obj.a = 3; return obj.a !== 3; }()); var ifCanFreezeIt = canFreeze ? it : xit; describe('Object', function () { 'use strict'; describe('.keys()', function () { var obj = { str: 'boz', obj: { }, arr: [], bool: true, num: 42, 'null': null, undefined: undefined }; var loopedValues = []; for (var key in obj) { loopedValues.push(key); } var keys = Object.keys(obj); it('should have correct length', function () { expect(keys.length).toBe(7); }); describe('arguments objects', function () { it('works with an arguments object', function () { (function () { expect(arguments.length).toBe(3); expect(Object.keys(arguments).length).toBe(arguments.length); expect(Object.keys(arguments)).toEqual(['0', '1', '2']); }(1, 2, 3)); }); it('works with a legacy arguments object', function () { var FakeArguments = function (args) { args.forEach(function (arg, i) { this[i] = arg; }.bind(this)); }; FakeArguments.prototype.length = 3; FakeArguments.prototype.callee = function () {}; var fakeOldArguments = new FakeArguments(['a', 'b', 'c']); expect(Object.keys(fakeOldArguments)).toEqual(['0', '1', '2']); }); }); it('should return an Array', function () { expect(Array.isArray(keys)).toBe(true); }); it('should return names which are own properties', function () { keys.forEach(function (name) { expect(has.call(obj, name)).toBe(true); }); }); it('should return names which are enumerable', function () { keys.forEach(function (name) { expect(loopedValues.indexOf(name)).toNotBe(-1); }); }); // ES6 Object.keys does not require this throw xit('should throw error for non object', function () { var e = {}; expect(function () { try { Object.keys(42); } catch (err) { throw e; } }).toThrow(e); }); describe('enumerating over non-enumerable properties', function () { it('has no enumerable keys on a Function', function () { var Foo = function () {}; expect(Object.keys(Foo.prototype)).toEqual([]); }); it('has no enumerable keys on a boolean', function () { expect(Object.keys(Boolean.prototype)).toEqual([]); }); it('has no enumerable keys on an object', function () { expect(Object.keys(Object.prototype)).toEqual([]); }); }); it('works with boxed primitives', function () { expect(Object.keys(Object('hello'))).toEqual(['0', '1', '2', '3', '4']); }); it('works with boxed primitives with extra properties', function () { var x = Object('x'); x.y = 1; var actual = Object.keys(x); var expected = ['0', 'y']; actual.sort(); expected.sort(); expect(actual).toEqual(expected); }); ifWindowIt('can serialize all objects on the `window`', function () { var windowItemKeys, exception; var excludedKeys = ['window', 'console', 'parent', 'self', 'frame', 'frames', 'frameElement', 'external', 'height', 'width', 'top', 'localStorage', 'applicationCache']; if (supportsDescriptors) { Object.defineProperty(window, 'thrower', { configurable: true, get: function () { throw new RangeError('thrower!'); } }); } for (var k in window) { exception = void 0; windowItemKeys = exception; if (excludedKeys.indexOf(k) === -1 && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { try { windowItemKeys = Object.keys(window[k]); } catch (e) { exception = e; } expect(Array.isArray(windowItemKeys)).toBe(true); expect(exception).toBeUndefined(); } } if (supportsDescriptors) { delete window.thrower; } }); }); describe('.isExtensible()', function () { var obj = { }; it('should return true if object is extensible', function () { expect(Object.isExtensible(obj)).toBe(true); }); ifExtensionsPreventibleIt('should return false if object is not extensible', function () { expect(Object.isExtensible(Object.preventExtensions(obj))).toBe(false); }); ifCanSealIt('should return false if object is sealed', function () { expect(Object.isExtensible(Object.seal(obj))).toBe(false); }); ifCanFreezeIt('should return false if object is frozen', function () { expect(Object.isExtensible(Object.freeze(obj))).toBe(false); }); it('should throw error for non object', function () { try { // note: in ES6, this is expected to return false. expect(Object.isExtensible(42)).toBe(false); } catch (err) { expect(err).toEqual(jasmine.any(TypeError)); } }); }); describe('.defineProperty()', function () { var obj; beforeEach(function () { obj = {}; Object.defineProperty(obj, 'name', { value: 'Testing', configurable: true, enumerable: true, writable: true }); }); it('should return the initial value', function () { expect(has.call(obj, 'name')).toBeTruthy(); expect(obj.name).toBe('Testing'); }); it('should be setable', function () { obj.name = 'Other'; expect(obj.name).toBe('Other'); }); it('should return the parent initial value', function () { var child = Object.create(obj, {}); expect(child.name).toBe('Testing'); expect(has.call(child, 'name')).toBeFalsy(); }); it('should not override the parent value', function () { var child = Object.create(obj, {}); Object.defineProperty(child, 'name', { value: 'Other' }); expect(obj.name).toBe('Testing'); expect(child.name).toBe('Other'); }); it('should throw error for non object', function () { expect(function () { Object.defineProperty(42, 'name', {}); }).toThrow(); }); it('should not throw error for empty descriptor', function () { expect(function () { Object.defineProperty({}, 'name', {}); }).not.toThrow(); }); ifSupportsDescriptorsIt('allows setting a nonwritable prototype', function () { var F = function () {}; expect(F.prototype).toEqual(Object.getOwnPropertyDescriptor(F, 'prototype').value); expect((new F()).toString).toEqual(Object.prototype.toString); F.prototype = Number.prototype; expect(F.prototype).toEqual(Object.getOwnPropertyDescriptor(F, 'prototype').value); expect((new F()).toString).toEqual(Number.prototype.toString); var toStringSentinel = {}; var sentinel = { toString: toStringSentinel }; Object.defineProperty(F, 'prototype', { value: sentinel, writable: false }); expect(F.prototype).toEqual(Object.getOwnPropertyDescriptor(F, 'prototype').value); expect((new F()).toString).toEqual(toStringSentinel); }); ifSupportsDescriptorsIt('properly makes a prototype non-writable', function () { var O = { prototype: 1 }; expect(O.prototype).toEqual(Object.getOwnPropertyDescriptor(O, 'prototype').value); expect(O.prototype).toEqual(1); expect(function () { Object.defineProperty(O, 'prototype', { writable: false, configurable: true }); }).not.toThrow(); var sentinel = {}; expect(function () { Object.defineProperty(O, 'prototype', { value: sentinel }); }).not.toThrow(); expect(O.prototype).toEqual(Object.getOwnPropertyDescriptor(O, 'prototype').value); expect(O.prototype).toEqual(sentinel); }); }); describe('.getOwnPropertyDescriptor()', function () { it('should return undefined because the object does not own the property', function () { var descr = Object.getOwnPropertyDescriptor({}, 'name'); expect(descr).toBeUndefined(); }); it('should return a data descriptor', function () { var descr = Object.getOwnPropertyDescriptor({ name: 'Testing' }, 'name'); var expected = { value: 'Testing', enumerable: true, writable: true, configurable: true }; expect(descr).toEqual(expected); }); it('should return undefined because the object does not own the property', function () { var descr = Object.getOwnPropertyDescriptor(Object.create({ name: 'Testing' }, {}), 'name'); expect(descr).toBeUndefined(); }); it('should return a data descriptor', function () { var expected = { value: 'Testing', configurable: true, enumerable: true, writable: true }; var obj = Object.create({}, { name: expected }); var descr = Object.getOwnPropertyDescriptor(obj, 'name'); expect(descr).toEqual(expected); }); it('should throw error for non object', function () { try { // note: in ES6, we expect this to return undefined. expect(Object.getOwnPropertyDescriptor(42, 'name')).toBeUndefined(); } catch (err) { expect(err).toEqual(jasmine.any(TypeError)); } }); }); describe('.getPrototypeOf()', function () { it('should return the [[Prototype]] of an object', function () { var Foo = function () {}; var proto = Object.getPrototypeOf(new Foo()); expect(proto).toBe(Foo.prototype); }); it('should shamone to the `Object.prototype` if `object.constructor` is not a function', function () { var Foo = function () {}; Foo.prototype.constructor = 1; var proto = Object.getPrototypeOf(new Foo()), fnToString = Function.prototype.toString; if (fnToString.call(Object.getPrototypeOf).indexOf('[native code]') < 0) { expect(proto).toBe(Object.prototype); } else { expect(proto).toBe(Foo.prototype); } }); it('should throw error for non object', function () { try { expect(Object.getPrototypeOf(1)).toBe(Number.prototype); // ES6 behavior } catch (err) { expect(err).toEqual(jasmine.any(TypeError)); } }); it('should return null on Object.create(null)', function () { var obj = Object.create(null); expect(Object.getPrototypeOf(obj) === null).toBe(true); }); }); describe('.defineProperties()', function () { it('should define the constructor property', function () { var target = {}; var newProperties = { constructor: { value: 'new constructor' } }; Object.defineProperties(target, newProperties); expect(target.constructor).toBe('new constructor'); }); }); describe('.create()', function () { it('should create objects with no properties when called as `Object.create(null)`', function () { var obj = Object.create(null); expect('hasOwnProperty' in obj).toBe(false); expect('toString' in obj).toBe(false); expect('constructor' in obj).toBe(false); var protoIsEnumerable = false; for (var k in obj) { if (k === '__proto__') { protoIsEnumerable = true; } } expect(protoIsEnumerable).toBe(false); expect(obj instanceof Object).toBe(false); }); }); }); ================================================ FILE: tests/spec/s-regexp.js ================================================ describe('RegExp', function () { 'use strict'; describe('#toString()', function () { describe('literals', function () { it('should return correct flags and in correct order', function () { expect(String(/pattern/)).toBe('/pattern/'); expect(String(/pattern/i)).toBe('/pattern/i'); expect(String(/pattern/mi)).toBe('/pattern/im'); expect(String(/pattern/im)).toBe('/pattern/im'); expect(String(/pattern/mgi)).toBe('/pattern/gim'); }); }); describe('objects', function () { it('should return correct flags and in correct order', function () { /* eslint prefer-regex-literals: 0 */ expect(String(new RegExp('pattern'))).toBe('/pattern/'); expect(String(new RegExp('pattern', 'i'))).toBe('/pattern/i'); expect(String(new RegExp('pattern', 'mi'))).toBe('/pattern/im'); expect(String(new RegExp('pattern', 'im'))).toBe('/pattern/im'); expect(String(new RegExp('pattern', 'mgi'))).toBe('/pattern/gim'); }); }); }); }); ================================================ FILE: tests/spec/s-string.js ================================================ describe('String', function () { 'use strict'; describe('#trim()', function () { var mvs = '\u180E'; var mvsIsWS = (/\s/).test(mvs); var test = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680' + (mvsIsWS ? mvs : '') + '\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFFHello, World!\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680' + (mvsIsWS ? mvs : '') + '\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF'; it('trims all ES5 whitespace', function () { expect(test.trim()).toBe('Hello, World!'); expect(test.trim().length).toBe(13); }); it('does not trim the zero-width space', function () { var zws = '\u200b'; expect(zws.trim()).toBe(zws); }); it('properly handles the mongolian vowel separator', function () { if (mvsIsWS) { expect(mvs.trim()).toBe(''); } else { expect(mvs.trim()).toBe(mvs); } }); }); describe('#replace()', function () { it('returns undefined for non-capturing groups', function () { var groups = []; 'x'.replace(/x(.)?/g, function (m, group) { groups.push(group); /* "" in FF, `undefined` in CH/WK/IE */ }); expect(groups.length).toBe(1); expect(groups[0]).toBeUndefined(); }); it('should not fail in Firefox', function () { expect(function () { return '* alef\n* beth \n* gimel~0\n'.replace( /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+([^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm, function (match, m1, m2, m3, m4) { return '
  • ' + m4 + '
  • \n'; } ); }).not.toThrow(); }); }); describe('#split()', function () { var test = 'ab'; it('If "separator" is undefined must return Array with one String - "this" string', function () { expect(test.split()).toEqual([test]); expect(test.split(void 0)).toEqual([test]); }); it('If "separator" is undefined and "limit" set to 0 must return Array[]', function () { expect(test.split(void 0, 0)).toEqual([]); }); describe('Tests from Steven Levithan', function () { it("''.split() results in ['']", function () { expect(''.split()).toEqual(['']); }); it("''.split(/./) results in ['']", function () { expect(''.split(/./)).toEqual(['']); }); it("''.split(/.?/) results in []", function () { expect(''.split(/.?/)).toEqual([]); }); it("''.split(/.??/) results in []", function () { expect(''.split(/.??/)).toEqual([]); }); it("'ab'.split(/a*/) results in ['', 'b']", function () { expect('ab'.split(/a*/)).toEqual(['', 'b']); }); it("'ab'.split(/a*?/) results in ['a', 'b']", function () { expect('ab'.split(/a*?/)).toEqual(['a', 'b']); }); it("'ab'.split(/(?:ab)/) results in ['', '']", function () { expect('ab'.split(/(?:ab)/)).toEqual(['', '']); }); it("'ab'.split(/(?:ab)*/) results in ['', '']", function () { expect('ab'.split(/(?:ab)*/)).toEqual(['', '']); }); it("'ab'.split(/(?:ab)*?/) results in ['a', 'b']", function () { expect('ab'.split(/(?:ab)*?/)).toEqual(['a', 'b']); }); it("'test'.split('') results in ['t', 'e', 's', 't']", function () { expect('test'.split('')).toEqual(['t', 'e', 's', 't']); }); it("'test'.split() results in ['test']", function () { expect('test'.split()).toEqual(['test']); }); it("'111'.split(1) results in ['', '', '', '']", function () { expect('111'.split(1)).toEqual(['', '', '', '']); }); it("'test'.split(/(?:)/, 2) results in ['t', 'e']", function () { expect('test'.split(/(?:)/, 2)).toEqual(['t', 'e']); }); it("'test'.split(/(?:)/, -1) results in ['t', 'e', 's', 't']", function () { expect('test'.split(/(?:)/, -1)).toEqual(['t', 'e', 's', 't']); }); it("'test'.split(/(?:)/, undefined) results in ['t', 'e', 's', 't']", function () { expect('test'.split(/(?:)/, undefined)).toEqual(['t', 'e', 's', 't']); }); it("'test'.split(/(?:)/, null) results in []", function () { expect('test'.split(/(?:)/, null)).toEqual([]); }); it("'test'.split(/(?:)/, NaN) results in []", function () { expect('test'.split(/(?:)/, NaN)).toEqual([]); }); it("'test'.split(/(?:)/, true) results in ['t']", function () { expect('test'.split(/(?:)/, true)).toEqual(['t']); }); it("'test'.split(/(?:)/, '2') results in ['t', 'e']", function () { expect('test'.split(/(?:)/, '2')).toEqual(['t', 'e']); }); it("'test'.split(/(?:)/, 'two') results in []", function () { expect('test'.split(/(?:)/, 'two')).toEqual([]); }); it("'a'.split(/-/) results in ['a']", function () { expect('a'.split(/-/)).toEqual(['a']); }); it("'a'.split(/-?/) results in ['a']", function () { expect('a'.split(/-?/)).toEqual(['a']); }); it("'a'.split(/-??/) results in ['a']", function () { expect('a'.split(/-??/)).toEqual(['a']); }); it("'a'.split(/a/) results in ['', '']", function () { expect('a'.split(/a/)).toEqual(['', '']); }); it("'a'.split(/a?/) results in ['', '']", function () { expect('a'.split(/a?/)).toEqual(['', '']); }); it("'a'.split(/a??/) results in ['a']", function () { expect('a'.split(/a??/)).toEqual(['a']); }); it("'ab'.split(/-/) results in ['ab']", function () { expect('ab'.split(/-/)).toEqual(['ab']); }); it("'ab'.split(/-?/) results in ['a', 'b']", function () { expect('ab'.split(/-?/)).toEqual(['a', 'b']); }); it("'ab'.split(/-??/) results in ['a', 'b']", function () { expect('ab'.split(/-??/)).toEqual(['a', 'b']); }); it("'a-b'.split(/-/) results in ['a', 'b']", function () { expect('a-b'.split(/-/)).toEqual(['a', 'b']); }); it("'a-b'.split(/-?/) results in ['a', 'b']", function () { expect('a-b'.split(/-?/)).toEqual(['a', 'b']); }); it("'a-b'.split(/-??/) results in ['a', '-', 'b']", function () { expect('a-b'.split(/-??/)).toEqual(['a', '-', 'b']); }); it("'a--b'.split(/-/) results in ['a', '', 'b']", function () { expect('a--b'.split(/-/)).toEqual(['a', '', 'b']); }); it("'a--b'.split(/-?/) results in ['a', '', 'b']", function () { expect('a--b'.split(/-?/)).toEqual(['a', '', 'b']); }); it("'a--b'.split(/-??/) results in ['a', '-', '-', 'b']", function () { expect('a--b'.split(/-??/)).toEqual(['a', '-', '-', 'b']); }); it("''.split(/()()/) results in []", function () { expect(''.split(/()()/)).toEqual([]); }); it("'.'.split(/()()/) results in ['.']", function () { expect('.'.split(/()()/)).toEqual(['.']); }); it("'.'.split(/(.?)(.?)/) results in ['', '.', '', '']", function () { expect('.'.split(/(.?)(.?)/)).toEqual(['', '.', '', '']); }); it("'.'.split(/(.??)(.??)/) results in ['.']", function () { expect('.'.split(/(.??)(.??)/)).toEqual(['.']); }); it("'.'.split(/(.)?(.)?/) results in ['', '.', undefined, '']", function () { expect('.'.split(/(.)?(.)?/)).toEqual(['', '.', undefined, '']); }); it("'Aboldandcoded'.split(/<(\\/)?([^<>]+)>/) results in ['A', undefined, 'B', 'bold', '/', 'B', 'and', undefined, 'CODE', 'coded', '/', 'CODE', '']", function () { expect('Aboldandcoded'.split(/<(\/)?([^<>]+)>/)).toEqual(['A', undefined, 'B', 'bold', '/', 'B', 'and', undefined, 'CODE', 'coded', '/', 'CODE', '']); }); it("'tesst'.split(/(s)*/) results in ['t', undefined, 'e', 's', 't']", function () { expect('tesst'.split(/(s)*/)).toEqual(['t', undefined, 'e', 's', 't']); }); it("'tesst'.split(/(s)*?/) results in ['t', undefined, 'e', undefined, 's', undefined, 's', undefined, 't']", function () { expect('tesst'.split(/(s)*?/)).toEqual(['t', undefined, 'e', undefined, 's', undefined, 's', undefined, 't']); }); it("'tesst'.split(/(s*)/) results in ['t', '', 'e', 'ss', 't']", function () { expect('tesst'.split(/(s*)/)).toEqual(['t', '', 'e', 'ss', 't']); }); it("'tesst'.split(/(s*?)/) results in ['t', '', 'e', '', 's', '', 's', '', 't']", function () { expect('tesst'.split(/(s*?)/)).toEqual(['t', '', 'e', '', 's', '', 's', '', 't']); }); it("'tesst'.split(/(?:s)*/) results in ['t', 'e', 't']", function () { expect('tesst'.split(/(?:s)*/)).toEqual(['t', 'e', 't']); }); it("'tesst'.split(/(?=s+)/) results in ['te', 's', 'st']", function () { expect('tesst'.split(/(?=s+)/)).toEqual(['te', 's', 'st']); }); it("'test'.split('t') results in ['', 'es', '']", function () { expect('test'.split('t')).toEqual(['', 'es', '']); }); it("'test'.split('es') results in ['t', 't']", function () { expect('test'.split('es')).toEqual(['t', 't']); }); it("'test'.split(/t/) results in ['', 'es', '']", function () { expect('test'.split(/t/)).toEqual(['', 'es', '']); }); it("'test'.split(/es/) results in ['t', 't']", function () { expect('test'.split(/es/)).toEqual(['t', 't']); }); it("'test'.split(/(t)/) results in ['', 't', 'es', 't', '']", function () { expect('test'.split(/(t)/)).toEqual(['', 't', 'es', 't', '']); }); it("'test'.split(/(es)/) results in ['t', 'es', 't']", function () { expect('test'.split(/(es)/)).toEqual(['t', 'es', 't']); }); it("'test'.split(/(t)(e)(s)(t)/) results in ['', 't', 'e', 's', 't', '']", function () { expect('test'.split(/(t)(e)(s)(t)/)).toEqual(['', 't', 'e', 's', 't', '']); }); it("'.'.split(/(((.((.??)))))/) results in ['', '.', '.', '.', '', '', '']", function () { expect('.'.split(/(((.((.??)))))/)).toEqual(['', '.', '.', '.', '', '', '']); }); it("'.'.split(/(((((.??)))))/) results in ['.']", function () { expect('.'.split(/(((((.??)))))/)).toEqual(['.']); }); it("'a b c d'.split(/ /, -(Math.pow(2, 32) - 1)) results in ['a']", function () { expect('a b c d'.split(/ /, -(Math.pow(2, 32) - 1))).toEqual(['a']); }); it("'a b c d'.split(/ /, Math.pow(2, 32) + 1) results in ['a']", function () { expect('a b c d'.split(/ /, Math.pow(2, 32) + 1)).toEqual(['a']); }); it("'a b c d'.split(/ /, Infinity) results in []", function () { expect('a b c d'.split(/ /, Infinity)).toEqual([]); }); }); it('works with the second argument', function () { expect('a b'.split(/ /, 1)).toEqual(['a']); }); }); describe('#indexOf()', function () { it('has basic support', function () { expect('abcab'.indexOf('a')).toBe(0); expect('abcab'.indexOf('a', 1)).toBe(3); expect('abcab'.indexOf('a', 4)).toBe(-1); }); it('works with unicode', function () { expect('あいabcあいabc'.indexOf('あい')).toBe(0); expect('あいabcあいabc'.indexOf('あい', 0)).toBe(0); expect('あいabcあいabc'.indexOf('あい', 1)).toBe(5); expect('あいabcあいabc'.indexOf('あい', 6)).toBe(-1); }); }); describe('#lastIndexOf()', function () { it('has the right length', function () { expect(String.prototype.lastIndexOf.length).toBe(1); }); it('has basic support', function () { expect('abcd'.lastIndexOf('d')).toBe(3); expect('abcd'.lastIndexOf('d', 3)).toBe(3); expect('abcd'.lastIndexOf('d', 2)).toBe(-1); }); it('works with unicode', function () { expect('abcあい'.lastIndexOf('あい')).toBe(3); expect('abcあい'.lastIndexOf('あい', 3)).toBe(3); expect('abcあい'.lastIndexOf('あい', 2)).toBe(-1); }); }); });