You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
4.9 KiB
275 lines
4.9 KiB
var test = require('tape-catch');
|
|
var plus = require('1-liners/plus');
|
|
var isNative = require('lodash.isnative');
|
|
// Shim Symbol.iterator if it's not available
|
|
require('core-js/es6/symbol');
|
|
|
|
var arrayFrom = require('./polyfill');
|
|
|
|
test('Works as expected', function(is) {
|
|
var mock = {
|
|
0: 'a',
|
|
1: 'b',
|
|
2: 'c',
|
|
length: 3,
|
|
};
|
|
|
|
is.deepEqual(
|
|
arrayFrom(mock),
|
|
['a', 'b', 'c'],
|
|
'with a mock object'
|
|
);
|
|
|
|
is.ok(
|
|
arrayFrom(mock) instanceof Array,
|
|
'– returning an array'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom({
|
|
0: 'a',
|
|
1: 'b',
|
|
2: 'c',
|
|
'a': 'left out',
|
|
'-1': 'left out',
|
|
length: 3,
|
|
}),
|
|
['a', 'b', 'c'],
|
|
'– ignoring illegal indices'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom({}),
|
|
[],
|
|
'with an empty object'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom([]),
|
|
[],
|
|
'with an empty array'
|
|
);
|
|
|
|
is.deepEqual(
|
|
(function() {return arrayFrom(arguments);})('a', 'b', 'c'),
|
|
['a', 'b', 'c'],
|
|
'with the `arguments` object'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom(['a', 'b', 'c']),
|
|
['a', 'b', 'c'],
|
|
'with an array'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom(mock, plus),
|
|
['a0', 'b1', 'c2'],
|
|
'when dealing with `mapFn`'
|
|
);
|
|
|
|
var context = {suffix: '+'};
|
|
is.deepEqual(
|
|
arrayFrom(mock,
|
|
function(item) {return (item + this.suffix);},
|
|
context
|
|
),
|
|
['a+', 'b+', 'c+'],
|
|
'when dealing with `mapFn` and `thisArg`'
|
|
);
|
|
|
|
var Transferable = function(){};
|
|
Transferable.from = arrayFrom;
|
|
|
|
is.ok(
|
|
Transferable.from([1]) instanceof Transferable,
|
|
'can be transferred to other constructor functions'
|
|
);
|
|
|
|
is.end();
|
|
});
|
|
|
|
test('Works for iterable objects', function(is) {
|
|
|
|
var SetPolyfill = require('core-js/library/fn/set');
|
|
|
|
is.deepEqual(
|
|
arrayFrom(new SetPolyfill(['a', 'b', 'c'])),
|
|
['a', 'b', 'c'],
|
|
'with Set (polyfill)'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom(new SetPolyfill(['a', 'b', 'c']).values(), plus),
|
|
['a0', 'b1', 'c2'],
|
|
'when dealing with `mapFn`'
|
|
);
|
|
|
|
var context = {suffix: '+'};
|
|
is.deepEqual(
|
|
arrayFrom(new SetPolyfill(['a', 'b', 'c']).keys(),
|
|
function(item) {return (item + this.suffix);},
|
|
context
|
|
),
|
|
['a+', 'b+', 'c+'],
|
|
'when dealing with `mapFn` and `thisArg`'
|
|
);
|
|
|
|
if(typeof Set !== 'undefined' && isNative(Set)) {
|
|
is.deepEqual(
|
|
arrayFrom(new Set(['a', 'b', 'c'])),
|
|
['a', 'b', 'c'],
|
|
'with native Set'
|
|
);
|
|
}
|
|
|
|
if(typeof Map !== 'undefined' && isNative(Map)) {
|
|
is.deepEqual(
|
|
arrayFrom(new Map()
|
|
.set('key1', 'value1')
|
|
.set('key2', 'value2')
|
|
.set('key3', 'value3')
|
|
.keys()
|
|
),
|
|
['key1', 'key2', 'key3'],
|
|
'with native Map'
|
|
);
|
|
}
|
|
|
|
var geckoIterator = {
|
|
value : 1,
|
|
'@@iterator' : function(){
|
|
var hasValue = true;
|
|
var value = this.value;
|
|
return {
|
|
next: function(){
|
|
if(hasValue) {
|
|
hasValue = false;
|
|
return { value: value, done: false };
|
|
} else {
|
|
return { done: true };
|
|
}
|
|
}
|
|
};
|
|
}
|
|
};
|
|
|
|
is.deepEqual(
|
|
arrayFrom(geckoIterator),
|
|
[1],
|
|
'when using Gecko-based "@@iterator" property.'
|
|
);
|
|
|
|
geckoIterator['@@iterator'] = null;
|
|
is.deepEqual(
|
|
arrayFrom(geckoIterator),
|
|
[],
|
|
'null iterator is like no iterator');
|
|
|
|
var Transferable = function(){};
|
|
Transferable.from = arrayFrom;
|
|
|
|
is.ok(Transferable.from(new SetPolyfill(['a'])) instanceof Transferable,
|
|
'can be transferred to other constructor functions (iterable)'
|
|
);
|
|
|
|
is.end();
|
|
});
|
|
|
|
test('Throws when things go very wrong.', function(is) {
|
|
is.throws(
|
|
function() {
|
|
arrayFrom();
|
|
},
|
|
TypeError,
|
|
'when the given object is invalid'
|
|
);
|
|
|
|
is.throws(
|
|
function() {
|
|
arrayFrom({length: 0}, /invalid/);
|
|
},
|
|
TypeError,
|
|
'when `mapFn` is invalid'
|
|
);
|
|
|
|
var invalidIterator = {};
|
|
invalidIterator[Symbol.iterator] = {};
|
|
|
|
is.throws(
|
|
function() {
|
|
arrayFrom(invalidIterator);
|
|
},
|
|
TypeError,
|
|
'when an iterable has an invalid iterator property'
|
|
);
|
|
|
|
var noIterator = {};
|
|
noIterator[Symbol.iterator] = function(){};
|
|
|
|
is.throws(
|
|
function() {
|
|
arrayFrom(noIterator);
|
|
},
|
|
TypeError,
|
|
'– no iterator returned');
|
|
|
|
var noNext = {};
|
|
noNext[Symbol.iterator] = function(){ return {}; };
|
|
|
|
is.throws(
|
|
function() {
|
|
arrayFrom(noNext);
|
|
},
|
|
TypeError,
|
|
'– no `next` function'
|
|
);
|
|
|
|
is.end();
|
|
});
|
|
|
|
test('Works for non-objects', function(is) {
|
|
is.deepEqual(
|
|
arrayFrom('a'),
|
|
['a'],
|
|
'string'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom('👺'),
|
|
['👺'],
|
|
'string(emoji)'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom('abc'),
|
|
['a', 'b', 'c'],
|
|
'string'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom('👺🍣🍻'),
|
|
['👺', '🍣', '🍻'],
|
|
'string(emoji)'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom(true),
|
|
[],
|
|
'boolean'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom(1),
|
|
[],
|
|
'number'
|
|
);
|
|
|
|
is.deepEqual(
|
|
arrayFrom(Symbol()),
|
|
[],
|
|
'symbol'
|
|
);
|
|
|
|
is.end();
|
|
});
|