Last active
July 28, 2019 21:32
-
-
Save jaromb/f858bca0ebf387df2861bd289fe00d7e to your computer and use it in GitHub Desktop.
ES6 Katas solutions (from es6katas.org)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 52: Generator - Send value to a generator | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Pass a value to a generator', () => { | |
it('basics: get the values from a generator in two ways', function() { | |
function* generatorFunction() { | |
yield 1; | |
yield 2; | |
} | |
// way #1 | |
var convertedToAnArray = Array.from(generatorFunction()); | |
// way #2 | |
var iterator = generatorFunction(); | |
// var iteratedOver = [iterator.next().___, iterator.___]; | |
var iteratedOver = [iterator.next().value, iterator.next().value]; | |
assert.deepEqual(convertedToAnArray, iteratedOver); | |
}); | |
it('pass a value to the iterator', function() { | |
function* generatorFunction() { | |
// yield 1; | |
// yield param; | |
var param = yield 1; | |
yield param; | |
} | |
var iterator = generatorFunction(); | |
var iteratedOver = [iterator.next().value, iterator.next(2).value]; | |
assert.deepEqual([1, 2], iteratedOver); | |
}); | |
it('a value passed to the 1st `next()` call is ignored', function() { | |
function* generatorFunction() { | |
// yield 1; | |
// declare param, with the first yield equal to 1, then yield the | |
// given param in following | |
var param = yield 1; | |
yield param; | |
} | |
let iterator = generatorFunction(); | |
const values = [ | |
iterator.next('irrelevant').value, | |
iterator.next(2).value | |
]; | |
assert.deepEqual(values, [1, 2]); | |
}); | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 10: destructuring - array | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Destructuring arrays makes shorter code', () => { | |
it('extract value from array, e.g. extract 0 into x like so `let [x] = [0];`', () => { | |
let [firstValue] = [1]; | |
assert.strictEqual(firstValue, 1); | |
}); | |
it('get the last item from array', () => { | |
let [firstValue, secondValue, lastValue] = [1, 2, 3]; | |
assert.strictEqual(lastValue, 3); | |
}); | |
it('swap two variables, in one operation', () => { | |
let [x, y] = ['ax', 'why']; | |
[y, x] = [x, y]; | |
assert.deepEqual([x, y], ['why', 'ax']); | |
}); | |
it('leading commas', () => { | |
const all = ['ax', 'why', 'zet']; | |
const [,,z] = all; | |
assert.equal(z, 'zet'); | |
}); | |
it('extract from nested arrays', () => { | |
const user = [['Some', 'One'], 23]; | |
const [[firstName, surname], age] = user; | |
const expected = 'Some One = 23 years'; | |
assert.equal(`${firstName} ${surname} = ${age} years`, expected); | |
}); | |
it('chained assignments', () => { | |
let c, d; | |
let [a, b] = [c, d] = [1, 2]; | |
assert.deepEqual([a, b, c, d], [1, 2, 1, 2]); | |
}); | |
it('in for-of loop', () => { | |
for (var [,a, b] of [[0, 1, 2]]) {} | |
assert.deepEqual([a, b], [1, 2]); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 11: destructuring - string | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Destructuring also works on strings', () => { | |
it('destructure every character, just as if the string was an array', () => { | |
let [a, b, c] = 'abc'; | |
assert.deepEqual([a, b, c], ['a', 'b', 'c']); | |
// values inside array pair with values of the same index in the string | |
}); | |
it('missing characters are undefined', () => { | |
const [a,, c] = 'ab'; | |
assert.equal(c, void 0); | |
// undefined because there is no letter in the same index of the string as that index in the array | |
}); | |
it('unicode character work too', () => { | |
const [space,, coffee] = 'a ☕'; | |
assert.equal(coffee, '\u{2615}'); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 12: destructuring - object | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Destructure objects', () => { | |
it('by surrounding the left-hand variable with `{}`', () => { | |
const {x} = {x: 1}; | |
assert.equal(x, 1); | |
}); | |
describe('nested', () => { | |
it('multiple objects', () => { | |
const magic = {first: 23, second: 42}; | |
const {magic: {second}} = {magic}; | |
assert.equal(second, 42); | |
}); | |
it('object and array', () => { | |
const {z:[,x]} = {z: [23, 42]}; | |
assert.equal(x, 42); | |
}); | |
it('array and object', () => { | |
const [,[{lang}]] = [null, [{env: 'browser', lang: 'ES6'}]]; | |
assert.equal(lang, 'ES6'); | |
}); | |
}); | |
describe('interesting', () => { | |
it('missing refs become undefined', () => { | |
const {z} = {x: 1, y: 2}; | |
assert.equal(z, void 0); | |
}); | |
it('destructure from builtins (string)', () => { | |
const {substr} = '1'; | |
assert.equal(substr, String.prototype.substr); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 13: destructuring - defaults | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('When destructuring you can also provide default values', () => { | |
it('just assign a default value, like so `a=1`', () => { | |
// indicates the first value in the array should equal 1 | |
const [a=1] = []; | |
assert.equal(a, 1); | |
}); | |
it('for a missing value', () => { | |
// gives default for the 1st index value where no value exists | |
const [,b=2,] = [1,,3]; | |
assert.equal(b, 2); | |
}); | |
it('in an object', () => { | |
// can define defaults in objects like in arrays (this problem initially given with const [a,b=2]) | |
const {a, b=2} = {a: 1}; | |
assert.equal(b, 2); | |
}); | |
it('if the value is undefined', () => { | |
// adding a value for b in the const sets the undefined b in object to the default given | |
const {a, b=2} = {a: 1, b: void 0}; | |
assert.strictEqual(b, 2); | |
}); | |
it('also a string works with defaults', () => { | |
// adding a to the array before b sets a equal to 1 as both are 0th index in array and string, respectively | |
const [a,b=2] = '1'; | |
assert.equal(a, '1'); | |
assert.equal(b, 2); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 14: destructuring - parameters | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Destructuring function parameters', () => { | |
describe('destruct parameters', () => { | |
it('multiple params from object', () => { | |
const fn = ({id, name}) => { | |
// using params in curly braces brings in params matching those names from object | |
assert.equal(id, 42); | |
assert.equal(name, 'Wolfram'); | |
}; | |
const user = {name: 'Wolfram', id: 42, param3: 3, param4: 'four'}; | |
fn(user); | |
}); | |
it('multiple params from array/object', () => { | |
//indicate place in the array that you want to access value, skipping first value | |
const fn = ([,{name}]) => { | |
assert.equal(name, 'Alice'); | |
}; | |
const users = [{name: 'nobody'}, {name: 'Alice', id: 42}]; | |
fn(users); | |
}); | |
}); | |
describe('default values', () => { | |
it('for simple values', () => { | |
const fn = (id, name='Bob') => { | |
assert.strictEqual(id, 23); | |
assert.strictEqual(name, 'Bob'); | |
}; | |
fn(23); | |
//param not stated in function call, so default for name is 'Bob' | |
}); | |
it('for a missing array value', () => { | |
const defaultUser = {id: 23, name: 'Joe'}; | |
const fn = ([user=defaultUser]) => { | |
// sets user equal to a given value in case value no stated in function call | |
assert.deepEqual(user, defaultUser); | |
}; | |
fn([]); | |
}) | |
it('mix of parameter types', () => { | |
const fn = (id=1, [arr=2], {obj=3}) => { | |
// sets values for default of each of these params in case there is no value | |
assert.equal(id, 1); | |
assert.equal(arr, 2); | |
assert.equal(obj, 3); | |
}; | |
fn(void 0, [], {}); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 15: destructuring - assign | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Assign object property values to new variables while destructuring', () => { | |
describe('for simple objects', function() { | |
it('use a colon after the property name, like so `propertyName: newName`', () => { | |
const {x, y} = {x: 1, y: 1}; | |
assert.equal(y, 1); | |
}); | |
it('assign a new name and give it a default value using `= <default value>`', () => { | |
const {x: y=42} = {y: 23}; | |
assert.equal(y, 42); | |
}); | |
}); | |
describe('for function parameter names', function() { | |
it('do it the same way, with a colon behind it', () => { | |
const fn = ({x: y}) => { | |
assert.equal(y, 1); | |
}; | |
fn({x: 1}); | |
}); | |
it('giving it a default value is possible too, like above', () => { | |
const fn = ({x: y=3}) => { | |
assert.equal(y, 3); | |
}; | |
fn({}); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 16: object-literal - computed properties | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Object literal properties may be computed values', () => { | |
it('a computed property `x` needs to be surrounded by `[]`', () => { | |
const propertyName = 'x'; | |
const obj = {[propertyName]: 1}; | |
assert.equal(obj.x, 1); | |
}); | |
it('can also get a function assigned', () => { | |
const key = 'func'; | |
const obj = {[key]: () => 'seven'}; | |
assert.equal(obj.func(), 'seven'); | |
}); | |
it('the key may also be the result of a function call', () => { | |
const getName = () => 'propertyName'; | |
const obj = {[getName()]: () => {return 'seven'}}; | |
assert.equal(obj.propertyName(), 'seven'); | |
}); | |
it('the key can also be constructed by an expression', () => { | |
const what = 'Key'; | |
const obj = {['proper' + 'tyName']: null}; | |
assert('propertyName' in obj); | |
}); | |
it('accessor keys can be computed names too', () => { | |
const obj = { | |
get ['key']() {return 1}, | |
}; | |
assert.equal(obj.key, 1); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 23: class - accessors | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Class accessors (getter and setter)', () => { | |
it('a getter is defined like a method prefixed with `get`', () => { | |
class MyAccount { | |
// get money() { return Infinity; } | |
get balance() { return Infinity; } | |
} | |
assert.equal(new MyAccount().balance, Infinity); | |
}); | |
it('a setter has the prefix `set`', () => { | |
class MyAccount { | |
get balance() { return this.amount; } | |
set balance(amount) { this.amount = amount; } | |
} | |
const account = new MyAccount(); | |
// account.balance = 42; | |
account.balance = 23; | |
assert.equal(account.balance, 23); | |
}); | |
describe('dynamic accessors', () => { | |
it('a dynamic getter name is enclosed in `[]`', function() { | |
const balance = 'yourMoney'; | |
class YourAccount { | |
// get [getterName]() { return -Infinity; } | |
get [balance]() { return -Infinity; } | |
} | |
assert.equal(new YourAccount().yourMoney, -Infinity); | |
}); | |
it('a dynamic setter name as well', function() { | |
const propertyName = 'balance'; | |
class MyAccount { | |
get [propertyName]() { return this.amount; } | |
// set propertyName(amount) { this.amount = 23; } | |
set [propertyName](amount) { this.amount = 23 } | |
} | |
const account = new MyAccount(); | |
account.balance = 42; | |
// not sure why this call to account.balance doesn't change the balance | |
assert.equal(account.balance, 23); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 39: iterator - custom. Iterable is a protocol, when implemented allows objects | |
// to customize their iteration behavior, such as what values are looped over in a for..of construct. | |
// read more at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('A simple iterable without items inside, implementing the right protocol', () => { | |
// function iteratorFunction() {} | |
function iteratorFunction() { | |
return {next: function() { | |
return {done: true} | |
} | |
} | |
} | |
describe('the `iteratorFunction` needs to comply to the iterator protocol', function() { | |
it('must return an object', function() { | |
assert.equal(typeof iteratorFunction(), 'object'); | |
}); | |
it('the object must have a function assigned to a key `next`', function() { | |
assert.equal(typeof iteratorFunction().next, 'function'); | |
}); | |
it('calling `next()` must return an object with `{done: true}`', function() { | |
assert.deepEqual(iteratorFunction().next(), {done: true}); | |
}); | |
}); | |
// let iterable; | |
let iterable = {[Symbol.iterator]: iteratorFunction}; | |
beforeEach(function() { | |
iterable; | |
}); | |
describe('the iterable', function() { | |
it('must be an object', function() { | |
assert.equal(typeof iterable, 'object'); | |
}); | |
it('must have the iterator function assigned to the key `Symbol.iterator`', function() { | |
assert.equal(iterable[Symbol.iterator], iteratorFunction); | |
}); | |
}); | |
describe('using the iterable', function() { | |
it('it contains no values', function() { | |
// let values; | |
let values = ''; | |
for (let value of iterable) { | |
values += value; | |
} | |
assert.equal(values, ''); | |
}); | |
it('has no `.length` property', function() { | |
const hasLengthProperty = !! iterable.length; | |
// !! to determine if length in this case is truthy or falsy | |
// returns false because there is no length property (undefined) | |
// which coerces to false | |
assert.equal(hasLengthProperty, false); | |
}); | |
describe('can be converted to an array', function() { | |
it('using `Array.from()`', function() { | |
// const arr = iterable; | |
const arr = Array.from(iterable); | |
assert.equal(Array.isArray(arr), true); | |
}); | |
it('where `.length` is still 0', function() { | |
// const arr = iterable; | |
const arr = Array.from(iterable); | |
const length = arr.length; | |
assert.equal(length, 0); | |
}); | |
}); | |
}); | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 40: iterator - one example usage. Build an iterable and use it with some built-in ES6 constructs. | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
// The example is a consumable users ("consumable" is in the name just to make it | |
// more explicit that the generator will consume them): | |
// - `consumableUser` contains a consumable user, | |
// - `anyLeft` tells if there is any user left that can be consumed. | |
class ConsumableUsers { | |
constructor() { | |
this.users = ['Alice', 'Bob']; | |
} | |
get nextUser() { | |
if (this.users.length > 0) { | |
return `user: ${this.users.shift()}`; | |
} | |
return void 0; | |
} | |
get anyLeft() { | |
return this.users.length > 0; | |
} | |
} | |
describe('Iterator usages', () => { | |
let usersIterable; | |
beforeEach(function(){ | |
const consumableUsers = new ConsumableUsers(); | |
function iteratorFunction() { | |
return { | |
next: function() { | |
// unsure why the below is necessary? why does defining this | |
// constant in place of using consumableUsers.anyLeft in the | |
// object directly change the resultant value that goes into done? | |
const anyLeft = consumableUsers.anyLeft | |
return {value: consumableUsers.nextUser, done: !anyLeft} | |
} | |
} | |
} | |
// usersIterable = {} | |
usersIterable = {[Symbol.iterator]: iteratorFunction}; | |
}); | |
describe('create an iterator/iterable', function() { | |
it('the `usersIterable` should be iterable', function() { | |
const isIterable = Symbol.iterator in usersIterable; | |
assert.equal(isIterable, true); | |
}); | |
it('the iterator of `usersIterable` should return an object', function() { | |
const iterator = usersIterable[Symbol.iterator](); | |
assert.equal(typeof iterator, 'object'); | |
}); | |
it('the iterator of `usersIterable` should have a next function', function() { | |
const iterator = usersIterable[Symbol.iterator](); | |
assert.equal(typeof iterator.next, 'function'); | |
}); | |
}); | |
describe('fill the iterable with content using `ConsumableUsers`', function() { | |
describe('using the iterator', function() { | |
let iterator; | |
beforeEach(function(){ | |
iterator = usersIterable[Symbol.iterator](); | |
}); | |
it('should return `Alice` as first user', function() { | |
const firstItem = iterator.next(); | |
assert.deepEqual(firstItem, {value: "user: Alice", done: false}); | |
}); | |
it('should return `Bob` as second user', function() { | |
iterator.next(); // drop the first item | |
const secondItem = iterator.next(); | |
assert.deepEqual(secondItem, {value: "user: Bob", done: false}); | |
}); | |
it('should return `done:true`, which means there are no more items', function() { | |
iterator.next(); | |
// iterator.____(); | |
iterator.next(); | |
const beyondLast = iterator.next(); | |
assert.deepEqual(beyondLast, {value: void 0, done: true}); | |
}) | |
}); | |
describe('using built-in constructs', function() { | |
it('use `Array.from()` to convert an iterable to an array', function() { | |
// const users = usersIterable; | |
const users = Array.from(usersIterable); | |
assert.deepEqual(users, ['user: Alice', 'user: Bob']); | |
}); | |
it('use for-of to loop over an iterable', function() { | |
const users = []; | |
// for (let user in usersIterable) users.push(user); | |
for (let user of usersIterable) users.push(user); | |
// for-of is specifically used to access values of iterable objects, | |
// where for-in returns a list of keys on the iterated object | |
assert.deepEqual(users, ['user: Alice', 'user: Bob']); | |
}); | |
it('use the spread-operator to convert/add iterable to an array', function() { | |
// const users = ['noname', usersIterable]; | |
const users = ['noname', ...usersIterable]; | |
assert.deepEqual(users, ['noname', 'user: Alice', 'user: Bob']); | |
}); | |
it('destructure an iterable like an array', function() { | |
// const {firstUser, secondUser} = usersIterable; | |
const [firstUser, secondUser] = usersIterable; | |
assert.equal(firstUser, 'user: Alice'); | |
assert.equal(secondUser, 'user: Bob'); | |
}) | |
}); | |
}); | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This one is broken right now |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 1: template strings - basics | |
// To do: make all tests pass, leave the asserts unchanged! | |
// Follow the hints of the failure messages! | |
describe('A template string, is wrapped in ` (backticks) instead of \' or "', function() { | |
describe('by default, behaves like a normal string', function() { | |
it('just surrounded by backticks', function() { | |
var str = `like a string`; | |
// backticks can surround a string just like quotation marks would surround a string, | |
// and then within that template string you can now also employ variables | |
assert.equal(str, 'like a string'); | |
}); | |
}); | |
var x = 42; | |
var y = 23; | |
describe('can evaluate variables, which are wrapped in "${" and "}"', function() { | |
it('e.g. a simple variable "${x}" just gets evaluated', function() { | |
var evaluated = `x=${x}`; | |
// placing a ${} around a variable allows the variable in template string to be evaluated | |
assert.equal(evaluated, 'x=' + x); | |
}); | |
it('multiple variables get evaluated too', function() { | |
var evaluated = `${x}+${y}`; | |
// multiple variables can each be evaluated by wrapping with ${} | |
assert.equal(evaluated, x + '+' + y); | |
}); | |
}); | |
describe('can evaluate any expression, wrapped inside "${...}"', function() { | |
it('all inside "${...}" gets evaluated', function() { | |
var evaluated = `${ x + y }`; | |
// no need for wrapping each individual variable in additional `` and ${} | |
// if you simply want to evaluate a whole expression | |
assert.equal(evaluated, x+y); | |
}); | |
it('inside "${...}" can also be a function call', function() { | |
function getDomain(){ | |
return document.domain; | |
} | |
var evaluated = `${ getDomain() }`; | |
// include function inside `${}` and specify function call with trailing parentheses | |
assert.equal(evaluated, 'tddbin.com'); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 2: template strings - multiline | |
// To do: make all tests pass, leave the asserts unchanged! | |
// Follow the hints of the failure messages! | |
describe('Template string, can contain multiline content', function() { | |
it('wrap it in backticks (`) and add a newline, to span across two lines', function() { | |
var normalString = `line1\n\nline3`; | |
// new lines are designated using backslash with n, e.g. "\n" | |
// above code creates 3 lines: line1 with text 'line1', line 2 with no text, and line3 with text | |
'line3' | |
assert.equal(normalString, 'line1\n\nline3'); | |
}); | |
it('even over more than two lines', function() { | |
var multiline = `\n\n\n`; | |
// above code creates 4 lines with all lines being blank | |
assert.equal(multiline.split('\n').length, 4); | |
}); | |
describe('and expressions inside work too', function() { | |
var x = 42; | |
it('like simple variables', function() { | |
var multiline = `line 1\n\n ${x}`; | |
// expressions can be included along with instances of new lines | |
assert.equal(multiline, 'line 1\n\n 42'); | |
}); | |
it('also here spaces matter', function() { | |
var multiline = `\n\n42`; | |
assert.equal(multiline, '\n\n42'); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 3: template strings - tagged | |
// To do: make all tests pass, leave the asserts unchanged! | |
// Follow the hints of the failure messages! | |
describe('Tagged template strings, are an advanced form of template strings', function() { | |
it('syntax: prefix a template string with a function to call (without "()" around it)', function() { | |
function tagFunction(s) { | |
return s.toString(); | |
} | |
var evaluated = tagFunction `template string`; | |
assert.equal(evaluated, 'template string'); | |
}); | |
//function calls performed with backticks where expressions are involved instead of calling with () | |
describe('the tag function can access each part of the template', function() { | |
describe('the 1st parameter receives only the pure strings of the template string', function() { | |
function tagFunction(strings) { | |
return strings; | |
} | |
it('the strings are an array', function() { | |
var result = tagFunction`template string`; | |
assert.deepEqual(tagFunction`template string`, result); | |
}); | |
// calls tagFunction with strings === 'template string' | |
it('expressions are NOT passed to it', function() { | |
var tagged = tagFunction`one${23}two`; | |
assert.deepEqual(tagged, ['one', 'two']); | |
}); | |
// expression not passed, so it is skipped and next portion of the string taken | |
}); | |
describe('the 2nd and following parameters contain the values of the processed substitution', function() { | |
var one = 1; | |
var two = 2; | |
var three = 3; | |
it('the 2nd parameter contains the first expression`s value', function() { | |
function firstValueOnly(strings, firstValue) { | |
return firstValue | |
} | |
assert.equal(firstValueOnly`uno ${one}, dos ${two}`, 1); | |
// returning 'strings' would return the string components, 'firstValue' (the second param) returns the first string literal expression | |
}); | |
it('the 3rd parameter contains the second expression`s value', function() { | |
function firstValueOnly(strings, firstValue, secondValue) { | |
return secondValue; | |
} | |
assert.equal(firstValueOnly`uno ${one}, dos ${two}`, 2); | |
// secondValue, the third param, returns the second string literal expression | |
}); | |
it('using ES6 rest syntax, all values can be accessed via one variable', function() { | |
function valuesOnly(stringsArray, ...allValues) { // using the new ES6 rest syntax | |
return allValues; | |
} | |
assert.deepEqual(valuesOnly`uno=${one}, dos=${two}, tres=${three}`, [1, 2, 3]); | |
//using rest syntax ...allValues (name is interchangeable) indicates a return of all values from string literal expressions | |
}); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 4: template strings - String.raw | |
// To do: make all tests pass, leave the asserts unchanged! | |
// Follow the hints of the failure messages! | |
describe('Use the `raw` property of tagged template strings like so `s.raw`', function() { | |
it('the `raw` property accesses the string as it was entered', function() { | |
function firstChar(strings) { | |
return strings.raw; | |
} | |
assert.equal(firstChar`\n`, '\\n'); | |
}); | |
it('`raw` can access the backslash of a line-break', function() { | |
function firstCharEntered(strings) { | |
var lineBreak = strings.raw[0]; | |
return lineBreak[0]; | |
} | |
assert.equal(firstCharEntered`\n`, '\\'); | |
}); | |
describe('`String.raw` as a static function', function(){ | |
it('concats the raw strings', function() { | |
var expected = '\\n'; | |
assert.equal(String.raw`\n`, expected); | |
}); | |
it('two raw-templates-string-backslashes equal two escaped backslashes', function() { | |
const TWO_BACKSLASHES = '\\\\'; | |
assert.equal(String.raw`\\`, TWO_BACKSLASHES); | |
}); | |
it('works on unicodes too', function() { | |
var smilie = '\\u{1F600}'; | |
var actual = String.raw`\u{1F600}`; | |
assert.equal(actual, smilie); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 5: arrow functions - basics | |
// To do: make all tests pass, leave the asserts unchanged! | |
// Follow the hints of the failure messages! | |
describe('Arrow functions', function() { | |
it('are shorter to write, instead of `function(){}` write `() => {}`', function() { | |
var func = '() => {}'; | |
assert.equal('' + func, '() => {}'); | |
}); | |
it('instead `{}` use an expression, as return value', function() { | |
var func = () => 'I return too'; | |
assert.equal(func(), 'I return too'); | |
}); | |
it('one parameter can be written without parens', () => { | |
var func = p => p - 1; | |
assert.equal(func(25), 24); | |
}); | |
it('many params require parens', () => { | |
var func = (param, param1) => param + param1; | |
assert.equal(func(23, 42), 23+42); | |
}); | |
it('the function body needs parens to return an object', () => { | |
var func = () => ({iAm: 'an object'}); | |
// parentheses indicate the curly brackets inside enclose an object | |
assert.deepEqual(func(), {iAm: 'an object'}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 6: arrow functions - binding | |
// To do: make all tests pass, leave the asserts unchanged! | |
// Follow the hints of the failure messages! | |
class LexicallyBound { | |
getFunction() { | |
return () => { | |
return this; | |
// instead of having getFunction return 'new LexicallyBound' which returns a new instance of the class, returning 'this' references the specific object which contains the return statement | |
} | |
} | |
getArgumentsFunction() { | |
return () => {return arguments} | |
} | |
} | |
describe('Arrow functions have lexical `this`, no dynamic `this`', () => { | |
it('bound at definition time, use `=>`', function() { | |
var bound = new LexicallyBound(); | |
var fn = bound.getFunction(); | |
// bound.getFunction() returns "this", which is the 'new LexicallyBound()' object stored in the variable bound | |
assert.strictEqual(fn(), bound); | |
}); | |
it('can NOT bind a different context', function() { | |
var bound = new LexicallyBound(); | |
var fn = bound.getFunction(); | |
var anotherObj = {}; | |
var expected = bound; | |
assert.strictEqual(fn.call(anotherObj), expected); | |
/* fn.call(this) attempts to bind the object in anotherObj as 'this' in getFunction(), but this doesn't work in an arrow function as you can't bind to a different context. With a function() statement, you can bind and the test passes with var expected set to anotherObj */ | |
}); | |
it('`arguments` does NOT work inside arrow functions', function() { | |
var bound = new LexicallyBound(); | |
var fn = bound.getArgumentsFunction(); | |
assert.equal(fn(1, 2).length, 0); | |
/* with getArguments set to a function() call, the length comes out as 0, but since you can't access arguments in an arrow function the length would come out to 0 as arguments comes back undefined */ | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 7: block scope - let | |
// To do: make all tests pass, leave the asserts unchanged! | |
// Follow the hints of the failure messages! | |
describe('`let` restricts the scope of the variable to the current block', () => { | |
describe('`let` vs. `var`', () => { | |
it('`var` works as usual, it`s scope is the function', () => { | |
if (true) { | |
var varX = true; | |
} | |
assert.equal(varX, true); | |
}); | |
it('`let` restricts scope to inside the block', () => { | |
if (true) { | |
let letX = true; | |
} | |
assert.throws(() => console.log(letX)); | |
}); | |
}); | |
describe('`let` usage', () => { | |
it('`let` use in `for` loops', () => { | |
let obj = {x: 1}; | |
for (let key in obj) {} | |
assert.throws(() => console.log(key)); | |
}); | |
it('create artifical scope, using curly braces', () => { | |
{ | |
let letX = true; | |
} | |
assert.throws(() => console.log(letX)); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 8: block scope - const | |
// To do: make all tests pass, leave the asserts unchanged! | |
// Follow the hints of the failure messages! | |
describe('`const` is like `let` plus read-only', () => { | |
describe('scalar values are read-only', () => { | |
it('e.g. a number', () => { | |
const constNum = 0; | |
// constNum = 1; ***can't change a read-only variable | |
assert.equal(constNum, 0); | |
}); | |
it('or a string', () => { | |
const constString = 'I am a const'; | |
// constString = 'Cant change you?'; *** still can't change | |
assert.equal(constString, 'I am a const'); | |
}); | |
}); | |
const notChangeable = 23; | |
it('const scope leaks too', () => { | |
assert.equal(notChangeable, 23); | |
}); | |
describe('complex types are NOT fully read-only', () => { | |
it('array`s items can be changed', () => { | |
const arr = []; | |
arr[0] = 0; | |
arr[0] = 42 | |
assert.equal(arr[0], 42); | |
}); | |
it('object`s can be modified', () => { | |
const obj = {x: 1}; | |
obj.x = 2; | |
obj.x = 3 | |
assert.equal(obj.x, 3); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 9: object-literals - basics | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('The object literal allows for new shorthands', () => { | |
const x = 1; | |
const y = 2; | |
describe('with variables', () => { | |
it('the short version for `{x: x}` is {x}', () => { | |
const short = {y}; | |
// when the key value pair share the same value, it can be abbreviated to that value | |
assert.deepEqual(short, {y: y}); | |
}); | |
it('works with multiple variables too', () => { | |
const short = {x, y}; | |
assert.deepEqual(short, {x: x, y: y}); | |
}); | |
}); | |
describe('with methods', () => { | |
const func = () => func; | |
it('using the name only uses it as key', () => { | |
const short = {func}; | |
assert.deepEqual(short, {func: func}); | |
}); | |
it('a different key must be given explicitly, just like before ES6', () => { | |
const short = {otherKey: func}; | |
assert.deepEqual(short, {otherKey: func}); | |
}); | |
it('inline functions, can written as `obj={func(){}}` instead of `obj={func:function(){}}`', () => { | |
const short = { | |
inlineFunc() {return 'I am inline'} | |
}; | |
// function can be accessed using its name as the key rather than explicitly defining a key | |
assert.deepEqual(short.inlineFunc(), 'I am inline'); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 17: unicode - in strings | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Unicode in strings', () => { | |
it('are prefixed with `\\u` (one backslash and u)', () => { | |
// const nuclear = u2622; | |
const nuclear = '\u2622'; | |
assert.equal(nuclear, '☢'); | |
}); | |
it('value is 4 bytes/digits', () => { | |
// const nuclear = '\u26222'; | |
const nuclear = '\u2622'; | |
assert.equal(`no more ${nuclear}`, 'no more ☢'); | |
}); | |
it('even "normal" character`s values can be written as hexadecimal unicode', () => { | |
// const nuclear = `\u006B\u006A more \u2622`; | |
// n = \u006E, o = \u006F | |
const nuclear = `\u006E\u006F more \u2622`; | |
assert.equal(nuclear, 'no more ☢'); | |
}); | |
it('curly braces may surround the value', () => { | |
// const nuclear = `\u{0000000006E}\u00006F more \u2622`; | |
const nuclear = `\u{0000000006E}\u{00006F} more \u2622`; | |
assert.equal(nuclear, 'no more ☢'); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 18: rest - as-parameter | |
// To do: make all tests pass, leave the assert lines unchanged! | |
describe('Rest parameters in functions', () => { | |
it('must be the last parameter', () => { | |
// const fn = (...rest, veryLast) => { | |
const fn = (...rest) => { | |
assert.deepEqual([1, 2], rest); | |
}; | |
fn(1, 2); | |
}); | |
it('can be used to get all other parameters', () => { | |
// const fn = (firstParam, secondParam, rest) => { | |
const fn = (firstParam, secondParam, ...rest) => { | |
assert.deepEqual([3,4], rest); | |
}; | |
fn(null, 2, 3, 4); | |
}); | |
it('makes `arguments` obsolete', () => { | |
// const fn = () => { | |
const fn = (...args) => { | |
assert.deepEqual([42, 'twenty three', 'win'], args); | |
}; | |
fn(42, 'twenty three', 'win'); | |
}); | |
it('eliminate `arguments`!!!', () => { | |
// const fn = () => arguments; | |
// function defined to return all the args that are input, | |
// second const defines 'rest' as all args after the first arg | |
// so fn(1,2,3) gives 3 args, of which rest is defined as the last 2 | |
const fn = (...args) => args; | |
const [firstArg, ...rest] = fn(1, 2, 3); | |
assert.deepEqual([2, 3], rest); | |
}); | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 19: rest - with-destructuring | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Rest parameters with destructuring', () => { | |
it('must be last', () => { | |
// const [...all, last] = [1, 2, 3, 4]; | |
const [...all] = [1, 2, 3, 4]; | |
assert.deepEqual(all, [1, 2, 3, 4]); | |
}); | |
it('assign rest of an array to a variable', () => { | |
// const [...all] = [1, 2, 3, 4]; | |
const [first, ...all] = [1, 2, 3, 4]; | |
assert.deepEqual(all, [2, 3, 4]); | |
}); | |
// the following are actually using `spread` ... oops, to be fixed #TODO | |
it('concat differently', () => { | |
const theEnd = [3, 4]; | |
// const allInOne = [1, 2, ...[theEnd]]; | |
const allInOne = [1, 2, ...theEnd]; | |
assert.deepEqual(allInOne, [1, 2, 3, 4]); | |
}); | |
it('`apply` made simple, even for constructors', () => { | |
const theDate = [2015, 1, 1]; | |
// const date = new Date(theDate); | |
const date = new Date(...theDate); | |
// when 'new Date' takes in an array, the second value is the month | |
// number, but when taking 3 values the first arg is year, second | |
// is monthIndex (0 for Jan, 1 for Feb, ...), third is day. Arrays | |
// taken in are handled as strings, e.g. '2015,1,1' producing Jan 1 2015 | |
// where handling as multiple args produced Feb 1 2015 | |
assert.deepEqual(new Date(2015, 1, 1), date); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 20: spread - with-arrays | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Spread syntax with arrays', () => { | |
describe('basically', () => { | |
it('expands the items of an array by prefixing it with `...`', function() { | |
const middle = [1, 2, 3]; | |
// const arr = [0, middle, 4]; | |
const arr = [0, ...middle, 4]; | |
assert.deepEqual(arr, [0, 1, 2, 3, 4]); | |
}); | |
it('an empty array expanded is no item', function() { | |
// const arr = [0, [], 1]; | |
const arr = [0, ...[], 1]; | |
assert.deepEqual(arr, [0, 1]); | |
}); | |
}); | |
describe('is (in a way) the opposite to the rest syntax', function() { | |
it('both use `...` to either expand all items and collect them', function() { | |
// const [...rest] = [...[,1, 2, 3, 4, 5]]; | |
const [...rest] = [...[1, 2, 3, 4, 5]]; | |
assert.deepEqual(rest, [1, 2, 3, 4, 5]); | |
}); | |
it('rest syntax must be last in an array, spread can be used in any place', function() { | |
// const [a, b, ...rest] = [1, [2, 3], 4, 5]; | |
const [a, b, ...rest] = [1, ...[2, 3], 4, 5]; | |
assert.equal(a, 1); | |
assert.equal(b, 2); | |
assert.deepEqual(rest, [3, 4, 5]); | |
}); | |
}); | |
describe('used as function parameter', () => { | |
it('prefix with `...` to spread as function params', function() { | |
const magicNumbers = [1, 2]; | |
const fn = (magicA, magicB) => { | |
assert.deepEqual(magicNumbers[0], magicA); | |
assert.deepEqual(magicNumbers[1], magicB); | |
}; | |
// | |
fn(...magicNumbers); | |
}); | |
it('pass an array of numbers to Math.max()', function() { | |
// const max = Math.max(...[23, 0, 42, 43]); | |
const max = Math.max(...[23, 0, 42]); | |
assert.equal(max, 42); | |
}); | |
}); | |
describe('used as constructor parameter', () => { | |
it('just like in a function call (is not possible using `apply`)', () => { | |
class X { | |
constructor(a, b, c) { return [a, b, c]; } | |
} | |
// const args = [1]; | |
const args = [1, 2, 3]; | |
assert.deepEqual(new X(...args), [1, 2, 3]); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 21: spread - with-strings | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Spread syntax with strings', () => { | |
it('expands each character of a string by prefixing it with `...`', function() { | |
// const [b, a] = [...'ab']; | |
const [b, a] = [...'ba']; | |
assert.equal(a, 'a'); | |
assert.equal(b, 'b'); | |
}); | |
it('expands any kind of character', function() { | |
// const arr = [...'12']; | |
const arr = [...'1 ☢ 2']; | |
assert.deepEqual(arr, ['1', ' ', '☢', ' ', '2']); | |
}); | |
it('works anywhere inside an array (must not be last)', function() { | |
// const letters = ['a', 'bcd', 'e', 'f']; | |
const letters = ['a', ...'bcd', 'e', 'f']; | |
assert.equal(letters.length, 6); | |
}); | |
it('don`t confuse with the rest operator', function() { | |
// const [...rest] = ['1234', ...'5']; | |
const [...rest] = [...'1234', '5']; | |
assert.deepEqual(rest, [1, 2, 3, 4, 5]); | |
}); | |
it('can also be used as function parameter', function() { | |
// const max = Math.max('12345'); | |
const max = Math.max(...'12345'); | |
assert.deepEqual(max, 5); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 22: class - creation | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Class creation', () => { | |
it('is as simple as `class XXX {}`', function() { | |
// let TestClass; | |
let TestClass = class XXX {}; | |
const instance = new TestClass(); | |
assert.equal(typeof instance, 'object'); | |
}); | |
it('a class is block scoped', () => { | |
// class Inside {} returns undefined now because class is defined within a | |
// local code block, not globally | |
{class Inside {}} | |
assert.equal(typeof Inside, 'undefined'); | |
}); | |
it('the `constructor` is a special method', function() { | |
class User { | |
// constructor(id) {} | |
constructor(id) {this.id = id} | |
} | |
const user = new User(42); | |
assert.equal(user.id, 42); | |
}); | |
it('defining a method by writing it inside the class body', function() { | |
class User { | |
// method below originally not defined in tests, method can be | |
// defined like so, but may more typically include reference to | |
// params in the constructor (as shown for constructor above) | |
writesTests() { return false } | |
} | |
const notATester = new User(); | |
assert.equal(notATester.writesTests(), false); | |
}); | |
it('multiple methods need no commas (opposed to object notation)', function() { | |
class User { | |
constructor() {this.everWroteATest = false;} | |
// constructor has been added to define default value to everWroteATest | |
wroteATest() { this.everWroteATest = true; } | |
// isLazy() { } | |
isLazy() { return !this.everWroteATest } | |
// tester is lazy if never wrote a test, not lazy if it has | |
} | |
const tester = new User(); | |
assert.equal(tester.isLazy(), true); | |
tester.wroteATest(); | |
assert.equal(tester.isLazy(), false); | |
}); | |
it('anonymous class', () => { | |
// const classType = typeof {}; | |
const classType = typeof class {}; | |
assert.equal(classType, 'function'); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 24: class - static keyword | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Inside a class you can use the `static` keyword', () => { | |
describe('for methods', () => { | |
class UnitTest {} | |
it('a static method just has the prefix `static`', () => { | |
class TestFactory { | |
// makeTest() { return new UnitTest(); } | |
static makeTest() { return new UnitTest(); } | |
} | |
assert.ok(TestFactory.makeTest() instanceof UnitTest); | |
}); | |
it('the method name can be dynamic/computed at runtime', () => { | |
// const methodName = 'makeTest'; | |
const methodName = 'createTest'; | |
class TestFactory { | |
static [methodName]() { return new UnitTest(); } | |
} | |
assert.ok(TestFactory.createTest() instanceof UnitTest); | |
}); | |
}); | |
describe('for accessors', () => { | |
it('a getter name can be static, just prefix it with `static`', () => { | |
class UnitTest { | |
// get testType() { return 'unit'; } | |
static get testType() { return 'unit'; } | |
} | |
assert.equal(UnitTest.testType, 'unit'); | |
}); | |
it('even a static getter name can be dynamic/computed at runtime', () => { | |
const type = 'test' + 'Type'; | |
class IntegrationTest { | |
// get type() { return 'integration'; } | |
static get [type]() { return 'integration'; } | |
} | |
assert.ok('testType' in IntegrationTest); | |
assert.equal(IntegrationTest.testType, 'integration'); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 25: class - extends | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Classes can inherit from another using `extends`', () => { | |
describe('the default super class is `Object`', () => { | |
it('a `class A` is an instance of `Object`', () => { | |
// let A | |
class A extends Object {} | |
assert.equal(new A() instanceof Object, true); | |
}); | |
it('when B extends A, B is also instance of `Object`', () => { | |
// class A {} | |
// class B {} | |
class A extends Object {} | |
class B extends A {} | |
assert.equal(new B() instanceof A, true); | |
assert.equal(new B() instanceof Object, true); | |
}); | |
it('a class can extend `null`, and is not an instance of Object', () => { | |
// class NullClass extends Object {} | |
class NullClass extends null {} | |
let nullInstance = new NullClass(); | |
assert.equal(nullInstance instanceof Object, false); | |
}); | |
}); | |
describe('instance of', () => { | |
it('when B inherits from A, `new B()` is also an instance of A', () => { | |
// let A; | |
class A extends Object {} | |
class B extends A {} | |
assert.equal(new B() instanceof A, true); | |
}); | |
it('extend over multiple levels', () => { | |
class A {} | |
// empty line, replaced by line below | |
class B extends A {} | |
class C extends B {} | |
assert.equal(new C instanceof A, true); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 26: class - more-extends | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Classes can inherit from another', () => { | |
it('extend an `old style` "class", a function, still works', () => { | |
// let A; | |
function A() {} | |
class B extends A {} | |
assert.equal(new B() instanceof A, true); | |
}); | |
describe('prototypes are as you know them', () => { | |
class A {} | |
class B extends A {} | |
it('A is the prototype of B', () => { | |
// const isIt = A.isPrototypeOf(null); | |
const isIt = A.isPrototypeOf(B); | |
assert.equal(isIt, true); | |
}); | |
it('A`s prototype is also B`s prototype', () => { | |
// const proto = B; | |
const proto = new B; | |
// Remember: don't touch the assert!!! :) | |
assert.equal(A.prototype.isPrototypeOf(proto), true); | |
}); | |
}); | |
describe('`extends` using an expression', () => { | |
it('e.g. the inline assignment of the parent class', () => { | |
let A; | |
// class B extends (A = {}) {} | |
class B extends (A = () => {}) {} | |
assert.equal(new B() instanceof A, true); | |
}); | |
it('or calling a function that returns the parent class', () => { | |
const returnParent = (beNull) => beNull ? null : class {}; | |
// class B extends returnParent() {} | |
class B extends returnParent(true) {} | |
assert.equal(Object.getPrototypeOf(B.prototype), null); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 27: class - super inside a method | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Inside a class use `super` to access parent methods', () => { | |
it('use of `super` without `extends` fails (already when transpiling)', () => { | |
// class A {hasSuper() { return super; }} | |
class A {hasSuper() { return false; }} | |
assert.equal(new A().hasSuper(), false); | |
}); | |
it('`super` with `extends` calls the method of the given name of the parent class', () => { | |
class A {hasSuper() { return true; }} | |
// class B extends A {hasSuper() { return super.hasSuper; }} | |
class B extends A {hasSuper() { return super.hasSuper(); }} | |
assert.equal(new B().hasSuper(), true); | |
}); | |
it('when overridden a method does NOT automatically call its super method', () => { | |
class A {hasSuper() { return true; }} | |
// class B extends A {hasSuper() { return 'nothing'; }} | |
class B extends A {hasSuper() { return undefined; }} | |
assert.equal(new B().hasSuper(), void 0); | |
}); | |
it('`super` works across any number of levels of inheritance', () => { | |
class A {iAmSuper() { return true; }} | |
class B extends A {} | |
// class C extends B {iAmSuper() { return iAmSuper(); }} | |
class C extends B {iAmSuper() { return super.iAmSuper(); }} | |
assert.equal(new C().iAmSuper(), true); | |
}); | |
it('accessing an undefined member of the parent class returns `undefined`', () => { | |
class A {} | |
// class B extends A {getMethod() { return super.constructor; }} | |
class B extends A {getMethod() { return super.constructor(); }} | |
assert.equal(new B().getMethod(), void 0); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 28: class - super in constructor | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Inside a class`s constructor `super()` can be used', () => { | |
it('`extend` a class and use `super()` to call the parent constructor', () => { | |
class A {constructor() { this.levels = 1; }} | |
// class B { | |
// constructor() { | |
class B extends A { | |
constructor() { | |
super(); | |
this.levels++; | |
} | |
} | |
assert.equal(new B().levels, 2); | |
}); | |
it('`super()` may also take params', () => { | |
class A {constructor(startValue=1, addTo=1) { this.counter = startValue + addTo; }} | |
class B extends A { | |
constructor(...args) { | |
// super(); | |
super(42,2); | |
this.counter++; | |
} | |
} | |
assert.equal(new B(42, 2).counter, 45); | |
}); | |
it('it is important where you place your `super()` call!', () => { | |
class A {inc() { this.countUp = 1; }} | |
class B extends A { | |
inc() { | |
// super.inc(); | |
this.countUp = 2; | |
super.inc(); | |
return this.countUp; | |
} | |
} | |
assert.equal(new B().inc(), 1); | |
}); | |
it('use `super.constructor` to find out if there is a parent constructor', () => { | |
class ParentClassA {constructor() {"parent"}} | |
class B extends ParentClassA { | |
constructor() { | |
super(); | |
// this.isTop = '' + super.konstructer; | |
this.isTop = '' + super.constructor; | |
} | |
} | |
assert(new B().isTop.includes('ParentClassA'), new B().isTop); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 29: array - `Array.from` static method | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Array.from` converts an array-like object or list into an Array', () => { | |
const arrayLike = {0: 'one', 1: 'two', length: 2}; | |
it('call `Array.from` with an array-like object', function() { | |
// const arr = arrayLike; | |
const arr = Array.from(arrayLike); | |
assert.deepEqual(arr, ['one', 'two']); | |
}); | |
it('a DOM node`s classList object can be converted', function() { | |
const domNode = document.createElement('span'); | |
domNode.classList.add('some'); | |
domNode.classList.add('other'); | |
// const classList = domNode.classList; | |
const classList = Array.from(domNode.classList); | |
assert.equal(''+classList, ''+['some', 'other']); | |
}); | |
it('convert a NodeList to an Array and `filter()` works on it', function() { | |
const nodeList = document.createElement('span'); | |
// const divs = nodeList.filter((node) => node.tagName === 'div'); | |
const divs = Array.from(nodeList).filter((node) => node.tagName === 'div'); | |
assert.deepEqual(divs.length, 0); | |
}); | |
describe('custom conversion using a map function as second param', () => { | |
it('we can modify the value before putting it in the array', function() { | |
// const arr = Array.from(arrayLike, (value) => value); | |
const arr = Array.from(arrayLike, (value) => value.toUpperCase()); | |
assert.deepEqual(arr, ['ONE', 'TWO']); | |
}); | |
it('and we also get the object`s key as second parameter', function() { | |
// const arr = Array.from(arrayLike, (value) => `${key}=${value}`); | |
const arr = Array.from(arrayLike, (value, key) => `${key}=${value}`); | |
assert.deepEqual(arr, ['0=one', '1=two']); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 30: array - `Array.of` static method | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Array.of` creates an array with the given arguments as elements', () => { | |
it('dont mix it up with `Array(10)`, where the argument is the array length', () => { | |
// const arr = Array(10); | |
const arr = Array.of(10); | |
assert.deepEqual(arr, [10]); | |
}); | |
it('puts all arguments into array elements', () => { | |
// const arr = Array.of(); | |
const arr = Array.of(1,2); | |
assert.deepEqual(arr, [1, 2]); | |
}); | |
it('takes any kind and number of arguments', () => { | |
const starter = [1, 2]; | |
const end = [3, '4']; | |
// const arr = Array.of(...starter, ...end); | |
const arr = Array.of(starter, ...end); | |
assert.deepEqual(arr, [[1, 2], 3, '4']); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 31: array - `Array.prototype.fill` method | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Array.prototype.fill` can fill up an array with one value', () => { | |
it('`fill(0)` will populate `0` into each array element', function() { | |
// const arr = new Array(3).fill(); | |
const arr = new Array(3).fill(0); | |
assert.deepEqual(arr, [0, 0, 0]); | |
}); | |
it('fill only changes content, adds no new elements', function() { | |
// const arr = [undefined].fill(0); | |
const arr = [].fill(0); | |
assert.deepEqual(arr, []); | |
}); | |
it('second parameter to `fill()` is the position where to start filling', function() { | |
// const fillPosition = 0; | |
const fillPosition = 2; | |
const arr = [1,2,3].fill(42, fillPosition); | |
assert.deepEqual(arr, [1, 2, 42]); | |
}); | |
it('third parameter is the position where filling stops', function() { | |
const fillStartAt = 1; | |
// const fillEndAt = 1; | |
const fillEndAt = 2; | |
const arr = [1,2,3].fill(42, fillStartAt, fillEndAt); | |
assert.deepEqual(arr, [1, 42, 3]); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 32: array - `Array.prototype.find` | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Array.prototype.find` makes finding items in arrays easier', () => { | |
it('takes a compare function', function() { | |
// const found = [true].find(true) | |
const found = [true].find(x => x= true); | |
assert.equal(found, true); | |
}); | |
it('returns the first value found', function() { | |
// const found = [0, 1].find(item => item > 1); | |
const found = [0, 1, 2].find(item => item > 1); | |
assert.equal(found, 2); | |
}); | |
it('returns `undefined` when nothing was found', function() { | |
// const found = [1, 2, 3].find(item => item === 2); | |
const found = [1, 2, 3].find(item => item === 4); | |
assert.equal(found, void 0); | |
}); | |
it('combined with destructuring complex compares become short', function() { | |
const bob = {name: 'Bob'}; | |
const alice = {name: 'Alice'}; | |
// const found = [bob, alice].find(({name}) => name); | |
const found = [bob, alice].find(({name: value}) => value === 'Alice'); | |
assert.equal(found, alice); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 33: array - `Array.prototype.findIndex` | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Array.prototype.findIndex` makes finding items in arrays easier', () => { | |
it('takes a compare function, returns the index where it returned true', function() { | |
// const foundAt = [false, true].findIndex(item); | |
const foundAt = [false, true].findIndex(item => item === true); | |
assert.equal(foundAt, 1); | |
}); | |
it('returns the first position it was found at', function() { | |
// const foundAt = [0, 1, 1, 1].findIndex(item => item = 1); | |
const foundAt = [0, 1, 1, 1].findIndex(item => item === 1); | |
assert.equal(foundAt, 1); | |
}); | |
it('returns `-1` when nothing was found', function() { | |
// const foundAt = [1, 2, 3].findIndex(item => item > 1); | |
const foundAt = [1, 2, 3].findIndex(item => item > 3); | |
assert.equal(foundAt, -1); | |
}); | |
it('the findIndex callback gets the item, index and array as arguments', function() { | |
const three = 3; | |
const containsThree = arr => arr.indexOf(three) > -1; | |
// function theSecondThree(index, arr) { | |
function theSecondThree(item, index, arr) { | |
const preceedingItems = arr.slice(0, index); | |
return containsThree(preceedingItems); | |
} | |
const foundAt = [1, 1, 2, 3, 3, 3].findIndex(theSecondThree); | |
assert.equal(foundAt, 4); | |
}); | |
it('combined with destructuring complex compares become short', function() { | |
const bob = {name: 'Bob'}; | |
const alice = {name: 'Alice'}; | |
// const foundAt = [bob, alice].findIndex(({name:{length:l}}) => length > 3); | |
const foundAt = [bob, alice].findIndex(({name:value}) => value.length > 3); | |
assert.equal(foundAt, 1); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 34: symbol - basics | |
// A symbol is a unique and immutable data type and may be used as an identifier for object properties | |
// read more at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Symbol', function() { | |
it('`Symbol` lives in the global scope', function(){ | |
// const expected = someNameSpace.Symbol; | |
const expected = window.Symbol; | |
assert.equal(Symbol, expected); | |
}); | |
it('every `Symbol()` is unique', function(){ | |
const sym1 = Symbol(); | |
// const sym2 = sym1; | |
const sym2 = Symbol(); | |
assert.notEqual(sym1, sym2); | |
}); | |
it('every `Symbol()` is unique, also with the same parameter', function(){ | |
var sym1 = Symbol('foo'); | |
// var sym1 = Symbol('foo'); | |
var sym2 = Symbol('foo'); | |
assert.notEqual(sym1, sym2); | |
}); | |
it('`typeof Symbol()` returns "symbol"', function(){ | |
// const theType = typeof Symbol; | |
const theType = typeof Symbol(); | |
assert.equal(theType, 'symbol'); | |
}); | |
it('`new Symbol()` throws an exception, to prevent creation of Symbol wrapper objects', function(){ | |
function fn() { | |
// Symbol(); | |
new Symbol(); | |
} | |
assert.throws(fn); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 35: Symbol.for - retrieves or creates a runtime-wide symbol | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Symbol.for` for registering Symbols globally', function() { | |
it('creates a new symbol (check via `typeof`)', function() { | |
// const symbolType = Symbol.for('symbol name'); | |
const symbolType = typeof Symbol.for('symbol name'); | |
assert.equal(symbolType, 'symbol'); | |
}); | |
it('stores the symbol in a runtime-wide registry and retrieves it from there', function() { | |
const sym = Symbol.for('new symbol'); | |
// const sym1 = Symbol.for('new symbol1'); | |
const sym1 = Symbol.for('new symbol'); | |
assert.equal(sym, sym1); | |
}); | |
it('is different to `Symbol()` which creates a symbol every time and does not store it', function() { | |
var globalSymbol = Symbol.for('new symbol'); | |
// var localSymbol = Symbol.for('new symbol'); | |
var localSymbol = Symbol('new symbol'); | |
assert.notEqual(globalSymbol, localSymbol); | |
}); | |
describe('`.toString()` on a Symbol', function() { | |
it('also contains the key given to `Symbol.for()`', function() { | |
// const description = Symbol('').toString(); | |
var localSymbol = Symbol('new symbol'); | |
const description = localSymbol.toString(); | |
assert.equal(description, 'Symbol(new symbol)'); | |
}); | |
describe('NOTE: the description of two different symbols', function() { | |
it('might be the same', function() { | |
const symbol1AsString = Symbol('new symbol 1').toString(); | |
// const symbol2AsString = Symbol.for('new symbol').toString(); | |
const symbol2AsString = Symbol.for('new symbol 1').toString(); | |
assert.equal(symbol1AsString, symbol2AsString); | |
}); | |
it('but the symbols are not the same!', function() { | |
// const symbol1 = Symbol.for('new symbol'); | |
const symbol1 = Symbol('new symbol'); | |
const symbol2 = Symbol.for('new symbol'); | |
assert.notEqual(symbol1, symbol2); | |
}); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 37: iterator/iterable - array. | |
// The iterator protocol defines a standard way to produce a sequence of values (either finite or infinite). | |
// read more at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('The native array is a built-in iterable object', function() { | |
const arr = ['a', 'B', 'see']; | |
describe('the iterator', function() { | |
it('an array has an iterator, which is a function', function() { | |
const iterator = arr[Symbol.iterator]; | |
const theType = typeof iterator; | |
// const expected = 'iterator?'; | |
const expected = 'function'; | |
assert.equal(theType, expected); | |
}); | |
it('can be looped with `for-of`, which expects an iterable', function() { | |
let count = 0; | |
for (let value of arr) { | |
// count--; | |
count++; | |
} | |
assert.equal(count, arr.length); | |
}); | |
}); | |
describe('the iterator protocol', function() { | |
it('calling `next()` on an iterator returns an object according to the iterator protocol', function() { | |
const iterator = arr[Symbol.iterator](); | |
// const firstItem = iterator.___(); | |
const firstItem = iterator.next(); | |
assert.deepEqual(firstItem, {done: false, value: 'a'}); | |
}); | |
it('the after-last element has done=true', function() { | |
const arr = []; | |
const iterator = arr[Symbol.iterator](); | |
// const afterLast = iterator.next; | |
const afterLast = iterator.next(); | |
assert.deepEqual(afterLast, {done: true, value: void 0}); | |
}); | |
}); | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 38: iterator/iterable - string. | |
// The iterator protocol defines a standard way to produce a sequence of values (either finite or infinite). | |
// read more at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('The native string is a built-in iterable object', function() { | |
const s = 'abc'; | |
describe('string is iterable', function() { | |
it('the string`s object key `Symbol.iterator` is a function', function() { | |
// const isA = typeof s.Symbol.iterator; | |
const isA = typeof s[Symbol.iterator]; | |
assert.equal(isA, 'function'); | |
}); | |
it('use `Array.from()` to make an array out of any iterable', function(){ | |
// const arr = s; | |
const arr = Array.from(s); | |
assert.deepEqual(arr, ['a', 'b', 'c']); | |
}); | |
}); | |
describe('a string`s iterator', function() { | |
let iterator; | |
beforeEach(function() { | |
iterator = s[Symbol.iterator](); | |
}); | |
it('has a special string representation', function(){ | |
// const description = iterator.to____(); | |
const description = iterator.toString(); | |
assert.equal(description, '[object String Iterator]'); | |
}); | |
it('`iterator.next()` returns an object according to the iterator protocol', function(){ | |
// const value = iterator.___(); | |
const value = iterator.next(); | |
assert.deepEqual(value, {done: false, value: 'a'}); | |
}); | |
it('the after-last call to `iterator.next()` says done=true, no more elements', function(){ | |
const str = ''; | |
const iterator = str[Symbol.iterator](); | |
iterator.next(); | |
assert.equal(iterator.next().done, true); | |
}); | |
}); | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 41: array - entries | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`[].entries()` returns an iterator object with all entries', function() { | |
it('returns key+value for each element', function() { | |
const arr = ['a', 'b', 'c']; | |
const entriesAsArray = Array.from(arr.entries()); | |
assert.deepEqual(entriesAsArray, [[0,"a"], [1,"b"], [2,"c"]]); | |
}); | |
it('empty elements contain the value `undefined`', function() { | |
const arr = ['one']; | |
arr[2] = 'three'; | |
// const secondValue = arr.entries(); | |
const secondValue = Array.from(arr.entries())[1]; | |
assert.deepEqual(secondValue, [1, void 0]); | |
}); | |
describe('returns an iterable', function() { | |
it('has `next()` to iterate', function() { | |
const arr = ['one']; | |
// const value = arr; | |
const next = arr.entries().next() | |
// arr.entries().next() returns { value: [0, 'one'], done: false } | |
const value = next.value | |
assert.deepEqual(value, [0, 'one']); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 42: array - `Array.prototype.keys` | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Array.prototype.keys` returns an iterator for all keys in the array', () => { | |
it('`keys()` returns an iterator', function() { | |
// const arr = ['a', 'b']; | |
const arr = ['a']; | |
const iterator = arr.keys(); | |
assert.deepEqual(iterator.next(), {value: 0, done: false}); | |
assert.deepEqual(iterator.next(), {value: void 0, done: true}); | |
}); | |
it('gets all keys', function() { | |
// const arr = ['a', 'b']; | |
const arr = ['a', 'b', 'c']; | |
const keys = Array.from(arr.keys()); | |
assert.deepEqual(keys, [0, 1, 2]); | |
}); | |
it('empty array contains no keys', function() { | |
// const arr = ['empty me']; | |
const arr = []; | |
const keys = [...arr.keys()]; | |
assert.equal(keys.length, 0); | |
}); | |
it('a sparse array without real values has keys though', function() { | |
const arr = [,,]; | |
// const keys = [...arr.___()]; | |
const keys = [...arr.keys()]; | |
assert.deepEqual(keys, [0, 1]); | |
}); | |
it('also includes holes in sparse arrays', function() { | |
const arr = ['a', , 'c']; | |
// const keys = arr.keys; | |
const keys = Array.from(arr.keys()); | |
assert.deepEqual(keys, [0, 1, 2]); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 43: array - `Array.prototype.values` | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Array.prototype.values` returns an iterator for all values in the array', () => { | |
it('`values()` returns an iterator', function() { | |
// const arr = ['k', 'e', 'y']; | |
const arr = []; | |
const iterator = arr.values(); | |
assert.deepEqual(iterator.next(), {value: void 0, done: true}); | |
}); | |
it('use `iterator.next()` to drop first value', function() { | |
const arr = ['keys', 'values', 'entries']; | |
const iterator = arr.values(); | |
// iterator.___(); | |
iterator.next(); | |
assert.deepEqual([...iterator], ['values', 'entries']); | |
}); | |
it('empty array contains no values', function() { | |
// const arr = [...[...[...[...'1']]]]; | |
const arr = [...[...[...[]]]]; | |
const values = [...arr.values()]; | |
assert.equal(values.length, 0); | |
}); | |
it('a sparse array without real values has values though', function() { | |
// const arr = [, 0]; | |
const arr = [, void 0]; | |
const keys = [...arr.values()]; | |
assert.deepEqual(keys, [void 0, void 0]); | |
}); | |
it('also includes holes in sparse arrays', function() { | |
// const arr = ['a',]; | |
const arr = ['a',, 'c']; | |
assert.deepEqual([...arr.values()], ['a', void 0, 'c']); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 44: Map - basics | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Map` is a key/value map', function(){ | |
it('`Map` is a new global constructor function', function() { | |
// const typeOfMap = '???'; | |
const typeOfMap = 'function'; | |
assert.equal(typeof Map, typeOfMap); | |
}); | |
it('provides `new Map().set()` to add key+value pair, `get()` to read it by key', function() { | |
let map = new Map(); | |
// map.set('key', null); | |
// const value = map.get(); | |
map.set('key', 'value'); | |
const value = map.get('key'); | |
assert.equal(value, 'value'); | |
}); | |
it('`has()` tells if map has the given key', function() { | |
let map = new Map(); | |
map.set('key', 'value'); | |
// const hasIt = map.hazz; | |
const hasIt = map.has('key') | |
assert.equal(hasIt, true); | |
}); | |
it('a map is iterable', function() { | |
let map = new Map(); | |
map.set('1', 'one'); | |
map.set('2', 'two'); | |
// const mapAsArray = map; // hint: kata #29 http://tddbin.com/#?kata=es6/language/array-api/from | |
const mapAsArray = Array.from(map); | |
assert.deepEqual(mapAsArray, [['1', 'one'], ['2', 'two']]); | |
}); | |
it('complex types can be keys', function() { | |
const obj = {x: 1}; | |
const otherObj = {x: 1}; | |
let map = new Map(); | |
map.set(obj, ''); | |
// map.set(otherObj, ''); | |
assert.equal(map.has(otherObj), false); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 45: Map.prototype.get() | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Map.prototype.get` returns the element from the map for a key', function(){ | |
it('`get(key)` returns the value stored for this key', function() { | |
let map = new Map(); | |
map.set('key', 'value'); | |
const value = map.get('key'); | |
assert.equal(value, 'value'); | |
}); | |
it('multiple calls still return the same value', function() { | |
let map = new Map(); | |
map.set('value', 'value'); | |
var value = map.get(map.get(map.get('value'))); | |
assert.equal(value, 'value'); | |
}); | |
it('requires exactly the value as passed to `set()`', function() { | |
let map = new Map(); | |
const obj = {}; | |
// map.set({}, 'object is key'); | |
map.set(obj, 'object is key'); | |
assert.equal(map.get(obj), 'object is key'); | |
}); | |
it('leave out the key, and you get the value set for the key `undefined` (void 0)', function() { | |
let map = new Map(); | |
map.set(void 0, 'yo'); | |
// const value = map.get(___); | |
const value = map.get(); | |
assert.equal(value, 'yo'); | |
}); | |
it('returns undefined for an unknown key', function() { | |
let map = new Map(); | |
map.set(void 0, 1); | |
// const value = map.get(); | |
const value = map.get('unknown'); | |
assert.equal(value, void 0); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 46: Map.prototype.set() | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Map.prototype.set` adds a new element with key and value to a Map', function(){ | |
it('simplest use case is `set(key, value)` and `get(key)`', function() { | |
let map = new Map(); | |
// map.set(); | |
map.set('key', 'value'); | |
assert.equal(map.get('key'), 'value'); | |
}); | |
it('the key can be a complex type too', function() { | |
const noop = function() {}; | |
let map = new Map(); | |
// map.set(function() {}, 'the real noop'); | |
map.set(noop, 'the real noop'); | |
assert.equal(map.get(noop), 'the real noop'); | |
}); | |
it('calling `set()` again with the same key replaces the value', function() { | |
let map = new Map(); | |
map.set('key', 'value'); | |
// map.set('key', 'value3'); | |
map.set('key', 'value1'); | |
assert.equal(map.get('key'), 'value1'); | |
}); | |
it('`set()` returns the map object, it`s chainable', function() { | |
let map = new Map(); | |
map.set(1, 'one') | |
.set(2, 'two') | |
// chain to add key 3, value 'three' | |
.set(3, 'three') | |
; | |
assert.deepEqual([...map.keys()], [1,2,3]); | |
assert.deepEqual([...map.values()], ['one', 'two', 'three']); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 47: Set - basics | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Set` lets you store unique values of any type', function(){ | |
it('`Set` is a new global constructor function', function() { | |
// const typeOfSet = 'function'; | |
const typeOfSet = 'function'; | |
assert.equal(typeof Set, typeOfSet); | |
}); | |
it('every value in a set is unique', function() { | |
let set = new Set(); | |
set.add(1); | |
// set.add(1); value must be unique | |
set.add(2); | |
const expectedSize = 2; | |
assert.equal(set.size, expectedSize); | |
}); | |
it('the string "1" is different to the number 1', function() { | |
let set = new Set(); | |
set.add(1); | |
// string '1' is of a different type than integer 1, so still unique | |
set.add('1') | |
assert.equal(set.size, 2); | |
}); | |
it('even NaN is equal to NaN', function() { | |
let set = new Set(); | |
set.add(NaN); | |
// set.add(Na); | |
set.add(NaN); | |
assert.equal(set.size, 1); | |
}); | |
it('+0 and -0 are seen as equal', function() { | |
let set = new Set(); | |
set.add(+0); | |
set.add(0); | |
// set.add('-0'); | |
set.add(-0); | |
assert.deepEqual([...set.values()], [+0]); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 48: Set - add | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`add()` appends a new element to the end of a Set object.', function(){ | |
let set; | |
beforeEach(() => set = new Set()); | |
it('adds every value, of any type, only once', function() { | |
const fn = () => {}; | |
set.add(1); | |
set.add(1); | |
set.add(fn); | |
// set.add({fn}); | |
set.add(fn); | |
assert.equal(set.size, 2); | |
}); | |
it('is chainable', function() { | |
// set.add.add; | |
set.add(1).add(2); | |
assert.equal(set.has(2), true); | |
}); | |
it('call without params adds undefined', function() { | |
// set.add | |
set.add() | |
assert.equal(set.has(void 0), true); | |
}); | |
it('0, -0 and +0 are equal', function() { | |
// set.add(); | |
// set.add(); | |
set.add(0); | |
set.add(+0); | |
set.add(-0); | |
assert.equal(set.has(+0), true); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 49: Generator - creation | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Generators can be created in multiple ways', function() { | |
it('the most common way is by adding `*` after `function`', function() { | |
// function g() {} | |
function * g() {} | |
assertIsGenerator(g()); | |
}); | |
it('as a function expression, by adding a `*` after `function`', function() { | |
// let g = function() {}; | |
let g = function*() {}; | |
assertIsGenerator(g()); | |
}); | |
it('inside an object by prefixing the function name with `*`', function() { | |
let obj = { | |
// g() {} | |
*g() {} | |
}; | |
assertIsGenerator(obj.g()); | |
}); | |
it('computed generator names, are just prefixed with a `*`', function() { | |
const generatorName = 'g'; | |
let obj = { | |
// [generatorName]() {} | |
*[generatorName]() {} | |
}; | |
assertIsGenerator(obj.g()); | |
}); | |
it('inside a class the same way', function() { | |
const generatorName = 'g'; | |
class Klazz { | |
// [generatorName]() {} | |
*[generatorName]() {} | |
} | |
assertIsGenerator(new Klazz().g()); | |
}); | |
function assertIsGenerator(gen) { | |
const toStringed = '' + gen; | |
assert.equal(toStringed, '[object Generator]'); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 50: Generator - iterator | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Generators returns an iterable object', function() { | |
function* generatorFunction(){ | |
yield 1; | |
yield 2; | |
} | |
let generator; | |
beforeEach(() => { | |
generator = generatorFunction(); | |
}); | |
it('a generator returns an object', function() { | |
// const typeOfTheGenerator = ''; | |
const typeOfTheGenerator = 'object'; | |
assert.equal(typeof generator, typeOfTheGenerator); | |
}); | |
it('a generator object has a key `Symbol.iterator`', function() { | |
// const key = '???'; | |
const key = Symbol.iterator; | |
assert.equal(key in generator, true); | |
}); | |
it('the `Symbol.iterator` is a function', function() { | |
// const theType = typeof generator.Symbol.iterator; | |
const theType = typeof generator[Symbol.iterator]; | |
assert.equal(theType, 'function'); | |
}); | |
it('can be looped with `for-of`, which expects an iterable', function() { | |
function iterateForOf(){ | |
// for (let value of {}) { | |
for (let value of generator) { | |
// no statements needed | |
} | |
} | |
assert.doesNotThrow(iterateForOf); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 51: Generator - Yield Expressions | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Generator - `yield` is used to pause and resume a generator function', () => { | |
function* generatorFunction() { | |
yield 'hello'; | |
yield 'world'; | |
} | |
let generator; | |
beforeEach(function() { | |
generator = generatorFunction(); | |
}); | |
it('converting a generator to an array (using `Array.from`) resumes the generator until all values are received', () => { | |
// let values = Array.from(generatorFunction); | |
let values = Array.from(generatorFunction()); | |
assert.deepEqual(values, ['hello', 'world']); | |
}); | |
describe('after the first `generator.next()` call', function() { | |
it('the value is "hello"', function() { | |
// const {value} = generator.next; | |
const {value} = generator.next(); | |
assert.equal(value, 'hello'); | |
}); | |
it('and `done` is false', function() { | |
// const {done} = generator; | |
const {done} = generator.next(); | |
assert.equal(done, false); | |
}); | |
}); | |
describe('after the second `next()` call', function() { | |
let secondItem; | |
beforeEach(function() { | |
// | |
generator.next() | |
// needs next to pass first iteration, on to second | |
secondItem = generator.next(); | |
}); | |
it('`value` is "world"', function() { | |
let {value} = secondItem; | |
assert.equal(value, 'world'); | |
}); | |
it('and `done` is still false', function() { | |
const {done} = secondItem; | |
assert.equal(done, false); | |
}); | |
}); | |
describe('after stepping past the last element, calling `next()` that often', function() { | |
it('`done` property equals true, since there is nothing more to iterator over', function() { | |
generator.next(); | |
generator.next(); | |
// let done = generator.done; | |
let {done} = generator.next(); | |
assert.equal(done, true); | |
}); | |
}); | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 53: Map - initialize | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('initialize a `Map`', function(){ | |
it('a `new Map()` is empty, has size=0', function() { | |
// const mapSize = new Map() | |
const mapSize = new Map().size; | |
assert.equal(mapSize, 0); | |
}); | |
it('init Map with `[[]]` has a size=1', function() { | |
// const mapSize = new Map().size; | |
const mapSize = new Map([[]]).size; | |
assert.equal(mapSize, 1); | |
}); | |
it('init a Map with `[[1]]` is the same as `map.set(1, void 0)`', function() { | |
// let map1 = new Map(); | |
let map1 = new Map([[1]]); | |
let map2 = new Map().set(1, void 0); | |
assertMapsEqual(map1, map2); | |
}); | |
it('init Map with multiple key+value pairs', function() { | |
const pair1 = [1, 'one']; | |
const pair2 = [2, 'two']; | |
// const map = new Map(); | |
const map = new Map([pair1, pair2]); | |
assertMapsEqual(map, new Map().set(...pair1).set(...pair2)); | |
}); | |
it('keys are unique, the last one is used', function() { | |
const pair1 = [1, 'one']; | |
const pair2 = [1, 'uno']; | |
const pair3 = [1, 'eins']; | |
const pair4 = [2, 'two']; | |
// const map = new Map([pair3, pair1, pair2, pair4]); | |
const map = new Map([pair2, pair1, pair3, pair4]); | |
assertMapsEqual(map, new Map().set(...pair3).set(...pair4)); | |
}); | |
it('init Map from an Object, is a bit of work', function() { | |
let map = new Map(); | |
const obj = {x: 1, y: 2}; | |
const keys = Object.keys(obj); | |
// keys.forEach(key => map.set(key)); | |
keys.forEach(key => map.set(key, obj[key])); | |
const expectedEntries = [['x', 1], ['y', 2]]; | |
assertMapsEqual(map, expectedEntries); | |
}); | |
}); | |
function mapToArray(map) { | |
return Array.from(map); | |
} | |
function assertMapsEqual(map1, map2) { | |
assert.deepEqual(mapToArray(map1), mapToArray(map2)); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ES6 - 54: Object - is | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Object.is()` determines whether two values are the same', function(){ | |
describe('scalar values', function() { | |
it('1 is the same as 1', function() { | |
// const areSame = Object.is(1, '???'); | |
const areSame = Object.is(1, 1); | |
assert(areSame); | |
}); | |
it('int 1 is different to string "1"', function() { | |
// const areSame = Object.___(1, '1'); | |
const areSame = Object.is(1, '1'); | |
assert(areSame === false); | |
}); | |
it('strings just have to match', function() { | |
// const areSame = Object.is('one', 'two'); | |
const areSame = Object.is('one', 'one'); | |
assert(areSame); | |
}); | |
it('+0 is not the same as -0', function() { | |
// const areSame = -1; | |
const areSame = false; | |
assert.equal(Object.is(+0, -0), areSame); | |
}); | |
it('NaN is the same as NaN', function() { | |
// const number = 0; | |
const number = 0/0; // 0/0 === NaN | |
assert.equal(Object.is(NaN, number), true); | |
}); | |
}); | |
describe('coercion, as in `==` and `===`, does NOT apply', function() { | |
it('+0 != -0', function() { | |
// const coerced = +0 === -0; | |
const coerced = +0 !== -0; | |
const isSame = Object.is(+0, -0); | |
assert.equal(isSame, coerced); | |
}); | |
it('empty string and `false` are not the same', function() { | |
const emptyString = ''; | |
// const isSame = Object.is(emptyString, false); | |
const isSame = !Object.is(emptyString, false); | |
assert.equal(isSame, emptyString == false); | |
}); | |
it('NaN', function() { | |
const coerced = NaN !== NaN; | |
const isSame = Object.is(NaN, NaN); | |
assert.equal(isSame, coerced); | |
}); | |
it('NaN 0/0', function() { | |
const isSame = Object.is(NaN, 0/0); | |
assert.equal(isSame, true); | |
}); | |
}); | |
describe('complex values', function() { | |
it('`{}` is just not the same as `{}`', function() { | |
const areSame = {} == {}; | |
assert(Object.is({}, {}) === areSame); | |
}); | |
it('Map', function() { | |
let map1 = new Map([[1, 'one']]); | |
let map2 = new Map([[1, 'one']]); | |
const areSame = Object.is(map1, map2); | |
assert.equal(areSame, false); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 55: Number - isInteger | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Number.isInteger()` determines if a value is an integer', function(){ | |
it('`isInteger` is a static function on `Number`', function() { | |
// const whatType = 'method'; | |
const whatType = 'function'; | |
assert.equal(typeof Number.isInteger, whatType); | |
}); | |
describe('zero in different ways', function() { | |
it('0 is an integer', function() { | |
// const zero = null; | |
const zero = 0; | |
assert(Number.isInteger(zero)); | |
}); | |
it('0.000', function() { | |
// const veryZero = 0.000001; | |
const veryZero = 0.000000; | |
assert(Number.isInteger(veryZero)); | |
}); | |
it('the string "0" is NOT an integer', function() { | |
// const stringZero = 0; | |
const stringZero = '0'; | |
assert(Number.isInteger(stringZero) === false); | |
}); | |
}); | |
describe('one in different ways', function() { | |
it('0.111 + 0.889', function() { | |
// const rest = 0.88; | |
const rest = 0.889; | |
assert(Number.isInteger(0.111 + rest)); | |
}); | |
it('0.5 + 0.2 + 0.2 + 0.1 = 1 ... isn`t it?', function() { | |
// const oneOrNot = 0.5 + 0.2 + 0.3; evaluates to 1 | |
const oneOrNot = 0.5 + 0.2 + 0.2 + 0.1; // evaluates to 1.09999... | |
assert(Number.isInteger(oneOrNot) === false); | |
}); | |
it('parseInt`ed "1" is an integer', function() { | |
// const convertedToInt = Number.parse('1.01'); | |
const convertedToInt = Number.parseInt('1.01'); | |
assert(Number.isInteger(convertedToInt)); | |
}); | |
}); | |
describe('what is not an integer', function() { | |
it('`Number()` is an integer', function() { | |
// const numberOne = Number; | |
const numberOne = Number(); | |
assert(Number.isInteger(numberOne)); | |
}); | |
it('`{}` is NOT an integer', function() { | |
// const isit = Number.isWhat({}); | |
const isit = Number.isInteger({}); | |
assert(isit === false); | |
}); | |
it('`0.1` is not an integer', function() { | |
// const isit = Number.isInteger(0.1); | |
const isit = Number.isInteger(0.1); | |
assert(isit === false); | |
}); | |
it('`Number.Infinity` is not an integer', function() { | |
// const isit = Number.isInteger(Number.MAX_VALUE); | |
const isit = Number.isInteger(Number.Infinity); | |
assert(isit === false); | |
}); | |
it('`NaN` is not an integer', function() { | |
// const isit = Number.isFloat(NaN); | |
const isit = Number.isInteger(NaN); | |
assert(isit === false); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 56: Generator - Send function to a generator | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Pass a function to a generator', () => { | |
it('the generator can receive a function as a value', function() { | |
let fn = function() {}; | |
function* generatorFunction() { | |
// can yield a function | |
yield fn; | |
assert.equal(yield null, fn); // remember, don't touch this line | |
} | |
let iterator = generatorFunction(); | |
iterator.next(); | |
iterator.next(); | |
}); | |
it('pass a function to the iterator, which calls it', function() { | |
function* generatorFunction() { | |
// yield (yield 1)(); | |
yield (yield 1)(yield 2); | |
} | |
var iterator = generatorFunction(); | |
var iteratedOver = [iterator.next().value, iterator.next().value]; | |
assert.deepEqual([1, 2], iteratedOver); | |
}); | |
it('nesting yielded function calls', function() { | |
function* generatorFunction() { | |
// yield (yield (yield 1)()); | |
// } | |
// var iteratedOver = []; | |
yield (yield (yield 1)(yield (yield 2)(yield 3))); | |
} | |
var iterator = generatorFunction(); | |
var iteratedOver = [iterator.next().value, iterator.next().value, iterator.next().value]; | |
assert.deepEqual([1, 2, 3], iteratedOver); | |
}); | |
}); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 57: Default parameters - basics | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('Default parameters make function parameters more flexible', () => { | |
it('define it using an assignment to the parameter `function(param=1){}`', function() { | |
// let number = (int) => int; | |
let number = (int=0) => int; | |
assert.equal(number(), 0); | |
}); | |
it('it is used when `undefined` is passed', function() { | |
let number = (int = 23) => int; | |
// const param = 42; | |
const param = undefined; | |
// or simply when declared without value, e.g. let param | |
assert.equal(number(param), 23); | |
}); | |
it('it is not used when a value is given', function() { | |
// function xhr() { | |
// return method; | |
// } | |
function xhr(method = 'PUT') { | |
return method; | |
} | |
assert.equal(xhr('POST'), 'POST'); | |
}); | |
it('it is evaluated at run time', function() { | |
// let defaultValue; | |
let defaultValue = 42; | |
function xhr(method = `value: ${defaultValue}`) { | |
return method; | |
} | |
assert.equal(xhr(), 'value: 42'); | |
}); | |
it('it can also be a function', function() { | |
// const defaultValue = 0; | |
const defaultValue = () => { | |
return 'defaultValue' | |
} | |
function fn(value = defaultValue()) { | |
return value; | |
} | |
assert.equal(fn(), 'defaultValue'); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 58: Reflect - basics | |
// To do: make all tests pass, leave the assert lines unchanged! | |
describe('`Reflect` basics', function() { | |
describe('Reflect is special, it is different to e.g. `Object`', function() { | |
it('it`s of type object', function() { | |
// const expectedType = 'not a function!'; | |
const expectedType = 'object'; | |
assert.equal(typeof Reflect, expectedType); | |
}); | |
it('it can not be instantiated (`new Reflect()`)', function() { | |
// const tryToConstruct = () => { Reflect; }; | |
const tryToConstruct = () => { new Reflect; }; | |
assert.throws(tryToConstruct, TypeError); | |
}); | |
it('has no `call` method (as opposed to e.g. Object)', function() { | |
// const expected = 'function'; | |
const expected = 'undefined'; | |
assert.equal(typeof Reflect.call, expected); | |
}); | |
}); | |
describe('some `Reflect` usages', function() { | |
it('`Reflect.construct()` is like `new ClassName`', function() { | |
// let Class | |
class Class {}; | |
assert.equal(Reflect.construct(Class, []) instanceof Class, true); | |
}); | |
it('`Reflect.get()` returns a property`s value', function() { | |
// let obj = {x: 42}; | |
let obj = {x: 23}; | |
assert.equal(Reflect.get(obj, 'x'), 23); | |
}); | |
it('`Reflect.has()` is like `in` just as a function', function() { | |
// let obj = {}; | |
let obj = {x: 'value'}; | |
assert.equal(Reflect.has(obj, 'x'), true); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 59: Reflect - apply | |
// To do: make all tests pass, leave the assert lines unchanged! | |
describe('`Reflect.apply` calls a target function', function() { | |
it('it is a static method', function() { | |
const expectedType = 'function'; | |
assert.equal(typeof Reflect.apply, expectedType) | |
}); | |
describe('the 1st parameter', () => { | |
it('is a callable, e.g. a function', () => { | |
// let fn; | |
let fn = () => { return 42 }; | |
assert.equal(Reflect.apply(fn, void 0, []), 42); | |
}); | |
it('passing it a non-callable throws a TypeError', function() { | |
const applyOnUncallable = () => | |
// Reflect.apply(() => {}, void 0, []); | |
Reflect.apply({}, void 0, []); | |
assert.throws(applyOnUncallable, TypeError); | |
}); | |
}); | |
describe('the 2nd parameter', () => { | |
it('is the scope (or the `this`)', function() { | |
class FourtyTwo { | |
constructor() { this.value = 42} | |
fn() {return this.value} | |
} | |
let instance = new FourtyTwo(); | |
// const fourtyTwo = Reflect.apply(instance.fn, ___, []); | |
const fourtyTwo = Reflect.apply(instance.fn, instance, []); | |
assert.deepEqual(fourtyTwo, 42); | |
}); | |
}); | |
describe('the 3rd parameter', () => { | |
it('must be an array (or array-like)', () => { | |
// const thirdParam = ['should be array-like']; | |
const thirdParam = []; | |
assert.doesNotThrow(() => Reflect.apply(() => void 0, null, thirdParam)); | |
}); | |
it('is an array of parameters passed to the call', function() { | |
// let emptyArrayWithFiveElements = Reflect.apply(Array); | |
// params are: callable item, scope, array (here indicating number of paramaters to be passed) | |
let emptyArrayWithFiveElements = Reflect.apply(Array, null, [5]); | |
assert.deepEqual(emptyArrayWithFiveElements.fill(42), [42, 42, 42, 42, 42]); | |
}); | |
}); | |
describe('example usages', () => { | |
it('simple function call', () => { | |
// const fn = () => ':('; | |
const fn = () => 'the return value'; | |
assert.equal(Reflect.apply(fn, void 0, []), 'the return value'); | |
}); | |
it('call a function on an array', () => { | |
// const fn = [].push; | |
const fn = [].splice; | |
assert.deepEqual(Reflect.apply(fn, [0, 23, 42], [1]), [23, 42]); | |
}); | |
it('pass in the `this` that the function to call needs', () => { | |
class Bob { | |
constructor() { this._name = 'Bob'; } | |
name() { return this._name; } | |
} | |
const bob = new Bob(); | |
// const scope = Bob; | |
const scope = bob; | |
assert.equal(Reflect.apply(bob.name, scope, []), 'Bob'); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 60: Reflect - getPrototypeOf | |
// To do: make all tests pass, leave the assert lines unchanged! | |
describe('`Reflect.getPrototypeOf` returns the prototype', function() { | |
it('works like `Object.getPrototypeOf`', function() { | |
const viaObject = Object.getPrototypeOf({}); | |
// const viaReflect = Reflect.getPrototypeOf(); | |
const viaReflect = Reflect.getPrototypeOf({}); | |
assert.strictEqual(viaObject, viaReflect); | |
}); | |
it('throws a TypeError for a non-object', function() { | |
// let fn = () => { Reflect.getPrototypeOf({}) }; | |
let fn = () => { Reflect.getPrototypeOf('non-object') }; | |
assert.throws(fn, TypeError); | |
}); | |
it('a `new Set()` has a prototype', function() { | |
// const aSet = Set; | |
const aSet = new Set(); | |
assert.equal(Reflect.getPrototypeOf(aSet), Set.prototype); | |
}); | |
it('for a class, it is `Klass.prototype`', function() { | |
class Klass {} | |
// const proto = new Klass(); | |
const proto = Reflect.getPrototypeOf(new Klass); | |
assert.equal(proto, Klass.prototype); | |
}); | |
it('works also for an old-style "class"', function() { | |
function Klass() {} | |
// const proto = Reflect.getPrototypeOf(); | |
const proto = Reflect.getPrototypeOf(new Klass); | |
assert.equal(proto, Klass.prototype); | |
}); | |
it('an array has a prototype too', function() { | |
let arr = []; | |
// const expectedProto = Array; | |
const expectedProto = Array.prototype; | |
assert.equal(Reflect.getPrototypeOf(arr), expectedProto); | |
}); | |
// TODO | |
// it('getting the prototype of an "exotic namespace object" returns `null`', function() { | |
// http://www.ecma-international.org/ecma-262/6.0/#sec-module-namespace-exotic-objects-getprototypeof | |
// Don't know how to write a test for this yet, without creating a dep in tddbin hardcoded | |
// PRs welcome | |
// assert.equal(Reflect.getPrototypeOf(namespace exotic object), null); | |
// }); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 62: Map - `has()` | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`map.has()` indicates whether an element with a key exists', function() { | |
it('finds nothing in an empty map', function() { | |
let map = new Map(); | |
// const hasKey = map.hazz(void 0); | |
const hasKey = map.has(void 0); | |
assert.equal(hasKey, false); | |
}); | |
it('finds an element by it`s key', function() { | |
let map = new Map([['key', 'VALUE']]); | |
// const hasKey = map.has(); | |
const hasKey = map.has('key'); | |
assert.equal(hasKey, true); | |
}); | |
it('finds `undefined` as key too', function() { | |
let map = new Map([[void 0, 'not defined key']]); | |
// const hasUndefinedAsKey = map; | |
const hasUndefinedAsKey = map.has(undefined); | |
assert.equal(hasUndefinedAsKey, true); | |
}); | |
it('does not coerce keys', function() { | |
let map = new Map([[1, 'one']]); | |
// const findsStringOne = true; | |
const findsStringOne = false; | |
assert.equal(map.has('1'), findsStringOne); | |
}); | |
it('after removal (using `map.delete(<key>)`) it doesnt find the element anymore', function() { | |
let map = new Map([[1, 'one']]); | |
// | |
map.delete(1); | |
assert.equal(map.has(1), false); | |
}); | |
it('adding an item (using `map.set(key, value)`) later will make `has()` return true', function() { | |
let map = new Map(); | |
// | |
map.set(undefined, 'aValue') | |
assert.equal(map.has(void 0), true); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 63: String - `includes()` | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`string.includes()` determines if a string can be found inside another one', function() { | |
describe('finding a single character', function() { | |
it('can be done (a character is also a string, in JS)', function() { | |
// const searchString = 'a'; | |
const searchString = 'x'; | |
assert.equal('xyz'.includes(searchString), true); | |
}); | |
it('reports false if character was not found', function() { | |
// const expected = '???'; | |
const expected = false; | |
assert.equal('xyz'.includes('abc'), expected); | |
}); | |
}); | |
describe('find a string', function() { | |
it('that matches exactly', function() { | |
// const findSome = findMe => 'xyz'.includes; | |
const findSome = findMe => 'xyz'.includes(findMe); | |
assert.equal(findSome('xyz'), true); | |
}); | |
}); | |
describe('search for an empty string, is always true', function() { | |
it('in an empty string', function() { | |
// const emptyString = ' '; | |
const emptyString = ''; | |
assert.equal(''.includes(emptyString), true); | |
}); | |
it('in `abc`', function() { | |
// const actual = _.includes(''); | |
const actual = 'abc'.includes(''); | |
assert.equal(actual, true); | |
}); | |
}); | |
describe('special/corner cases', function() { | |
it('search for `undefined` in a string fails', function() { | |
// const findInAbc = (what) => 'abc'.includes; | |
const findInAbc = (what) => 'abc'.includes(what); | |
assert.equal(findInAbc(undefined), false); | |
}); | |
it('searches are case-sensitive', function() { | |
// const findInAbc = (what) => 'abc'.inkludez(what); | |
const findInAbc = (what) => 'abc'.includes(what); | |
assert.equal(findInAbc('A'), false); | |
}); | |
it('must NOT be a regular expression', function() { | |
// const regExp = ''; | |
const regExp = /\w+/; | |
assert.throws(() => {''.includes(regExp)}); | |
}); | |
describe('coerces the searched "thing" into a string', function() { | |
it('e.g. from a number', function() { | |
// const actual = '123'.includes(4); | |
const actual = '123'.includes(3); | |
assert.equal(actual, true); | |
}); | |
it('e.g. from an array', function() { | |
// const actual = '123'.includes([1,2,3]); | |
const actual = '123'.includes([123]); | |
assert.equal(actual, true); | |
}); | |
it('e.g. from an object, with a `toString()` method', function() { | |
// const objWithToString = {toString: 1}; | |
const objWithToString = {toString: () => 1}; | |
// think of key-value pair as reading key = value, | |
// so the method is a function toString = () => 1 in arrow notation | |
assert.equal('123'.includes(objWithToString), true); | |
}); | |
}); | |
}); | |
describe('takes a position from where to start searching', function() { | |
it('does not find `a` after position 1 in `abc`', function() { | |
// const position = 0; | |
const position = 1; | |
assert.equal('abc'.includes('a', position), false); | |
}); | |
it('even the position gets coerced', function() { | |
// const findAtPosition = position => 'xyz'.includes('x', pos); | |
const findAtPosition = pos => 'xyz'.includes('x', pos); | |
assert.equal(findAtPosition('2'), false); | |
}); | |
describe('invalid positions get converted to 0', function() { | |
it('e.g. `undefined`', function() { | |
// const findAtPosition = (pos=2) => 'xyz'.includes('x', pos); | |
const findAtPosition = (pos=undefined) => 'xyz'.includes('x', pos); | |
assert.equal(findAtPosition(undefined), true); | |
}); | |
it('negative numbers', function() { | |
// const findAtPosition = (pos) => 'xyz'.includes('x', -pos); | |
const findAtPosition = (pos) => 'xyz'.includes('x', pos); | |
assert.equal(findAtPosition(-2), true); | |
}); | |
it('NaN', function() { | |
// const findAtPosition = (pos) => 'xyz'.includes('x', 1); | |
const findAtPosition = (pos) => 'xyz'.includes('x', NaN); | |
assert.equal(findAtPosition(NaN), true); | |
}); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 64: Set - delete | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`set.delete()` deletes an element from a set', function(){ | |
let set; | |
beforeEach(() => set = new Set()); | |
describe('use `delete(<value>)` to delete an element', function() { | |
beforeEach(function() { | |
set.add('one').add('two').add('three'); | |
}); | |
it('`delete()` returns `true` when the element was found', function() { | |
// const returns = set.remove; | |
const returns = set.delete('one'); | |
assert.strictEqual(returns, true); | |
}); | |
it('and the size decreases', function() { | |
// | |
set.delete('one') | |
assert.equal(set.size, 2); | |
}); | |
}); | |
describe('if nothing was deleted (no element with the given value was found)', function() { | |
it('returns `false`', function() { | |
set.add('one'); | |
// const returns = set.delete('one'); | |
const returns = set.delete('two'); | |
assert.equal(returns, false); | |
}); | |
}); | |
describe('`undefined` is a valid value in a set', function() { | |
it('deleting it, when it is not in the set, returns `false` too', function() { | |
// initializing without a value is the same as whatToDelete = undefined | |
let whatToDelete; | |
assert.equal(set.delete(whatToDelete), false); | |
}); | |
it('`delete()` removes it, when its in the set', function() { | |
// performing set.add() without a value adds an undefined value to the set | |
set.add() | |
assert.equal(set.delete(), true); | |
}); | |
}); | |
describe('the value does NOT get casted', function() { | |
it('number 1 is different to string "1"', function() { | |
set.add(1); | |
// set.add('1'); | |
assert.equal(set.delete('1'), false); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 65: Set - API overview | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Set` API overview', function(){ | |
const api = ['size', 'add', 'clear', 'delete', 'entries', 'forEach', 'has', 'keys', 'values']; | |
let set; | |
beforeEach(function() { | |
set = new Set(api); | |
}); | |
it('a Set can be created from an array', function() { | |
// let set = new Set([]); | |
let set = new Set(api); | |
assert.deepEqual(Array.from(set), api); | |
}); | |
it('`size` is the number of values', function() { | |
// const theSize = set.count; | |
const theSize = set.size; | |
assert.equal(theSize, api.length); | |
}); | |
it('`add()` appends the given value', function() { | |
// Hint: To make the content of `api` and `set` consistent you can add the | |
// `Symbol.iterator` to the `set`. Strongly speaking it is missing in the API. | |
set.add(Symbol.iterator) | |
assert.equal(set.size, api.length + 1); | |
}); | |
it('`clear()` removes all elements', function() { | |
// | |
set.clear() | |
assert.equal(set.size, 0); | |
}); | |
it('`delete()` removes the given value', function() { | |
// | |
set.delete('add') | |
assert.equal(set.size, api.length - 1); | |
}); | |
it('`entries()` returns an iterator for all values', function() { | |
const expectedEntries = api.map(entry => [entry, entry]); | |
// const actualEntries = set.entry; | |
const actualEntries = set.entries(); | |
assert.deepEqual([...actualEntries], expectedEntries); | |
}); | |
it('`forEach()` calls a callback for each value', function() { | |
let values = []; | |
// set.map(value => { values.push(value); }); | |
set.forEach(value => { values.push(value); }); | |
assert.deepEqual(values, api); | |
}); | |
it('`has()` returns true if the given value is in the set', function() { | |
// const propertyName = ''; | |
const propertyName = 'add'; | |
assert.equal(set.has(propertyName), true); | |
}); | |
describe('returns an iterator that contains all values', function() { | |
// In order to be alike to `Map`, `keys()` and `values()` are essentially the same thing for a `Set`. | |
it('`keys()`', function() { | |
// const allKeys = Object.keys(set); | |
const allKeys = set.keys() | |
assert.deepEqual([...allKeys], api); | |
}); | |
it('`values()`', function() { | |
// const allValues = set.value(); | |
const allValues = set.values(); | |
assert.deepEqual([...allValues], api); | |
}); | |
it('`[Symbol.iterator]()`', function() { | |
// const iteratorKey = '???'; | |
const iteratorKey = Symbol.iterator; | |
assert.deepEqual([...set[iteratorKey]()], api); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 66: object-literal - getter | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('An object literal can also contain getters', () => { | |
it('just prefix the property with `get` (and make it a function)', function() { | |
const obj = { | |
// x() { return 'ax'; } | |
get x() { return 'ax'; } | |
}; | |
assert.equal(obj.x, 'ax'); | |
}); | |
it('must have NO parameters', function() { | |
const obj = { | |
// x(param) { return 'ax'; } | |
get x() { return 'ax'; } | |
}; | |
assert.equal(obj.x, 'ax'); | |
}); | |
it('can be a computed property (an expression enclosed in `[]`)', function() { | |
const keyName = 'x'; | |
const obj = { | |
// get keyName() { return 'ax'; } | |
get [keyName]() { return 'ax'; } | |
}; | |
assert.equal(obj.x, 'ax'); | |
}); | |
it('can be removed using delete', function() { | |
const obj = { | |
get x() { return 'ax'; } | |
}; | |
// delete obj.y; | |
delete obj.x; | |
assert.equal(obj.x, void 0); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 67: object-literal - setter | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('An object literal can also contain setters', () => { | |
describe('defining: a setter', function() { | |
it('by prefixing the property with `set` (and make it a function)', function() { | |
let theX = null; | |
const obj = { | |
// x(newX) { theX = newX; } | |
set x(newX) { theX = newX; } | |
}; | |
obj.x = 'the new X'; | |
assert.equal(theX, 'the new X'); | |
}); | |
it('must have exactly one parameter', function() { | |
// let setterCalledWith = void 0; | |
// const obj = { | |
// x() { // <<<<=== it's not a setter yet! | |
// if (arguments.length === 1) { | |
// setterCalledWith = arguments[0]; | |
let setterCalledWith = 'new value'; | |
const obj = { | |
set x(SetterCalledWith) { // <<<<=== it's not a setter yet! | |
if (arguments.length === 1) { | |
setterCalledWith = arguments[0]; | |
} | |
} | |
}; | |
assert.equal(obj.x = 'new value', setterCalledWith); | |
}); | |
it('can be a computed property (an expression enclosed in `[]`)', function() { | |
const publicPropertyName = 'x'; | |
const privatePropertyName = '_' + publicPropertyName; | |
const obj = { | |
[privatePropertyName]: null, | |
// | |
set [publicPropertyName](param) { | |
obj[privatePropertyName] = param | |
} | |
// write the complete setter to make the assert below pass :) | |
}; | |
obj.x = 'axe'; | |
assert.equal(obj._x, 'axe'); | |
}); | |
}); | |
describe('working with/on the setter', function() { | |
it('you can use `delete` to remove the property (including it`s setter)', function() { | |
let setterCalled = false; | |
const obj = { | |
set x(param) { setterCalled = true; } | |
}; | |
// delete the property x here, to make the test pass | |
// | |
delete obj.x | |
obj.x = true; | |
assert.equal(setterCalled, false); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 68: Reflect - construct | |
// To do: make all tests pass, leave the assert lines unchanged! | |
describe('`Reflect.construct` is the `new` operator as a function', function() { | |
describe('the function itself', function() { | |
it('is static on the `Reflect` object', function() { | |
// const name = 'konstructor'; | |
const name = 'constructor'; | |
assert.equal(name in Reflect, true); | |
}); | |
it('is of type `function`', function() { | |
// const expectedType = '???'; | |
const expectedType = 'function'; | |
assert.equal(typeof Reflect.construct, expectedType) | |
}); | |
}); | |
describe('the 1st parameter is the constructor to be invoked', function() { | |
it('fails when given a number as constructor', function() { | |
// let aNumber = class {} | |
let aNumber = 5; | |
assert.throws(() => { Reflect.construct(aNumber, []) }, TypeError); | |
}); | |
it('works given a function that can be instanciated', function() { | |
// let aFunction; | |
let aFunction = function() {return 'this works'}; | |
assert.doesNotThrow(() => { Reflect.construct(aFunction, []) }); | |
}); | |
it('works given a class', function() { | |
// const aClass = {}; | |
const aClass = class {}; | |
assert.doesNotThrow(() => { Reflect.construct(aClass, []) }); | |
}); | |
}); | |
describe('the 2nd parameter is a list of arguments, that will be passed to the constructor', function() { | |
const aClass = class {}; | |
it('fails when it`s not an array(-like), e.g. a number', function() { | |
// let aNumber = []; | |
let aNumber = 5; | |
assert.throws(() => { Reflect.construct(aClass, aNumber) }, TypeError); | |
}); | |
it('works with an array-like object (the `length` property look up should not throw)', function() { | |
// let arrayLike = {get length() { throw new Error(); }}; | |
let arrayLike = {get length() { return 'this is the length'; }}; | |
assert.doesNotThrow(() => { Reflect.construct(aClass, arrayLike) }); | |
}); | |
it('works with a real array', function() { | |
// let realArray = ''; | |
let realArray = [1,2,3,4,5]; | |
assert.doesNotThrow(() => { Reflect.construct(aClass, realArray) }); | |
}); | |
}); | |
describe('in use', function() { | |
it('giving it a class it returns an instance of this class', function() { | |
class Constructable {} | |
// let instance = Reflect.construct; // use Reflect.construct here!!! | |
let instance = Reflect.construct(Constructable, []); | |
// or | |
instance = Reflect.construct(Constructable, {}); | |
assert.equal(instance instanceof Constructable, true); | |
}); | |
describe('the list of arguments are passed to the constructor as given', function() { | |
class Constructable { | |
constructor(...args) { this.args = args; } | |
} | |
it('if none given, nothing is passed', function() { | |
// let instance = Reflect.construct(Constructable, [1]); | |
let instance = Reflect.construct(Constructable, []); | |
assert.deepEqual(instance.args, []); | |
}); | |
it('passing an array, all args of any type are passed', function() { | |
const argumentsList = ['arg1', ['arg2.1', 'arg2.2'], {arg: 3}]; | |
// let instance = Reflect.construct; | |
let instance = Reflect.construct(Constructable, argumentsList); | |
assert.deepEqual(instance.args, argumentsList); | |
}); | |
}); | |
}); | |
describe('the length property', function() { | |
it('of `Reflect.construct` is 2', function() { | |
// let expected; | |
let expected = 2; | |
assert.equal(Reflect.construct.length, expected); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 69: Reflect - defineProperty | |
// To do: make all tests pass, leave the assert lines unchanged! | |
describe('`Reflect.defineProperty()` is like `Object.defineProperty()` but returns a Boolean.', function() { | |
describe('the function itself', function() { | |
it('is static on the `Reflect` object', function() { | |
// const name = 'what`s the functions name again? :)'; | |
const name = 'defineProperty'; | |
assert.equal(name in Reflect, true); | |
}); | |
it('is of type `function`', function() { | |
// const expectedType = ''; | |
const expectedType = 'function'; | |
assert.equal(typeof Reflect.defineProperty, expectedType) | |
}); | |
}); | |
describe('the 1st parameter is the object on which to define a property', function() { | |
it('fails if it is not an object', function() { | |
// let noObj = {}; | |
let noObj = ''; | |
assert.throws(() => { Reflect.defineProperty(noObj, 'property', {value: 'value'}); }); | |
}); | |
it('accepts an object', function() { | |
// let obj = ''; | |
let obj = {}; | |
assert.doesNotThrow(() => { Reflect.defineProperty(obj, 'property', {value: 'value'}); }); | |
}); | |
it('accepts an instance (of a class)', function() { | |
// let instance; | |
let instance = class {}; | |
assert.doesNotThrow(() => { Reflect.defineProperty(instance, 'property', {value: 'value'}); }); | |
}); | |
}); | |
describe('2nd parameter is the name of the property to be defined on the object (normally a string)', function() { | |
it('works with a `normal` string', function() { | |
let obj = {}; | |
// Reflect.defineProperty(obj, '', {}); | |
Reflect.defineProperty(obj, 'prop', {}); | |
assert.equal('prop' in obj, true); | |
}); | |
it('a number gets converted into a string', function() { | |
let obj = {}; | |
// Reflect.defineProperty(obj, 2, {}); | |
Reflect.defineProperty(obj, 1, {}); | |
assert.equal('1' in obj, true); | |
}); | |
it('`undefined` also gets converted into a string (watch out!)', function() { | |
let obj = {}; | |
// let undef = ''; | |
let undef = undefined; | |
Reflect.defineProperty(obj, undef, {}); | |
assert.equal('undefined' in obj, true); | |
}); | |
it('it can be a symbol', function() { | |
let obj = {}; | |
const sym = Symbol.for('prop'); | |
// Reflect.defineProperty(obj, 'prop', {}); | |
Reflect.defineProperty(obj, sym, {}); | |
assert.equal(sym in obj, true); | |
}); | |
}); | |
describe('the `value` is part of the 3rd parameter, given as a property in an object `{value: ...}`', function() { | |
// The entire complexity of the 3rd parameter might be covered in a later kata. | |
it('contains the initial value of the property, as an object in the property `value`', function() { | |
let obj = {}; | |
// Reflect.defineProperty(obj, 'prop'); | |
Reflect.defineProperty(obj, 'prop', {value: 'property value'}); | |
assert.equal(obj.prop, 'property value'); | |
}); | |
it('can be of any type (even itself)', function() { | |
let obj = {}; | |
// Reflect.defineProperty(obj, 'prop'); | |
Reflect.defineProperty(obj, 'prop', {value: obj}); | |
assert.equal(obj.prop, obj); | |
}); | |
}); | |
describe('the return value of the function indicates whether the property was defined successfully', function() { | |
describe('returns true', function() { | |
it('when the property was created (which requires the 3rd parameter too!!!)', function() { | |
let instance = new class {}; | |
// const wasPropertyDefined = Reflect.defineProperty(); | |
const wasPropertyDefined = Reflect.defineProperty(instance, 'property', {value: 'value'}); | |
assert.equal(wasPropertyDefined, true); | |
}); | |
it('no matter what the value of the property is (just the 3rd param has to exist as `{}`)', function() { | |
let instance = new class {}; | |
// const wasPropertyDefined = Reflect.defineProperty(instance); | |
const wasPropertyDefined = Reflect.defineProperty(instance, 'property', {value: 'value'}); | |
assert.equal(wasPropertyDefined, true); | |
}); | |
}); | |
describe('returns false', function() { | |
it('when a non-configurable property wants to be changed to configurable=true', function() { | |
let obj = {}; | |
Reflect.defineProperty(obj, 'x', {configurable: false}); | |
// const wasPropertyDefined = Reflect.defineProperty; | |
const wasPropertyDefined = Reflect.defineProperty(obj, 'x', {configurable: true}); | |
assert.equal(wasPropertyDefined, false); | |
}); | |
it('when the object we want to add a property to is frozen', function() { | |
let instance = new class {}; | |
Object.freeze(instance); | |
// const wasPropertyDefined = Reflect.defineProperty({}, 'prop', {value: 1}); | |
const wasPropertyDefined = Reflect.defineProperty(instance, 'prop', {value: 1}); | |
assert.equal(wasPropertyDefined, false); | |
}); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 70: Set - clear | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`clear()` removes all elements from a Set object.', function(){ | |
let set; | |
beforeEach(() => set = new Set()); | |
it('`set.size` becomes 0', function() { | |
set.add('one').add(2); | |
set.clear(); | |
// var expectedSize; | |
var expectedSize = 0; | |
assert.equal(set.size, expectedSize); | |
}); | |
it('the iterator `set.entries()` will not contain any items', function() { | |
set.add('one').add(2); | |
// set.clear; | |
set.clear(); | |
const {done} = set.entries().next(); | |
assert.equal(done, true); | |
}); | |
it('any call to `set.has()` returns false', function() { | |
set.add('one').add(2); | |
// | |
set.clear(); | |
set.has(); | |
assert.deepEqual(set.has(2), false); | |
}); | |
it('returns `undefined`', function() { | |
// var expectedReturn = true; | |
var expectedReturn = undefined; | |
assert.equal(set.clear(), expectedReturn); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 71: String - `repeat()` | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`str.repeat(x)` concatenates `x` copies of `str` and returns it', function() { | |
describe('the 1st parameter the count', function() { | |
it('if missing, returns an empty string', function() { | |
// const what = 'one'.repeat(23); | |
const what = 'one'.repeat(); | |
assert.equal(what, ''); | |
}); | |
it('when `1`, the string stays the same', function() { | |
// const what = 'one'.repeat(); | |
const what = 'one'.repeat(1); | |
assert.equal(what, 'one'); | |
}); | |
it('for `3` the string `x` becomes `xxx`', function() { | |
// const actual = 'x'.REPEAT(1); | |
const actual = 'x'.repeat(3); | |
assert.equal(actual, 'xxx'); | |
}); | |
it('for `0` an empty string is returned', function() { | |
// const repeatCount = 1; | |
const repeatCount = 0; | |
assert.equal('shrink'.repeat(repeatCount), ''); | |
}); | |
describe('the count is not a number', () => { | |
it('such as a string "3", it gets converted to an int', function() { | |
// const repeated = 'three'.repeat('2'); | |
const repeated = 'three'.repeat('3'); | |
assert.equal(repeated, 'threethreethree'); | |
}); | |
it('a hex looking number as a string "0xA", it gets converted to an int', function() { | |
// const repeated = 'x'.repeat('0A'); | |
const repeated = 'x'.repeat('0xA'); | |
assert.equal('xxxxxxxxxx', repeated); | |
}); | |
it('and does not look like a number, it behaves like 0', function() { | |
const repeated = 'x'.repeat('z'); | |
assert.equal('', repeated); | |
}); | |
}); | |
}); | |
describe('throws an error for', function() { | |
it('a count of <0', function() { | |
// const belowZero = 1; | |
const belowZero = -1; | |
assert.throws(() => { ''.repeat(belowZero); }, RangeError); | |
}); | |
it('a count of +Infinty', function() { | |
// let infinity = 'infinity'; | |
let infinity = +Infinity; | |
assert.throws(() => { ''.repeat(infinity); }, RangeError); | |
}); | |
}); | |
describe('accepts everything that can be coerced to a string', function() { | |
it('e.g. a boolean', function() { | |
// let aBool = true; | |
let aBool = false; | |
assert.equal(String.prototype.repeat.call(aBool, 2), 'falsefalse'); | |
}); | |
it('e.g. a number', function() { | |
// let aNumber; | |
let aNumber=1; | |
assert.equal(String.prototype.repeat.call(aNumber, 2), '11'); | |
}); | |
}); | |
describe('for my own (string) class', function() { | |
it('calls `toString()` to make it a string', function() { | |
class MyString { toString() { return 'my string'; } } | |
// const expectedString = '' | |
const expectedString = new MyString();; | |
assert.equal(String(new MyString()).repeat(1), expectedString); | |
}); | |
it('`toString()` is only called once', function() { | |
let counter = 1; | |
class X { | |
toString() { | |
return counter++; | |
} | |
} | |
let repeated = String(new X()).repeat(2); | |
assert.equal(repeated, '11'); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 72: String - `startsWith()` | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`str.startsWith(searchString)` determines whether `str` begins with `searchString`.', function() { | |
const s = 'the string s'; | |
describe('the 1st parameter, the string to search for', function() { | |
it('can be just a character', function() { | |
// const actual = s.starts_with('t'); | |
const actual = s.startsWith('t'); | |
assert.equal(actual, true); | |
}); | |
it('can be a string', function() { | |
// const expected = '???'; | |
const expected = true; | |
assert.equal(s.startsWith('the'), expected); | |
}); | |
it('can contain unicode characters', function() { | |
// const nuclear = 'NO ☢ NO'; | |
const nuclear = '☢ NO'; | |
assert.equal(nuclear.startsWith('☢'), true); | |
}); | |
it('a regular expression throws a TypeError', function() { | |
// const aRegExp = 'the'; | |
const aRegExp = /the/; | |
assert.throws(() => {''.startsWith(aRegExp)}, TypeError); | |
}); | |
}); | |
describe('the 2nd parameter, the position where to start searching from', function() { | |
it('e.g. find "str" at position 4', function() { | |
// const position = 3; | |
const position = 4; | |
assert.equal(s.startsWith('str', position), true); | |
}); | |
it('for `undefined` is the same as 0', function() { | |
// const _undefined_ = '1'; | |
const _undefined_ = undefined; | |
assert.equal(s.startsWith('the', _undefined_), true); | |
}); | |
it('the parameter gets converted to an int', function() { | |
// const position = 'four'; | |
const position = '4'; | |
assert.equal(s.startsWith('str', position), true); | |
}); | |
it('a value larger than the string`s length, returns false', function() { | |
// const expected = true; | |
const expected = false; | |
assert.equal(s.startsWith(' ', s.length + 1), expected); | |
}); | |
}); | |
describe('this functionality can be used on non-strings too', function() { | |
it('e.g. a boolean', function() { | |
// let aBool; | |
let aBool = false; | |
assert.equal(String.prototype.startsWith.call(aBool, 'false'), true); | |
}); | |
it('e.g. a number', function() { | |
// let aNumber = 19; | |
let aNumber = '19'; | |
assert.equal(String.prototype.startsWith.call(aNumber + 84, '1984'), true); | |
}); | |
it('also using the position works', function() { | |
// const position = 0; | |
const position = 1; | |
assert.equal(String.prototype.startsWith.call(1994, '99', position), true); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 73: Generator - `return` inside a generator is special | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`return` in a generator function is special', function() { | |
describe('the returned value is an IteratorResult (just like any value returned via `yield`)', function() { | |
it('returns an IteratorResult (an object with the properties `value` and `done`)', function() { | |
function* generatorFunction() { return 1; } | |
const returned = generatorFunction().next(); | |
const propertyNames = ['value', 'done']; | |
assert.deepEqual(Object.keys(returned), propertyNames); | |
}); | |
it('the property `value` is the returned value', function() { | |
// function* generatorFunction() { return; } | |
function* generatorFunction() { return 23; } | |
const {value} = generatorFunction().next(); | |
assert.equal(value, 23); | |
}); | |
it('the property `done` is true', function() { | |
// function* generatorFunction() { yield 42; } | |
function* generatorFunction() { return 42; } | |
const {done} = generatorFunction().next(); | |
assert.equal(done, true); | |
}); | |
it('NOTE: `yield` does not return `done=true` but `done=false`!', function() { | |
// function* generatorFunction() { return 1; } | |
function* generatorFunction() { yield 1; } | |
const returned = generatorFunction().next(); | |
assert.deepEqual(returned, {value: 1, done: false}); | |
}); | |
it('a missing `return` returns `{value: undefined, done: true}`', function() { | |
// function* generatorFunction() { yield; } | |
function* generatorFunction() { return ; } | |
const returned = generatorFunction().next(); | |
assert.deepEqual(returned, {value: void 0, done: true}); | |
}); | |
}); | |
describe('mixing `return` and `yield`', function() { | |
function* generatorFunctionWithYieldAndReturn() { | |
yield 1; | |
// yield ; | |
// | |
return 2 | |
} | |
it('is possible', function() { | |
const iterator = generatorFunctionWithYieldAndReturn(); | |
const values = [ | |
iterator.next(), | |
iterator.next() | |
]; | |
assert.deepEqual(values, [{value: 1, done: false}, {value: 2, done: true}]); | |
}); | |
it('the mix behaves different to two `yield`s', function() { | |
const iterator = generatorFunctionWithYieldAndReturn(); | |
// const values = [1, 2]; | |
const values = [1] | |
assert.deepEqual(Array.from(iterator), values); | |
}); | |
it('two `yield`s returning values', function() { | |
function* generatorFunctionWithTwoYields() { | |
// | |
yield 1; | |
yield 2; | |
} | |
assert.deepEqual(Array.from(generatorFunctionWithTwoYields()), [1, 2]); | |
}); | |
it('return a yielded value by "chaining" `return` and `yield`', function() { | |
function* generatorFunction() { | |
return yield 1 | |
} | |
const iterator = generatorFunction(); | |
const values = [ | |
iterator.next().value, | |
iterator.next(2).value | |
]; | |
assert.deepEqual(values, [1, 2]); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 74: String - `endsWith()` | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`str.endsWith(searchString)` determines whether `str` ends with `searchString`', function() { | |
const s = 'el fin'; | |
describe('the 1st parameter the string to search for', function() { | |
it('can be a character', function() { | |
// const doesEndWith = s.doesItReallyEndWith('n'); | |
const doesEndWith = s.endsWith('n'); | |
assert.equal(doesEndWith, true); | |
}); | |
it('can be a string', function() { | |
// const expected = false; | |
const expected = true; | |
assert.equal(s.endsWith('fin'), expected); | |
}); | |
it('can contain unicode characters', function() { | |
// const nuclear = 'NO ☢ Oh NO!'; | |
const nuclear = 'NO ☢'; | |
assert.equal(nuclear.endsWith('☢'), true); | |
}); | |
it('a regular expression throws a TypeError', function() { | |
// const aRegExp = '/the/'; | |
const aRegExp = /the/; | |
assert.throws(() => {''.endsWith(aRegExp)}, TypeError); | |
}); | |
}); | |
describe('the 2nd parameter, the position where the search ends (as if the string was only that long)', function() { | |
it('find "el" at a substring of the length 2', function() { | |
// const endPos = 0; | |
const endPos = 2; | |
assert.equal(s.endsWith('el', endPos), true); | |
}); | |
it('`undefined` uses the entire string', function() { | |
// const _undefined_ = 'i would like to be undefined'; | |
const _undefined_ = undefined; | |
assert.equal(s.endsWith('fin', _undefined_), true); | |
}); | |
it('the parameter gets coerced to an integer (e.g. "5" becomes 5)', function() { | |
// const position = 'five'; | |
const position = '5'; | |
assert.equal(s.endsWith('fi', position), true); | |
}); | |
describe('value less than 0', function() { | |
it('returns `true`, when searching for an empty string', function() { | |
// const emptyString = '??'; | |
const emptyString = ''; | |
assert.equal('1'.endsWith(emptyString, -1), true); | |
}); | |
it('return `false`, when searching for a non-empty string', function() { | |
// const notEmpty = ''; | |
const notEmpty = 'not empty'; | |
assert.equal('1'.endsWith(notEmpty, -1), false); | |
}); | |
}); | |
}); | |
describe('this functionality can be used on non-strings too', function() { | |
it('e.g. a boolean', function() { | |
let aBool = false; | |
assert.equal(String.prototype.endsWith.call(aBool, 'lse'), true); | |
}); | |
it('e.g. a number', function() { | |
// let aNumber = 0; | |
let aNumber = 84; | |
assert.equal(String.prototype.endsWith.call(aNumber + 1900, 84), true); | |
}); | |
it('also using the position works', function() { | |
// const position = '??'; | |
const position = 3; | |
assert.equal(String.prototype.endsWith.call(1994, '99', position), true); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 75: Promise - basics | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('a Promise represents an operation that hasn`t completed yet, but is expected in the future', function() { | |
it('`Promise` is a global function', function() { | |
// const expectedType = '???'; | |
const expectedType = 'function'; | |
assert.equal(typeof Promise, expectedType); | |
}); | |
describe('the constructor', function() { | |
it('instantiating it without params throws', function() { | |
// const fn = () => { Promise } | |
const fn = () => { new Promise } | |
assert.throws(fn); | |
}); | |
it('expects a function as parameter', function() { | |
// const param = null; | |
const param = () => {}; | |
assert.doesNotThrow(() => { new Promise(param); }); | |
}); | |
}); | |
describe('simplest promises', function() { | |
it('resolve a promise by calling the `resolve` function given as first parameter', function(done) { | |
let promise = new Promise((resolve) => { | |
// | |
done(); | |
}); | |
promise | |
.then(() => done()) | |
.catch(() => done(new Error('The promise is expected to resolve.'))); | |
}); | |
it('the `resolve` function can return a value, that is consumed by the `promise.then()` callback', function(done) { | |
let promise = new Promise((resolve) => { | |
// resolve(); | |
resolve(42); | |
}); | |
promise | |
.then(value => {assert.equal(value, 42); done(); }) | |
.catch(() => done(new Error('The promise is expected to resolve with 42!'))); | |
}); | |
it('rejecting a promise is done by calling the callback given as 2nd parameter', function(done) { | |
// let promise = new Promise((resolve, reject) => { | |
let promise = new Promise((resolve, reject) => { | |
reject(); | |
}); | |
promise | |
.then(() => done(new Error('The promise is expected to be rejected.'))) | |
.catch(() => done()); | |
}); | |
}); | |
describe('an asynchronous promise', function() { | |
it('can resolve later, also by calling the first callback', function(done) { | |
// let promise = new Promise(() => { | |
let promise = new Promise((resolve) => { | |
setTimeout(() => resolve(), 100); | |
}); | |
promise | |
.then(() => done()) | |
.catch(() => done(new Error('The promise is expected to resolve.'))); | |
}); | |
it('reject it at some later point in time, calling the 2nd callback', function(done) { | |
// let promise = new Promise((reject) => { | |
let promise = new Promise((resolve, reject) => { | |
setTimeout(() => reject(), 100); | |
}); | |
promise | |
.then(() => done(new Error('The promise is expected to be rejected.'))) | |
.catch(() => done()); | |
}); | |
}); | |
describe('test library (mocha here) support for promises', function() { | |
it('just returning the promise makes the test library check that the promise resolves', function() { | |
// let promise = new Promise((reject, resolve) => { | |
let promise = new Promise((resolve, reject) => { | |
resolve(); | |
}); | |
// return the promise to mocha, it has the checking for promise resolving built in, when it receives a promise | |
return promise; | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 76: Promise - creation | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('A promise can be created in multiple ways', function() { | |
describe('creating a promise fails when', function() { | |
it('using `Promise` as a function', function() { | |
function callPromiseAsFunction() { | |
// Promise; | |
Promise(); | |
} | |
assert.throws(callPromiseAsFunction); | |
}); | |
it('no parameter is passed', function() { | |
function promiseWithoutParams() { | |
// new Promise(() => {}); | |
new Promise(); | |
} | |
assert.throws(promiseWithoutParams); | |
}); | |
it('passing a non-callable throws too', function() { | |
// const notAFunction = () => {}; | |
const notAFunction = null; | |
assert.throws(() => { new Promise(notAFunction); }); | |
}); | |
}); | |
describe('most commonly Promises get created using the constructor', function() { | |
it('by passing a resolve function to it', function() { | |
// const promise = new Promise(() => resolve()); | |
const promise = new Promise((resolve) => resolve()); | |
return promise; | |
}); | |
it('by passing a resolve and a reject function to it', function(done) { | |
// const promise = new Promise((resolve, reject) => resolve()); | |
const promise = new Promise((resolve, reject) => reject()); | |
promise | |
.then(() => done(new Error('Expected promise to be rejected.'))) | |
.catch(done); | |
}); | |
}); | |
describe('extending a `Promise`', function() { | |
it('using `class X extends Promise{}` is possible', function(done) { | |
// class MyPromise {} | |
// const promise = MyPromise(resolve => resolve()); | |
class MyPromise extends Promise{} | |
const promise = new MyPromise(resolve => resolve()); | |
promise | |
.then(() => done()) | |
.catch(e => done(new Error('Expected to resolve, but failed with: ' + e))); | |
}); | |
it('must call `super()` in the constructor if it wants to inherit/specialize the behavior', function() { | |
class ResolvingPromise extends Promise { | |
// | |
constructor(resolve,reject) { | |
super(resolve) | |
} | |
} | |
return new ResolvingPromise(resolve => resolve()); | |
}); | |
}); | |
describe('`Promise.all()` returns a promise that resolves when all given promises resolve', function() { | |
it('returns all results', function(done) { | |
const promise = Promise.all([ | |
// new Promise(resolve => resolve(1)),new Promise(resolve => resolve(2)),new Promise(resolve => resolve(3)) | |
new Promise(resolve => resolve(1)),new Promise(resolve => resolve(2)) | |
]); | |
promise | |
.then(value => { assert.deepEqual(value, [1, 2]); done(); }) | |
.catch(e => done(new Error(e))); | |
}); | |
it('is rejected if one rejects', function(done) { | |
const promise = Promise.all([ | |
// new Promise(resolve => resolve(1)) | |
new Promise(resolve => resolve(1)), new Promise((resolve, reject) => reject(2)) | |
]); | |
promise | |
.then(() => done(new NotRejectedError())) | |
.catch(() => done()); | |
}); | |
}); | |
describe('`Promise.race()` returns the first settled promise', function() { | |
it('if it resolves first, the promises resolves', function(done) { | |
const lateRejectedPromise = new Promise((resolve, reject) => setTimeout(reject, 100)); | |
const earlyResolvingPromise = new Promise(resolve => resolve('1st :)')); | |
// const promise = Promise.race([lateRejectedPromise]); | |
const promise = Promise.race([lateRejectedPromise, earlyResolvingPromise]); | |
promise | |
.then(value => { assert.deepEqual(value, '1st :)'); done(); }) | |
.catch(e => done(new Error('Expected to resolve, but failed with: ' + e))); | |
}); | |
it('if one of the given promises rejects first, the returned promise is rejected', function(done) { | |
// const earlyRejectedPromise = new Promise((resolve, reject) => reject('I am a REJECTOR')); | |
const earlyRejectedPromise = new Promise((resolve, reject) => reject('I am a rejector')); | |
const lateResolvingPromise = new Promise(resolve => setTimeout(resolve, 10)); | |
const promise = Promise.race([earlyRejectedPromise, lateResolvingPromise]); | |
promise | |
.then(() => done(new NotRejectedError())) | |
.catch(value => { assert.equal(value, 'I am a rejector'); done(); }) | |
.catch(done); | |
}); | |
}); | |
describe('`Promise.resolve()` returns a resolving promise', function() { | |
it('if no value given, it resolves with `undefined`', function(done) { | |
// const promise = Promise.resolve; | |
const promise = Promise.resolve(); | |
promise | |
.then(value => { assert.deepEqual(value, void 0); done(); }) | |
.catch(e => done(new Error('Expected to resolve, but failed with: ' + e))); | |
}); | |
it('resolves with the given value', function(done) { | |
// const promise = Promise.resolve(); | |
const promise = Promise.resolve('quick resolve'); | |
promise | |
.then(value => { assert.equal(value, 'quick resolve'); done(); }) | |
.catch(e => done(e)); | |
}); | |
}); | |
describe('`Promise.reject()` returns a rejecting promise', function() { | |
it('if no value given, it rejects with `undefined`', function(done) { | |
// const promise = Promise.resolve(); | |
const promise = Promise.reject(); | |
promise | |
.then(() => done(new NotRejectedError())) | |
.catch(value => { assert.deepEqual(value, void 0); done(); }) | |
.catch(done); | |
}); | |
it('the parameter passed to `reject()` can be used in the `.catch()`', function(done) { | |
// const promise = Promise; | |
const promise = Promise.reject('quick reject'); | |
promise | |
.then(() => done(new NotRejectedError())) | |
.catch(value => { assert.deepEqual(value, 'quick reject'); done(); }) | |
.catch(done); | |
}); | |
}); | |
}); | |
class NotRejectedError extends Error { | |
constructor() { | |
super(); | |
this.message = 'Expected promise to be rejected.'; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 77: Promise - chaining | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('chaining multiple promises can enhance readability', () => { | |
describe('prerequisites for understanding', function() { | |
it('reminder: the test passes when a fulfilled promise is returned', function() { | |
// return Promise.reject('I should fulfill.'); | |
return Promise.resolve('I should fulfill.'); | |
}); | |
it('a function given to `then()` fulfills (if it doesnt throw)', function() { | |
// const beNice = () => { throw new Error('I am nice') }; | |
const beNice = () => { return 'I am nice' }; | |
return Promise.resolve() | |
.then(beNice) | |
.then(niceMessage => assert.equal(niceMessage, 'I am nice')); | |
}); | |
}); | |
describe('chain promises', function() { | |
const removeMultipleSpaces = string => string.replace(/\s+/g, ' '); | |
it('`then()` receives the result of the promise it was called on', function() { | |
const wordsPromise = Promise.resolve('one space between each word'); | |
return wordsPromise | |
// .then(string => removeMultipleSpaces()) | |
.then(string => removeMultipleSpaces(string)) | |
.then(actual => {assert.equal(actual, 'one space between each word')}) | |
; | |
}); | |
const appendPeriod = string => `${string}.`; | |
it('multiple `then()`s can be chained', function() { | |
const wordsPromise = Promise.resolve('Sentence without an end'); | |
return wordsPromise | |
// | |
.then(string => string.concat('.')) | |
.then(removeMultipleSpaces) | |
.then(actual => {assert.equal(actual, 'Sentence without an end.')}) | |
; | |
}); | |
const trim = string => string.replace(/^\s+/, '').replace(/\s+$/, ''); | |
it('order of the `then()`s matters', function() { | |
const wordsPromise = Promise.resolve('Sentence without an end '); | |
return wordsPromise | |
// .then(appendPeriod) | |
.then(trim) | |
.then(appendPeriod) | |
.then(removeMultipleSpaces) | |
.then(actual => {assert.equal(actual, 'Sentence without an end.')}) | |
; | |
}); | |
const asyncUpperCaseStart = (string, onDone) => { | |
const format = () => onDone(string[0].toUpperCase() + string.substr(1)); | |
setTimeout(format, 100); | |
}; | |
it('any of the things given to `then()` can resolve asynchronously (the real power of Promises)', function() { | |
const wordsPromise = Promise.resolve('sentence without an end'); | |
return wordsPromise | |
// .then(string => new Promise(resolve => asyncUpperCaseStart)) | |
.then(string => new Promise(resolve => asyncUpperCaseStart(string, resolve))) | |
.then(string => new Promise(resolve => setTimeout(() => resolve(appendPeriod(string)), 100))) | |
.then(actual => {assert.equal(actual, 'Sentence without an end.')}) | |
; | |
}); | |
it('also asynchronously, the order still matters, promises wait, but don`t block', function() { | |
const wordsPromise = Promise.resolve('trailing space '); | |
return wordsPromise | |
.then(string => new Promise(resolve => asyncUpperCaseStart(string, resolve))) | |
// .then(string => new Promise(resolve => setTimeout(() => resolve(appendPeriod(string)), 100))) | |
.then(string => new Promise(resolve => setTimeout(() => resolve(trim(string)), 100))) | |
.then(string => new Promise(resolve => setTimeout(() => resolve(appendPeriod(string)), 100))) | |
.then(actual => {assert.equal(actual, 'Trailing space.')}) | |
; | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 78: Promise - API overview | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Promise` API overview', function() { | |
it('`new Promise()` requires a function as param', () => { | |
// const param = null; | |
const param = () => {}; | |
assert.doesNotThrow(() => { new Promise(param); }); | |
}); | |
describe('resolving a promise', () => { | |
// reminder: the test passes when a fulfilled promise is returned | |
it('via constructor parameter `new Promise((resolve) => { resolve(); })`', () => { | |
// const param = () => { resolve(); }; | |
const param = (resolve) => { resolve(); }; | |
return new Promise(param); | |
}); | |
it('using `Promise.resolve()`', () => { | |
// return Promise.reject('all fine'); | |
return Promise.resolve('all fine'); | |
}); | |
}); | |
describe('a rejected promise', () => { | |
it('using the constructor parameter', (done) => { | |
// const promise = new Promise((reject) => { reject(); }); | |
const promise = new Promise((resolve, reject) => { reject(); }); | |
promise | |
.then(() => done(new Error('The promise is expected to be rejected.'))) | |
.catch(() => done()); | |
}); | |
it('via `Promise.reject()`', (done) => { | |
// const promise = Promise.resolve(); | |
const promise = Promise.reject(); | |
promise | |
.then(() => done(new Error('The promise is expected to be rejected.'))) | |
.catch(() => done()); | |
}); | |
}); | |
describe('`Promise.all()`', () => { | |
it('`Promise.all([p1, p2])` resolves when all promises resolve', () => { | |
// return Promise.all([Promise.resolve(), Promise.reject(), Promise.resolve()]) | |
return Promise.all([Promise.resolve(), Promise.resolve(), Promise.resolve()]) | |
}); | |
it('`Promise.all([p1, p2])` rejects when a promise is rejected', (done) => { | |
// Promise.all([Promise.resolve()]) | |
Promise.all([Promise.reject()]) | |
.then(() => done(new Error('The promise is expected to be rejected.'))) | |
.catch(() => done()) | |
}); | |
}); | |
describe('`Promise.race()`', () => { | |
it('`Promise.race([p1, p2])` resolves/reject when one of the promises resolves/rejects', () => { | |
// return Promise.race([Promise.reject(), Promise.reject()]) | |
return Promise.race([Promise.resolve(), Promise.reject()]) | |
}); | |
it('`Promise.race([p1, p2])` rejects when one of the promises rejects', (done) => { | |
// Promise.race([Promise.resolve()]) | |
Promise.race([Promise.reject()]) | |
.then(() => done(new Error('The promise is expected to be rejected.'))) | |
.catch(() => done()) | |
}); | |
it('`Promise.race([p1, p2])` order matters (and timing)', () => { | |
// return Promise.race([Promise.reject(), Promise.resolve()]) | |
return Promise.race([Promise.resolve(), Promise.reject()]) | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 79: Promise - catch | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
// Here we use promises to trigger, don't modify the block with the | |
// returning promise! | |
describe('`catch()` returns a Promise and deals with rejected cases only', () => { | |
describe('prerequisites for understanding', () => { | |
it('*return* a fulfilled promise, to pass a test', () => { | |
// Promise.resolve(); | |
return Promise.resolve(); | |
assert(false); // Don't touch! Make the test pass in the line above! | |
}); | |
it('reminder: the test passes when a fulfilled promise is returned', () => { | |
// return Promise.reject('I should fulfill.'); | |
return Promise.resolve('I should fulfill.'); | |
}); | |
}); | |
describe('`catch` method basics', () => { | |
it('is an instance method', () => { | |
// const p = Promise; | |
const p = new Promise(resolve => {}); | |
assert.equal(typeof p.catch, 'function'); | |
}); | |
it('catches only promise rejections', (done) => { | |
// const promise = Promise.resolve(); | |
const promise = Promise.reject(); | |
promise | |
.then(() => { done('Should not be called!'); }) | |
.catch(done); | |
}); | |
it('returns a new promise', () => { | |
// const whatToReturn = () => Promise.reject(); | |
// needs to provide a new function to run when there is a catch | |
const whatToReturn = () => Promise.resolve(); | |
const promise = Promise.reject(); | |
return promise.catch(() => | |
whatToReturn() | |
); | |
}); | |
it('converts it`s return value into a promise', () => { | |
const p = Promise.reject(); | |
// const p1 = p.catch(() => void 0); | |
const p1 = p.catch(() => 'promise?'); | |
return p1.then(result => assert.equal('promise?', result)); | |
}); | |
it('the first parameter is the rejection reason', () => { | |
// const p = Promise.reject('rejection'); | |
const p = Promise.reject('oops'); | |
return p.catch(reason => { | |
assert.equal(reason, 'oops'); | |
}); | |
}); | |
}); | |
describe('multiple `catch`es', () => { | |
it('only the first `catch` is called', () => { | |
const p = Promise.reject('1'); | |
const p1 = p | |
// .catch(reason => 'void 0') | |
.catch(reason => reason + ' AND 2') | |
.catch(reason => `${reason} AND 3`) | |
; | |
return p1.then(result => | |
assert.equal(result, '1 AND 2') | |
); | |
}); | |
it('if a `catch` throws, the next `catch` catches it', () => { | |
const p = Promise.reject('1'); | |
const p1 = p | |
.catch(reason => { throw Error(`${reason} AND 2`) }) | |
// .catch(err => { throw Error(`${err.message} AND 3`) }) | |
.catch(err => { return `${err.message} AND 3` }) | |
.catch(err => `${err} but NOT THIS`) | |
; | |
return p1.then(result => | |
assert.equal(result, '1 AND 2 AND 3') | |
); | |
}); | |
}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 80: Number - isNaN | |
// To do: make all tests pass, leave the assert lines unchanged! | |
// Follow the hints of the failure messages! | |
describe('`Number.isNaN()` determines if a value is `NaN`', function(){ | |
it('it is a static function on `Number`', function() { | |
// const whatType = 'method'; | |
const whatType = 'function'; | |
assert.equal(typeof Number.isNaN, whatType); | |
}); | |
describe('returns false', () => { | |
describe('for any not-Number type', () => { | |
it('like null', () => { | |
// const justNull = NaN; | |
const justNull = null; | |
assert.equal(Number.isNaN(justNull), false); | |
}); | |
it('like a string', () => { | |
// const aString = NaN; | |
const aString = 'string'; | |
assert.equal(Number.isNaN(aString), false); | |
}); | |
it('like an object', () => { | |
// const anObject = NaN; | |
const anObject = {}; | |
assert.equal(Number.isNaN(anObject), false); | |
}); | |
describe('different to the global `isNaN` function (specified way before ES6)', () => { | |
it('an object gets converted to a Number before the check, and returns true therefore', () => { | |
// const fn = Number.isNaN; | |
const fn = object => Number.isNaN(Number(object)); | |
assert.equal(fn({}), true); | |
}); | |
it('a string gets converted to a Number first, and returns true therefore (even though its not `NaN`)', () => { | |
// const fn = Number.isNaN | |
const fn = (string) => Number.isNaN(Number(string)) | |
assert.equal(fn('just a string'), true); | |
}); | |
}); | |
}); | |
describe('for Numbers', () => { | |
it('like 0', () => { | |
// const zero = NaN; | |
const zero = 0; | |
assert.equal(Number.isNaN(zero), false); | |
}); | |
it('or Infinity (+∞)', () => { | |
// const infinity = Nummmmber.POSITIVE_INFINITY; | |
const infinity = Number.POSITIVE_INFINITY; | |
assert.equal(Number.isNaN(infinity), false); | |
}); | |
it('or the biggest Number (9007199254740991 (2^53−1))', () => { | |
// const max = N_u_m_b_e_r.MAX_SAFE_INTEGER; | |
const max = Number.MAX_SAFE_INTEGER; | |
assert.equal(Number.isNaN(max), false); | |
}); | |
it('or a decimal number', () => { | |
// const pie = 3.1415926535897932; | |
const pi = 3.1415926535897932; | |
assert.equal(Number.isNaN(pi), false); | |
}); | |
}); | |
}); | |
describe('returns true for', () => { | |
it('exactly `NaN`', () => { | |
// const notANumber = 1; | |
const notANumber = NaN; | |
assert.equal(Number.isNaN(notANumber), true); | |
}); | |
it('zero divided by zero', () => { | |
// const zeroDividedByZero = 0 / 1; | |
const zeroDividedByZero = 0 / 0; | |
assert.equal(Number.isNaN(zeroDividedByZero), true); | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment