Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,25 @@
(function(globals){
if (Array.prototype.find) return;

var maxInteger = Number.MAX_SAFE_INTEGER || (Math.pow(2, 53) - 1);

var find = function(predicate) {
var list = Object(this);
var length = list.length < 0 ? 0 : list.length >>> 0; // ES.ToUint32;
if (length === 0) return undefined;
// Loose implementation of ToLength:
// * It does not deal with negative numbers correctly, but it does not
// matter because it will iterate between 0 and length
// * It only casts to Integer (with |0) after making sure it has the maximum
// integer or |0 will cast Infinity to 0
var length = Math.min(Number(list.length), maxInteger) | 0;
if (typeof predicate !== 'function' || Object.prototype.toString.call(predicate) !== '[object Function]') {
throw new TypeError('Array#find: predicate must be a function');
}
if (length <= 0) return;
var thisArg = arguments[1];
for (var i = 0, value; i < length; i++) {
value = list[i];
if (predicate.call(thisArg, value, i, list)) return value;
}
return undefined;
};

if (Object.defineProperty) {
Expand Down
2 changes: 1 addition & 1 deletion tests/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,4 @@ describe('polluted Object.prototype', function() {
Object.prototype[1] = 42;
runTests();
delete Object.prototype[1];
});
});
274 changes: 274 additions & 0 deletions tests/test262.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
var chai = require('chai');
require('../index');

var globalThis = global;

describe('Test 262: Array.prototype.find', function () {
function runTestCase(fn) {
chai.assert(fn(), 'Test did not pass');
}

function $ERROR(message) {
chai.assert(false, message);
}

var assert = {
sameValue: function (actual, expected, message) {
chai.assert.strictEqual(actual, expected, message);
},
notSameValue: function (actual, expected, message) {
chai.assert.notStrictEqual(actual, expected, message);
}
};

/*
Test Array.prototype.find_callable-predicate ignored: Uses Proxy and arrow functions
*/
specify('Array.prototype.find_empty-array-undefined', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: Find on empty array should return undefined
---*/

var a = [].find(function () {
return true;
});

if (a !== undefined) {
$ERROR('#1: a !== undefined. Actual: ' + typeof a);
}

});
specify('Array.prototype.find_length-property', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: The length property of the find method is 1
---*/

if ([].find.length !== 1) {
$ERROR('1: [].find.length !== 1. Actual: ' + [].find.length);
}

});
specify('Array.prototype.find_modify-after-start', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: Array may be mutated by calls to the predicate
---*/

[1, 2, 3].find(function (v, i, arr) {
arr[i + 1] = arr[i + 1] + 1;
switch (i) {
case 0:
if (arr[i] !== 1) {
$ERROR('#1: arr[0] !== 1. Actual: ' + arr[i]);
}
break;
case 1:
if (arr[i] !== 3) {
$ERROR('#2: arr[1] !== 3. Actual: ' + arr[i]);
}
break;
case 2:
if (arr[i] !== 4) {
$ERROR('#3: arr[1] !== 4. Actual: ' + arr[i]);
}
break;
}
});

});
specify('Array.prototype.find_non-returning-predicate', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: Find with a predicate with no return value should return undefined
---*/

var a = [1, 2, 3].find(function () {});

if (a !== undefined) {
$ERROR('#1: a !== undefined. Actual: ' + typeof a);
}

});
specify('Array.prototype.find_noncallable-predicate', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: >
Array.prototype.find should throw a TypeError if
IsCallable(predicate) is false
includes: [runTestCase.js]
---*/

var uncallableValues = [
undefined,
null,
true,
this,
{},
'string',
0
];

function testcase() {
for (var i = 0, len = uncallableValues.length; i < len; i++) {
try {
[].find(uncallableValues[i]);
return false;
} catch (e) {
if (!(e instanceof TypeError)) {
return false;
}
}
}
return true;
}

runTestCase(testcase);

});
specify('Array.prototype.find_predicate-arguments', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: >
predicate is called with three arguments: the value of the
element, the index of the element, and the object being traversed.
---*/

var a = [1];

var b = a.find(function (v, i, arr) {
if (arguments.length !== 3) {
$ERROR('#1: arguments.length !== 3. Actual: ' + arguments.length);
}
if (v !== 1) {
$ERROR('#2: element value !== 1. Actual: ' + v);
}
if (i !== 0) {
$ERROR('#3: index !== 0. Actual: ' + i);
}
if (arr !== a) {
$ERROR('#4: object being traversed !== a');
}
});

});
specify('Array.prototype.find_push-after-start', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: >
Elements added to array after find has been called should not be
visited
---*/

[1].find(function (v, i, arr) {
arr.push('string');
if (v === 'string') {
$ERROR('#' + i + ': \'string\' should not be visited');
}
});

});
specify('Array.prototype.find_return-found-value', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: Find should return value if predicate returns true
---*/

var testVals = [
undefined,
null,
0,
'string',
String,
this,
true,
[1,2,3]
];

var a;

for (var i = 0, len = testVals.length; i < len; i++) {
a = testVals.find(function (v) {
return v === testVals[i];
});
if (a !== testVals[i]) {
$ERROR('#' + (i + 1) + ': a !== testVals[' + i + ']. Actual: ' + a);
}
}

});
specify('Array.prototype.find_this-defined', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: thisArg should be bound to this if provided
---*/

[1].find(function () {
assert.sameValue(this, Array, 'this should equal Array');
assert.notSameValue(this, globalThis, 'this should not equal globalThis');
}, Array);

});
specify('Array.prototype.find_this-is-object', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: Array.prototype.find should convert thisArg into an object
---*/

var dataTypes = [
undefined,
null,
true,
this,
{},
'string',
0,
function () {}
]

for (var i = 0, len = dataTypes.length; i < len; i++) {
[1].find(function () {
if (!(this instanceof Object)) {
$ERROR('#' + i + ': !(this instanceof Object). Actual: ' + typeof this);
}
}, dataTypes[i])
}

});
specify('Array.prototype.find_this-undefined', function () {
// Copyright (c) 2014 Matthew Meyers. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.

/*---
description: thisArg should be undefined if not provided
---*/

[1].find(function () {
if (this !== globalThis) {
$ERROR('#1: this !== globalThis');
}
});

});
});