From 52e9c2fa8793b067ce3fed2774257fef7345cd29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Mon, 18 May 2020 21:38:13 +0000 Subject: [PATCH 1/6] Update repo config files --- .editorconfig | 6 ++++++ .gitignore | 1 + .npmrc | 1 + 3 files changed, 8 insertions(+) create mode 100644 .editorconfig create mode 100644 .npmrc diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..4ef4194 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,6 @@ +root = true + +[*] +indent_style = tab +end_of_line = lf +insert_final_newline = true diff --git a/.gitignore b/.gitignore index 444ec4d..8effac9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ coverage # Installed npm modules node_modules +package-lock.json # Folder view configuration files .DS_Store diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false From 70aafcfff025900f07abcae052e3ce883d956774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Wed, 20 May 2020 17:55:07 +0000 Subject: [PATCH 2/6] [breaking] Implement the es-shim-api interface --- auto.js | 3 +++ implementation.js | 30 ++++++++++++++++++++++++++++ includes.js | 50 ----------------------------------------------- index.js | 20 +++++++++++++++++++ package.json | 18 ++++++++++++----- polyfill.js | 9 +++++++++ shim.js | 17 ++++++++++++++++ tests/tests.js | 2 +- 8 files changed, 93 insertions(+), 56 deletions(-) create mode 100644 auto.js create mode 100644 implementation.js delete mode 100644 includes.js create mode 100644 index.js create mode 100644 polyfill.js create mode 100644 shim.js diff --git a/auto.js b/auto.js new file mode 100644 index 0000000..e6e57f0 --- /dev/null +++ b/auto.js @@ -0,0 +1,3 @@ +/*! https://mths.be/includes v2.0.0 by @mathias */ + +require('./shim')(); diff --git a/implementation.js b/implementation.js new file mode 100644 index 0000000..a85039e --- /dev/null +++ b/implementation.js @@ -0,0 +1,30 @@ +/*! https://mths.be/includes v2.0.0 by @mathias */ + +'use strict'; + +var callBound = require('es-abstract/helpers/callBound') +var RequireObjectCoercible = require('es-abstract/2019/RequireObjectCoercible'); +var ToString = require('es-abstract/2019/ToString'); +var ToInteger = require('es-abstract/2019/ToInteger'); +var IsRegExp = require('es-abstract/2019/IsRegExp'); + +var min = Math.min; +var max = Math.max; +var indexOf = callBound('String.prototype.indexOf'); + +module.exports = function includes(searchString) { + var O = RequireObjectCoercible(this); + var S = ToString(O); + if (IsRegExp(searchString)) throw TypeError(); + var searchStr = String(searchString); + var searchLength = searchStr.length; + var position = arguments.length > 1 ? arguments[1] : undefined; + var pos = ToInteger(position); + var len = S.length; + var start = min(max(pos, 0), len); + // Avoid the `indexOf` call if no match is possible + if (searchLength + start > len) { + return false; + } + return indexOf(S, searchStr, pos) != -1; +}; diff --git a/includes.js b/includes.js deleted file mode 100644 index ffd41b2..0000000 --- a/includes.js +++ /dev/null @@ -1,50 +0,0 @@ -/*! https://mths.be/includes v1.0.0 by @mathias */ -if (!String.prototype.includes) { - (function() { - 'use strict'; // needed to support `apply`/`call` with `undefined`/`null` - var toString = {}.toString; - var defineProperty = (function() { - // IE 8 only supports `Object.defineProperty` on DOM elements - try { - var object = {}; - var $defineProperty = Object.defineProperty; - var result = $defineProperty(object, object, object) && $defineProperty; - } catch(error) {} - return result; - }()); - var indexOf = ''.indexOf; - var includes = function(search) { - if (this == null) { - throw TypeError(); - } - var string = String(this); - if (search && toString.call(search) == '[object RegExp]') { - throw TypeError(); - } - var stringLength = string.length; - var searchString = String(search); - var searchLength = searchString.length; - var position = arguments.length > 1 ? arguments[1] : undefined; - // `ToInteger` - var pos = position ? Number(position) : 0; - if (pos != pos) { // better `isNaN` - pos = 0; - } - var start = Math.min(Math.max(pos, 0), stringLength); - // Avoid the `indexOf` call if no match is possible - if (searchLength + start > stringLength) { - return false; - } - return indexOf.call(string, searchString, pos) != -1; - }; - if (defineProperty) { - defineProperty(String.prototype, 'includes', { - 'value': includes, - 'configurable': true, - 'writable': true - }); - } else { - String.prototype.includes = includes; - } - }()); -} diff --git a/index.js b/index.js new file mode 100644 index 0000000..9efa4a3 --- /dev/null +++ b/index.js @@ -0,0 +1,20 @@ +/*! https://mths.be/includes v2.0.0 by @mathias */ + +'use strict'; + +var callBind = require('es-abstract/helpers/callBind'); +var define = require('define-properties'); + +var implementation = require('./implementation'); +var getPolyfill = require('./polyfill'); +var shim = require('./shim'); + +var boundIncludes = callBind(getPolyfill()); + +define(boundIncludes, { + getPolyfill: getPolyfill, + implementation: implementation, + shim: shim +}); + +module.exports = boundIncludes; diff --git a/package.json b/package.json index 9d733ca..b166a54 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,15 @@ "version": "1.0.0", "description": "A robust & optimized `String.prototype.includes` polyfill, based on the ECMAScript 6 specification.", "homepage": "https://mths.be/includes", - "main": "includes.js", + "main": "index.js", + "exports": { + ".": "./index.js", + "./auto": "./auto.js", + "./shim": "./shim.js", + "./getPolyfill": "./getPolyfill.js", + "./implementation": "./implementation.js", + "./package.json": "./package.json" + }, "keywords": [ "string", "includes", @@ -21,12 +29,12 @@ "url": "https://github.com/mathiasbynens/String.prototype.includes.git" }, "bugs": "https://github.com/mathiasbynens/String.prototype.includes/issues", - "files": [ - "LICENSE-MIT.txt", - "includes.js" - ], "scripts": { "test": "node tests/tests.js", "cover": "istanbul cover --report html --verbose --dir coverage tests/tests.js" + }, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" } } diff --git a/polyfill.js b/polyfill.js new file mode 100644 index 0000000..b6ffd65 --- /dev/null +++ b/polyfill.js @@ -0,0 +1,9 @@ +/*! https://mths.be/includes v2.0.0 by @mathias */ + +'use strict'; + +var implementation = require('./implementation'); + +module.exports = function getPolyfill() { + return String.prototype.includes || implementation; +}; diff --git a/shim.js b/shim.js new file mode 100644 index 0000000..3e67f7e --- /dev/null +++ b/shim.js @@ -0,0 +1,17 @@ +/*! https://mths.be/includes v2.0.0 by @mathias */ + +'use strict'; + +var define = require('define-properties'); + +var getPolyfill = require('./polyfill'); + +module.exports = function shimIncludes() { + var polyfill = getPolyfill(); + + if (String.prototype.includes !== polyfill) { + define(String.prototype, { includes: polyfill }); + } + + return polyfill; +}; diff --git a/tests/tests.js b/tests/tests.js index bdde023..6e83330 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -2,7 +2,7 @@ var assert = require('assert'); var assertEquals = assert.equal; var assertThrows = assert['throws']; -require('../includes.js'); +require('../auto.js'); Object.prototype[1] = 2; // try to break `arguments[1]` From 8abc31f046310aacc1106d1de3cf5431c7d6f2b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Mon, 18 May 2020 21:49:31 +0000 Subject: [PATCH 3/6] Test that it respects the es-shim-api interface --- package.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index b166a54..21d71fe 100644 --- a/package.json +++ b/package.json @@ -30,11 +30,17 @@ }, "bugs": "https://github.com/mathiasbynens/String.prototype.includes/issues", "scripts": { - "test": "node tests/tests.js", + "pretest": "es-shim-api --bound", + "test": "npm run tests-only", + "tests-only": "node tests/tests.js", "cover": "istanbul cover --report html --verbose --dir coverage tests/tests.js" }, "dependencies": { "define-properties": "^1.1.3", "es-abstract": "^1.17.5" + }, + "devDependencies": { + "@es-shims/api": "^2.1.2", + "istanbul": "^0.4.5" } } From 473fec67bcffb8da7a949c73d56ef1d745996e7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Mon, 18 May 2020 21:51:16 +0000 Subject: [PATCH 4/6] Update readme --- README.md | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 19bb849..4c98afe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # ES6 `String.prototype.includes` polyfill [![Build status](https://travis-ci.org/mathiasbynens/String.prototype.includes.svg?branch=master)](https://travis-ci.org/mathiasbynens/String.prototype.includes) -A robust & optimized ES3-compatible polyfill for [the `String.prototype.includes` method (previously known as `String.prototype.contains`) in ECMAScript 6](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.includes). +A robust & optimized polyfill for [the `String.prototype.includes` method (previously known as `String.prototype.contains`) in ECMAScript 6](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-string.prototype.includes). + +This package implements the [es-shim API](https://github.com/es-shims/api) interface. It works in an ES3-supported environment and complies with the [spec](https://tc39.es/ecma262/#sec-string.prototype.includes). Other polyfills for `String.prototype.includes` are available: @@ -9,12 +11,6 @@ Other polyfills for `String.prototype.includes` are available: ## Installation -In a browser: - -```html - -``` - Via [npm](http://npmjs.org/): ```bash @@ -24,13 +20,19 @@ npm install string.prototype.includes Then, in [Node.js](http://nodejs.org/): ```js -require('string.prototype.includes'); +var includes = require('string.prototype.includes'); +``` + +In a browser: -// On Windows and on Mac systems with default settings, case doesn’t matter, -// which allows you to do this instead: -require('String.prototype.includes'); +```html + ``` +> **NOTE**: It's recommended that you install this module using a package manager +> such as `npm`, because loading multiple polyfills from a CDN (such as `bundle.run`) +> will lead to duplicated code. + ## Notes Polyfills + test suites for [`String.prototype.startsWith`](https://mths.be/startswith) and [`String.prototype.endsWith`](https://mths.be/endswith) are available, too. From a89b9aa77f7284bc530bfbb291b983cebe488b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Mon, 18 May 2020 22:02:46 +0000 Subject: [PATCH 5/6] Use `tape` in tests and run them on every Node.js version --- .travis.yml | 8 +- package.json | 9 +- tests/index.js | 12 +++ tests/shimmed.js | 30 ++++++ tests/tests.js | 238 +++++++++++++++++++++++++---------------------- 5 files changed, 182 insertions(+), 115 deletions(-) create mode 100644 tests/index.js create mode 100644 tests/shimmed.js diff --git a/.travis.yml b/.travis.yml index 6e5919d..7a78e0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,7 @@ +version: ~> 1.0 language: node_js -node_js: - - "0.10" +os: + - linux +import: + - ljharb/travis-ci:node/all.yml + - ljharb/travis-ci:node/pretest.yml diff --git a/package.json b/package.json index 21d71fe..19e151a 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,8 @@ "scripts": { "pretest": "es-shim-api --bound", "test": "npm run tests-only", - "tests-only": "node tests/tests.js", - "cover": "istanbul cover --report html --verbose --dir coverage tests/tests.js" + "tests-only": "tape 'tests/*.js'", + "cover": "istanbul cover --report html --verbose --dir coverage tape 'tests/*.js'" }, "dependencies": { "define-properties": "^1.1.3", @@ -41,6 +41,9 @@ }, "devDependencies": { "@es-shims/api": "^2.1.2", - "istanbul": "^0.4.5" + "function-bind": "^1.1.1", + "functions-have-names": "^1.2.1", + "istanbul": "^0.4.5", + "tape": "^5.0.0" } } diff --git a/tests/index.js b/tests/index.js new file mode 100644 index 0000000..a748583 --- /dev/null +++ b/tests/index.js @@ -0,0 +1,12 @@ +'use strict'; + +var includes = require('../'); +var test = require('tape'); + +var runTests = require('./tests'); + +test('as a function', function (t) { + runTests(includes, t); + + t.end(); +}); diff --git a/tests/shimmed.js b/tests/shimmed.js new file mode 100644 index 0000000..b3ef5a3 --- /dev/null +++ b/tests/shimmed.js @@ -0,0 +1,30 @@ +'use strict'; + +var includes = require('../'); +includes.shim(); + +var test = require('tape'); +var defineProperties = require('define-properties'); +var bind = require('function-bind'); +var isEnumerable = Object.prototype.propertyIsEnumerable; +var functionsHaveNames = require('functions-have-names')(); + +var runTests = require('./tests'); + +test('shimmed', function (t) { + t.equal(String.prototype.includes.length, 1, 'String#includes has a length of 1'); + + t.test('Function name', { skip: !functionsHaveNames }, function (st) { + st.equal(String.prototype.includes.name, 'includes', 'String#includes has name "includes"'); + st.end(); + }); + + t.test('enumerability', { skip: !defineProperties.supportsDescriptors }, function (st) { + st.equal(false, isEnumerable.call(String.prototype, 'includes'), 'String#includes is not enumerable'); + st.end(); + }); + + runTests(bind.call(Function.call, String.prototype.includes), t); + + t.end(); +}); diff --git a/tests/tests.js b/tests/tests.js index 6e83330..f965879 100644 --- a/tests/tests.js +++ b/tests/tests.js @@ -1,120 +1,138 @@ -var assert = require('assert'); -var assertEquals = assert.equal; -var assertThrows = assert['throws']; +'use strict'; -require('../auto.js'); +function fakeArg(fn) { + return function(st) { + try { + Object.prototype[1] = 2; // try to break `arguments[1]` + fn(st); + } finally { + delete Object.prototype[1]; + } + }; +} -Object.prototype[1] = 2; // try to break `arguments[1]` +module.exports = function(includes, t) { + t.test('cast searchString arg', fakeArg(function(st) { + st.equals(includes('abc'), false); + st.equals(includes('aundefinedb'), true); + st.equals(includes('abc', undefined), false); + st.equals(includes('aundefinedb', undefined), true); + st.equals(includes('abc', null), false); + st.equals(includes('anullb', null), true); + st.equals(includes('abc', false), false); + st.equals(includes('afalseb', false), true); + st.equals(includes('abc', NaN), false); + st.equals(includes('aNaNb', NaN), true); + st.end(); + })); -assertEquals(String.prototype.includes.length, 1); -assertEquals(String.prototype.propertyIsEnumerable('includes'), false); + t.test('basic support', fakeArg(function(st) { + st.equals(includes('abc', 'abc'), true); + st.equals(includes('abc', 'def'), false); + st.equals(includes('abc', ''), true); + st.equals(includes('', ''), true); + st.equals(includes('abc', 'bc'), true); + st.equals(includes('abc', 'bc\0'), false); + st.end(); + })); -assertEquals('abc'.includes(), false); -assertEquals('aundefinedb'.includes(), true); -assertEquals('abc'.includes(undefined), false); -assertEquals('aundefinedb'.includes(undefined), true); -assertEquals('abc'.includes(null), false); -assertEquals('anullb'.includes(null), true); -assertEquals('abc'.includes(false), false); -assertEquals('afalseb'.includes(false), true); -assertEquals('abc'.includes(NaN), false); -assertEquals('aNaNb'.includes(NaN), true); -assertEquals('abc'.includes('abc'), true); -assertEquals('abc'.includes('def'), false); -assertEquals('abc'.includes(''), true); -assertEquals(''.includes(''), true); + t.test('pos argument', function(st) { + st.equals(includes('abc', 'b', -Infinity), true); + st.equals(includes('abc', 'b', -1), true); + st.equals(includes('abc', 'b', -0), true); + st.equals(includes('abc', 'b', +0), true); + st.equals(includes('abc', 'b', NaN), true); + st.equals(includes('abc', 'b', 'x'), true); + st.equals(includes('abc', 'b', false), true); + st.equals(includes('abc', 'b', undefined), true); + st.equals(includes('abc', 'b', null), true); + st.equals(includes('abc', 'b', 1), true); + st.equals(includes('abc', 'b', 2), false); + st.equals(includes('abc', 'b', 3), false); + st.equals(includes('abc', 'b', 4), false); + st.equals(includes('abc', 'b', +Infinity), false); + st.end(); + }); -assertEquals('abc'.includes('b', -Infinity), true); -assertEquals('abc'.includes('b', -1), true); -assertEquals('abc'.includes('b', -0), true); -assertEquals('abc'.includes('b', +0), true); -assertEquals('abc'.includes('b', NaN), true); -assertEquals('abc'.includes('b', 'x'), true); -assertEquals('abc'.includes('b', false), true); -assertEquals('abc'.includes('b', undefined), true); -assertEquals('abc'.includes('b', null), true); -assertEquals('abc'.includes('b', 1), true); -assertEquals('abc'.includes('b', 2), false); -assertEquals('abc'.includes('b', 3), false); -assertEquals('abc'.includes('b', 4), false); -assertEquals('abc'.includes('b', +Infinity), false); -assertEquals('abc'.includes('bc'), true); -assertEquals('abc'.includes('bc\0'), false); + t.test('cast stringSearch arg with pos - included', function(st) { + st.equals(includes('abc123def', 1, -Infinity), true); + st.equals(includes('abc123def', 1, -1), true); + st.equals(includes('abc123def', 1, -0), true); + st.equals(includes('abc123def', 1, +0), true); + st.equals(includes('abc123def', 1, NaN), true); + st.equals(includes('abc123def', 1, 'x'), true); + st.equals(includes('abc123def', 1, false), true); + st.equals(includes('abc123def', 1, undefined), true); + st.equals(includes('abc123def', 1, null), true); + st.equals(includes('abc123def', 1, 1), true); + st.equals(includes('abc123def', 1, 2), true); + st.equals(includes('abc123def', 1, 3), true); + st.equals(includes('abc123def', 1, 4), false); + st.equals(includes('abc123def', 1, 5), false); + st.equals(includes('abc123def', 1, +Infinity), false); + st.end(); + }); -assertEquals('abc123def'.includes(1, -Infinity), true); -assertEquals('abc123def'.includes(1, -1), true); -assertEquals('abc123def'.includes(1, -0), true); -assertEquals('abc123def'.includes(1, +0), true); -assertEquals('abc123def'.includes(1, NaN), true); -assertEquals('abc123def'.includes(1, 'x'), true); -assertEquals('abc123def'.includes(1, false), true); -assertEquals('abc123def'.includes(1, undefined), true); -assertEquals('abc123def'.includes(1, null), true); -assertEquals('abc123def'.includes(1, 1), true); -assertEquals('abc123def'.includes(1, 2), true); -assertEquals('abc123def'.includes(1, 3), true); -assertEquals('abc123def'.includes(1, 4), false); -assertEquals('abc123def'.includes(1, 5), false); -assertEquals('abc123def'.includes(1, +Infinity), false); + t.test('cast stringSearch arg with pos - not included', function(st) { + st.equals(includes('abc123def', 9, -Infinity), false); + st.equals(includes('abc123def', 9, -1), false); + st.equals(includes('abc123def', 9, -0), false); + st.equals(includes('abc123def', 9, +0), false); + st.equals(includes('abc123def', 9, NaN), false); + st.equals(includes('abc123def', 9, 'x'), false); + st.equals(includes('abc123def', 9, false), false); + st.equals(includes('abc123def', 9, undefined), false); + st.equals(includes('abc123def', 9, null), false); + st.equals(includes('abc123def', 9, 1), false); + st.equals(includes('abc123def', 9, 2), false); + st.equals(includes('abc123def', 9, 3), false); + st.equals(includes('abc123def', 9, 4), false); + st.equals(includes('abc123def', 9, 5), false); + st.equals(includes('abc123def', 9, +Infinity), false); + st.end(); + }); -assertEquals('abc123def'.includes(9, -Infinity), false); -assertEquals('abc123def'.includes(9, -1), false); -assertEquals('abc123def'.includes(9, -0), false); -assertEquals('abc123def'.includes(9, +0), false); -assertEquals('abc123def'.includes(9, NaN), false); -assertEquals('abc123def'.includes(9, 'x'), false); -assertEquals('abc123def'.includes(9, false), false); -assertEquals('abc123def'.includes(9, undefined), false); -assertEquals('abc123def'.includes(9, null), false); -assertEquals('abc123def'.includes(9, 1), false); -assertEquals('abc123def'.includes(9, 2), false); -assertEquals('abc123def'.includes(9, 3), false); -assertEquals('abc123def'.includes(9, 4), false); -assertEquals('abc123def'.includes(9, 5), false); -assertEquals('abc123def'.includes(9, +Infinity), false); + t.test('regex searchString', function(st) { + st.equals(includes('foo[a-z]+(bar)?', '[a-z]+'), true); + st['throws'](function() { includes('foo[a-z]+(bar)?', /[a-z]+/); }, TypeError); + st['throws'](function() { includes('foo/[a-z]+/(bar)?', /[a-z]+/); }, TypeError); + st.equals(includes('foo[a-z]+(bar)?', '(bar)?'), true); + st['throws'](function() { includes('foo[a-z]+(bar)?', /(bar)?/); }, TypeError); + st['throws'](function() { includes('foo[a-z]+/(bar)?/', /(bar)?/); }, TypeError); + st.end(); + }); -assertEquals('foo[a-z]+(bar)?'.includes('[a-z]+'), true); -assertThrows(function() { 'foo[a-z]+(bar)?'.includes(/[a-z]+/); }, TypeError); -assertThrows(function() { 'foo/[a-z]+/(bar)?'.includes(/[a-z]+/); }, TypeError); -assertEquals('foo[a-z]+(bar)?'.includes('(bar)?'), true); -assertThrows(function() { 'foo[a-z]+(bar)?'.includes(/(bar)?/); }, TypeError); -assertThrows(function() { 'foo[a-z]+/(bar)?/'.includes(/(bar)?/); }, TypeError); + t.test('astral symbols', function(st) { + // https://mathiasbynens.be/notes/javascript-unicode#poo-test + var string = 'I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9'; + st.equals(string.includes(''), true); + st.equals(string.includes('\xF1t\xEBr'), true); + st.equals(string.includes('\xE0liz\xE6'), true); + st.equals(string.includes('\xF8n\u2603\uD83D\uDCA9'), true); + st.equals(string.includes('\u2603'), true); + st.equals(string.includes('\uD83D\uDCA9'), true); + st.end(); + }); -// https://mathiasbynens.be/notes/javascript-unicode#poo-test -var string = 'I\xF1t\xEBrn\xE2ti\xF4n\xE0liz\xE6ti\xF8n\u2603\uD83D\uDCA9'; -assertEquals(string.includes(''), true); -assertEquals(string.includes('\xF1t\xEBr'), true); -assertEquals(string.includes('\xE0liz\xE6'), true); -assertEquals(string.includes('\xF8n\u2603\uD83D\uDCA9'), true); -assertEquals(string.includes('\u2603'), true); -assertEquals(string.includes('\uD83D\uDCA9'), true); + t.test('nullish this object', function(st) { + st['throws'](function() { includes(undefined); }, TypeError); + st['throws'](function() { includes(undefined, 'b'); }, TypeError); + st['throws'](function() { includes(undefined, 'b', 4); }, TypeError); + st['throws'](function() { includes(null); }, TypeError); + st['throws'](function() { includes(null, 'b'); }, TypeError); + st['throws'](function() { includes(null, 'b', 4); }, TypeError); + st.end(); + }); -assertThrows(function() { String.prototype.includes.call(undefined); }, TypeError); -assertThrows(function() { String.prototype.includes.call(undefined, 'b'); }, TypeError); -assertThrows(function() { String.prototype.includes.call(undefined, 'b', 4); }, TypeError); -assertThrows(function() { String.prototype.includes.call(null); }, TypeError); -assertThrows(function() { String.prototype.includes.call(null, 'b'); }, TypeError); -assertThrows(function() { String.prototype.includes.call(null, 'b', 4); }, TypeError); -assertEquals(String.prototype.includes.call(42, '2'), true); -assertEquals(String.prototype.includes.call(42, 'b', 4), false); -assertEquals(String.prototype.includes.call(42, '2', 4), false); -assertEquals(String.prototype.includes.call({ 'toString': function() { return 'abc'; } }, 'b', 0), true); -assertEquals(String.prototype.includes.call({ 'toString': function() { return 'abc'; } }, 'b', 1), true); -assertEquals(String.prototype.includes.call({ 'toString': function() { return 'abc'; } }, 'b', 2), false); -assertThrows(function() { String.prototype.includes.call({ 'toString': function() { throw RangeError(); } }, /./); }, RangeError); -assertThrows(function() { String.prototype.includes.call({ 'toString': function() { return 'abc'; } }, /./); }, TypeError); - -assertThrows(function() { String.prototype.includes.apply(undefined); }, TypeError); -assertThrows(function() { String.prototype.includes.apply(undefined, ['b']); }, TypeError); -assertThrows(function() { String.prototype.includes.apply(undefined, ['b', 4]); }, TypeError); -assertThrows(function() { String.prototype.includes.apply(null); }, TypeError); -assertThrows(function() { String.prototype.includes.apply(null, ['b']); }, TypeError); -assertThrows(function() { String.prototype.includes.apply(null, ['b', 4]); }, TypeError); -assertEquals(String.prototype.includes.apply(42, ['2']), true); -assertEquals(String.prototype.includes.apply(42, ['b', 4]), false); -assertEquals(String.prototype.includes.apply(42, ['2', 4]), false); -assertEquals(String.prototype.includes.apply({ 'toString': function() { return 'abc'; } }, ['b', 0]), true); -assertEquals(String.prototype.includes.apply({ 'toString': function() { return 'abc'; } }, ['b', 1]), true); -assertEquals(String.prototype.includes.apply({ 'toString': function() { return 'abc'; } }, ['b', 2]), false); -assertThrows(function() { String.prototype.includes.apply({ 'toString': function() { throw RangeError(); } }, [/./]); }, RangeError); -assertThrows(function() { String.prototype.includes.apply({ 'toString': function() { return 'abc'; } }, [/./]); }, TypeError); + t.test('cast this object', function(st) { + st.equals(includes(42, '2'), true); + st.equals(includes(42, 'b', 4), false); + st.equals(includes(42, '2', 4), false); + st.equals(includes({ 'toString': function() { return 'abc'; } }, 'b', 0), true); + st.equals(includes({ 'toString': function() { return 'abc'; } }, 'b', 1), true); + st.equals(includes({ 'toString': function() { return 'abc'; } }, 'b', 2), false); + st['throws'](function() { includes({ 'toString': function() { throw RangeError(); } }, /./); }, RangeError); + st['throws'](function() { includes({ 'toString': function() { return 'abc'; } }, /./); }, TypeError); + st.end(); + }); +}; From 0affed6ac9e621bea5862b3ec2b28af9d6a03129 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Ribaudo?= Date: Wed, 20 May 2020 17:55:45 +0000 Subject: [PATCH 6/6] Improve error messages --- implementation.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/implementation.js b/implementation.js index a85039e..15811aa 100644 --- a/implementation.js +++ b/implementation.js @@ -15,7 +15,9 @@ var indexOf = callBound('String.prototype.indexOf'); module.exports = function includes(searchString) { var O = RequireObjectCoercible(this); var S = ToString(O); - if (IsRegExp(searchString)) throw TypeError(); + if (IsRegExp(searchString)) { + throw TypeError('Argument to String.prototype.includes cannot be a RegExp'); + } var searchStr = String(searchString); var searchLength = searchStr.length; var position = arguments.length > 1 ? arguments[1] : undefined;