adding more javascript subjects (+fixes)

This commit is contained in:
Clement Denis 2020-05-31 17:21:17 +02:00
parent ee0dc3c77c
commit 52adf5c8fd
71 changed files with 2311 additions and 56 deletions

56
js/tests/date-is_test.js Normal file
View File

@ -0,0 +1,56 @@
export const tests = []
const t = (f) => tests.push(f)
// is the date a valid date?
const invalid = (callback, ary = 1) => {
for (const s of [
`new Date('')`,
`new Date(NaN)`,
`''`,
`'2013-01-01'`,
`NaN`,
]) {
if (callback(...Array(ary).fill(eval(s)))) {
throw Error(`${callback.name}(${s}) should be false`)
}
}
}
// isValid
t(() => !invalid(isValid))
t(() => isValid(new Date()))
t(() => isValid(Date.now()))
t(() => isValid(new Date('December 17, 1995 03:24:00')))
t(() => isValid(new Date(1488370835081)))
t(() => isValid(new Date('1995-12-17T03:24:00')))
t(() => isValid(new Date('1995-12-17T03:24:00').getTime()))
// isAfter
t(() => !invalid(isAfter, 2))
t(() => !isAfter(new Date('1992-01-01'), new Date('1992-01-02')))
t(() => !isAfter(new Date('1992-01-01'), new Date('1992-01-02')))
t(() => isAfter(new Date(2321, 11, 21), new Date(Date.now())))
t(() => isAfter(123123, 526))
// isBefore
t(() => !invalid(isBefore, 2))
t(() => !isBefore(new Date(2321, 11, 21), new Date(Date.now())))
t(() => !isBefore(123123, 526))
t(() => isBefore(new Date('1992-01-01'), new Date('1992-01-02')))
t(() => isBefore(new Date('1992-01-01'), new Date('1992-01-02')))
// isFuture
t(() => !invalid(isFuture))
t(() => !isFuture(new Date('1992-01-01')))
t(() => !isFuture(new Date(Date.now() - 1)))
t(() => isFuture(new Date(2021, 11, 31)))
t(() => isFuture(new Date(Date.now() + 1)))
// isPast
t(() => !invalid(isPast))
t(() => !isPast(new Date(Date.now() + 1)))
t(() => !isPast(new Date(2021, 11, 31)))
t(() => isPast(new Date(1442, 11, 31)))
t(() => isPast(new Date(Date.now() - 1)))
Object.freeze(tests)

485
js/tests/filter_test.js Normal file
View File

@ -0,0 +1,485 @@
Array.prototype.filter = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
const check1 = (el) => el % 2 === 0
const check2 = (el, i) => el % 3 === 0 && i % 2 === 0
const check3 = (el) => Array.isArray(el)
const check4 = (el, i, arr) =>
typeof el !== 'number' && i % 2 !== 0 && arr.includes(true)
const check5 = (el, i) =>
(typeof el === 'number' || typeof el === 'boolean') && i > 5
const check6 = (el) => el.region === 'South' || el.region === 'West'
// Filter
t(({ eq, ctx }) =>
eq(filter(ctx.onlyNumbers, check1), [
10,
-10,
20,
86,
2,
32,
450,
950,
66,
150,
]),
)
t(({ eq, ctx }) => eq(filter(ctx.onlyNumbers, check2), [15, 33, 450, 66]))
t(({ eq, ctx }) =>
eq(filter(ctx.mixedTypes, check3), [
['how', 'are', 'the', 2],
['iu', 2],
]),
)
t(({ eq, ctx }) =>
eq(filter(ctx.mixedTypes, check4), [
['how', 'are', 'the', 2],
['iu', 2],
'good',
true,
]),
)
t(({ eq, ctx }) =>
eq(filter(ctx.mixedTypes, check5), [-10, 2, 65, 2, 2678, true]),
)
// Reject
t(({ eq, ctx }) => eq(reject(ctx.onlyNumbers, check1), [-95, 15, 3, 5, 33, 45]))
t(({ eq, ctx }) =>
eq(reject(ctx.onlyNumbers, check2), [
10,
-10,
20,
-95,
86,
2,
3,
5,
32,
45,
950,
150,
]),
)
t(({ eq, ctx }) =>
eq(reject(ctx.mixedTypes, check3), [
1,
2,
4,
8,
'hello',
12,
-10,
'of',
'well',
2,
65,
'good',
2,
2678,
'be',
true,
]),
)
t(({ eq, ctx }) =>
eq(reject(ctx.mixedTypes, check4), [
1,
2,
4,
8,
'hello',
12,
-10,
'of',
'well',
2,
65,
2,
2678,
'be',
]),
)
t(({ eq, ctx }) =>
eq(reject(ctx.mixedTypes, check5), [
1,
2,
4,
8,
'hello',
12,
['how', 'are', 'the', 2],
'of',
['iu', 2],
'well',
'good',
'be',
]),
)
// Partition
t(({ eq, ctx }) =>
eq(partition(ctx.onlyNumbers, check1), [
[10, -10, 20, 86, 2, 32, 450, 950, 66, 150],
[-95, 15, 3, 5, 33, 45],
]),
)
t(({ eq, ctx }) =>
eq(partition(ctx.onlyNumbers, check2), [
[15, 33, 450, 66],
[10, -10, 20, -95, 86, 2, 3, 5, 32, 45, 950, 150],
]),
)
t(({ eq, ctx }) =>
eq(partition(ctx.mixedTypes, check3), [
[
['how', 'are', 'the', 2],
['iu', 2],
],
[
1,
2,
4,
8,
'hello',
12,
-10,
'of',
'well',
2,
65,
'good',
2,
2678,
'be',
true,
],
]),
)
t(({ eq, ctx }) =>
eq(partition(ctx.mixedTypes, check4), [
[['how', 'are', 'the', 2], ['iu', 2], 'good', true],
[1, 2, 4, 8, 'hello', 12, -10, 'of', 'well', 2, 65, 2, 2678, 'be'],
]),
)
t(({ eq, ctx }) =>
eq(partition(ctx.mixedTypes, check5), [
[-10, 2, 65, 2, 2678, true],
[
1,
2,
4,
8,
'hello',
12,
['how', 'are', 'the', 2],
'of',
['iu', 2],
'well',
'good',
'be',
],
]),
)
/// Filter on an object
t(({ eq, ctx }) =>
eq(filter(ctx.statesData, check6), [
{
tag: 'AL',
name: 'Alabama',
capital: 'Montgomery',
region: 'South',
},
{ tag: 'AK', name: 'Alaska', capital: 'Juneau', region: 'West' },
{ tag: 'AZ', name: 'Arizona', capital: 'Phoenix', region: 'West' },
{
tag: 'AR',
name: 'Arkansas',
capital: 'Little Rock',
region: 'South',
},
{
tag: 'CA',
name: 'California',
capital: 'Sacramento',
region: 'West',
},
{ tag: 'CO', name: 'Colorado', capital: 'Denver', region: 'West' },
{ tag: 'DE', name: 'Delaware', capital: 'Dover', region: 'South' },
{
tag: 'DC',
name: 'District Of Columbia',
capital: 'Washington',
region: 'South',
},
{
tag: 'FL',
name: 'Florida',
capital: 'Tallahassee',
region: 'South',
},
{ tag: 'GA', name: 'Georgia', capital: 'Atlanta', region: 'South' },
{ tag: 'HI', name: 'Hawaii', capital: 'Honolulu', region: 'West' },
{ tag: 'ID', name: 'Idaho', capital: 'Boise', region: 'West' },
{
tag: 'KY',
name: 'Kentucky',
capital: 'Frankfort',
region: 'South',
},
{
tag: 'LA',
name: 'Louisiana',
capital: 'Baton Rouge',
region: 'South',
},
{
tag: 'MD',
name: 'Maryland',
capital: 'Annapolis',
region: 'South',
},
{
tag: 'MS',
name: 'Mississippi',
capital: 'Jackson',
region: 'South',
},
{ tag: 'MT', name: 'Montana', capital: 'Helena', region: 'West' },
{ tag: 'NV', name: 'Nevada', capital: 'Carson City', region: 'West' },
{
tag: 'NM',
name: 'New Mexico',
capital: 'Santa Fe',
region: 'West',
},
{
tag: 'NC',
name: 'North Carolina',
capital: 'Raleigh',
region: 'South',
},
{
tag: 'OK',
name: 'Oklahoma',
capital: 'Oklahoma City',
region: 'South',
},
{ tag: 'OR', name: 'Oregon', capital: 'Salem', region: 'West' },
{
tag: 'SC',
name: 'South Carolina',
capital: 'Columbia',
region: 'South',
},
{
tag: 'TN',
name: 'Tennessee',
capital: 'Nashville',
region: 'South',
},
{ tag: 'TX', name: 'Texas', capital: 'Austin', region: 'South' },
{
tag: 'UT',
name: 'Utah',
capital: 'Salt Lake City',
region: 'West',
},
{ tag: 'VA', name: 'Virginia', capital: 'Richmond', region: 'South' },
{ tag: 'WA', name: 'Washington', capital: 'Olympia', region: 'West' },
{
tag: 'WV',
name: 'West Virginia',
capital: 'Charleston',
region: 'South',
},
{ tag: 'WY', name: 'Wyoming', capital: 'Cheyenne', region: 'West' },
]),
)
export const setup = () => {
const onlyNumbers = Object.freeze([
10,
-10,
20,
-95,
15,
86,
2,
3,
5,
32,
33,
45,
450,
950,
66,
150,
])
const mixedTypes = Object.freeze([
1,
2,
4,
8,
'hello',
12,
-10,
['how', 'are', 'the', 2],
'of',
['iu', 2],
'well',
2,
65,
'good',
2,
2678,
'be',
true,
])
const statesData = Object.freeze(
[
{ tag: 'AL', name: 'Alabama', capital: 'Montgomery', region: 'South' },
{ tag: 'AK', name: 'Alaska', capital: 'Juneau', region: 'West' },
{ tag: 'AZ', name: 'Arizona', capital: 'Phoenix', region: 'West' },
{ tag: 'AR', name: 'Arkansas', capital: 'Little Rock', region: 'South' },
{ tag: 'CA', name: 'California', capital: 'Sacramento', region: 'West' },
{ tag: 'CO', name: 'Colorado', capital: 'Denver', region: 'West' },
{
tag: 'CT',
name: 'Connecticut',
capital: 'Hartford',
region: 'Northeast',
},
{ tag: 'DE', name: 'Delaware', capital: 'Dover', region: 'South' },
{
tag: 'DC',
name: 'District Of Columbia',
capital: 'Washington',
region: 'South',
},
{ tag: 'FL', name: 'Florida', capital: 'Tallahassee', region: 'South' },
{ tag: 'GA', name: 'Georgia', capital: 'Atlanta', region: 'South' },
{ tag: 'HI', name: 'Hawaii', capital: 'Honolulu', region: 'West' },
{ tag: 'ID', name: 'Idaho', capital: 'Boise', region: 'West' },
{
tag: 'IL',
name: 'Illinois',
capital: 'Springfield',
region: 'Midwest',
},
{
tag: 'IN',
name: 'Indiana',
capital: 'Indianapolis',
region: 'Midwest',
},
{ tag: 'IA', name: 'Iowa', capital: 'Des Moines', region: 'Midwest' },
{ tag: 'KS', name: 'Kansas', capital: 'Topeka', region: 'Midwest' },
{ tag: 'KY', name: 'Kentucky', capital: 'Frankfort', region: 'South' },
{ tag: 'LA', name: 'Louisiana', capital: 'Baton Rouge', region: 'South' },
{ tag: 'ME', name: 'Maine', capital: 'Augusta', region: 'Northeast' },
{ tag: 'MD', name: 'Maryland', capital: 'Annapolis', region: 'South' },
{
tag: 'MA',
name: 'Massachusetts',
capital: 'Boston',
region: 'Northeast',
},
{ tag: 'MI', name: 'Michigan', capital: 'Lansing', region: 'Midwest' },
{ tag: 'MN', name: 'Minnesota', capital: 'St. Paul', region: 'Midwest' },
{ tag: 'MS', name: 'Mississippi', capital: 'Jackson', region: 'South' },
{
tag: 'MO',
name: 'Missouri',
capital: 'Jefferson City',
region: 'Midwest',
},
{ tag: 'MT', name: 'Montana', capital: 'Helena', region: 'West' },
{ tag: 'NE', name: 'Nebraska', capital: 'Lincoln', region: 'Midwest' },
{ tag: 'NV', name: 'Nevada', capital: 'Carson City', region: 'West' },
{
tag: 'NH',
name: 'New Hampshire',
capital: 'Concord',
region: 'Northeast',
},
{
tag: 'NJ',
name: 'New Jersey',
capital: 'Trenton',
region: 'Northeast',
},
{ tag: 'NM', name: 'New Mexico', capital: 'Santa Fe', region: 'West' },
{ tag: 'NY', name: 'New York', capital: 'Albany', region: 'Northeast' },
{
tag: 'NC',
name: 'North Carolina',
capital: 'Raleigh',
region: 'South',
},
{
tag: 'ND',
name: 'North Dakota',
capital: 'Bismarck',
region: 'Midwest',
},
{ tag: 'OH', name: 'Ohio', capital: 'Colombus', region: 'Midwest' },
{
tag: 'OK',
name: 'Oklahoma',
capital: 'Oklahoma City',
region: 'South',
},
{ tag: 'OR', name: 'Oregon', capital: 'Salem', region: 'West' },
{
tag: 'PA',
name: 'Pennsylvania',
capital: 'Harrisburg',
region: 'Northeast',
},
{
tag: 'RI',
name: 'Rhode Island',
capital: 'Providence',
region: 'Northeast',
},
{
tag: 'SC',
name: 'South Carolina',
capital: 'Columbia',
region: 'South',
},
{ tag: 'SD', name: 'South Dakota', capital: 'Pierre', region: 'Midwest' },
{ tag: 'TN', name: 'Tennessee', capital: 'Nashville', region: 'South' },
{ tag: 'TX', name: 'Texas', capital: 'Austin', region: 'South' },
{ tag: 'UT', name: 'Utah', capital: 'Salt Lake City', region: 'West' },
{
tag: 'VT',
name: 'Vermont',
capital: 'Montpelier',
region: 'Northeast',
},
{ tag: 'VA', name: 'Virginia', capital: 'Richmond', region: 'South' },
{ tag: 'WA', name: 'Washington', capital: 'Olympia', region: 'West' },
{
tag: 'WV',
name: 'West Virginia',
capital: 'Charleston',
region: 'South',
},
{ tag: 'WI', name: 'Wisconsin', capital: 'Madison', region: 'Midwest' },
{ tag: 'WY', name: 'Wyoming', capital: 'Cheyenne', region: 'West' },
].map((e) => Object.freeze(e)),
)
Object.getPrototypeOf([]).proto = ' [avoid for..in] '
return { onlyNumbers, mixedTypes, statesData }
}
Object.freeze(tests)

33
js/tests/for-each_test.js Normal file
View File

@ -0,0 +1,33 @@
Array.prototype.forEach = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
export const setup = () => {
const arr = [1, 2, 3, 4, 5, Math.random(), 7, 10, -10, 20, -95]
Object.getPrototypeOf([]).proto = ' [avoid for..in] '
return { arr }
}
// callback is call with the item value
t(({ eq, ctx }) => {
const result = []
forEach(ctx.arr, (value) => result.push(value))
return eq(result, ctx.arr)
})
// callback second parameter is the index
t(({ eq, ctx }) => {
const result = []
forEach(ctx.arr, (_, index) => result.push(index))
return eq(result, [...ctx.arr.keys()])
})
// callback third parameter is the array
t(({ eq, ctx }) => {
const result = []
forEach(ctx.arr, (_, __, arr) => result.push(arr))
return eq(result, Array(ctx.arr.length).fill(ctx.arr))
})
Object.freeze(tests)

70
js/tests/get-json_test.js Normal file
View File

@ -0,0 +1,70 @@
export const tests = []
const t = (f) => tests.push(f)
const fakeFetch = async ({ data, error, ...opts } = {}) => ({
ok: !opts.status,
type: 'basic',
status: 200,
statusText: 'OK',
json: async () => ({ data, error }),
text: async () => JSON.stringify({ data, error }),
...opts,
})
// check url parsing
t(async ({ eq }) => {
let url
fetch = async (arg) => fakeFetch({ url: (url = arg) })
const pending = getJSON('/test', { query: 'hello world', b: 5 })
return eq(url, '/test?query=hello%20world&b=5')
})
// check that it return the given value
t(async ({ eq }) => {
const data = Math.random()
fetch = (url) => fakeFetch({ url, data })
return eq(await getJSON('/', { q: 1 }), data)
})
// check that it throw an error with the correct message
t(async ({ eq }) => {
const error = `oops: ${Math.random()}`
fetch = (url) => fakeFetch({ url, error })
return eq(
await getJSON('/', { q: 1 }).then(
() => Promise.reject(Error('Should fail')),
(err) => err.message,
),
error,
)
})
// check that it throw if the request is not ok
t(async ({ eq }) => {
fetch = (url) =>
fakeFetch({ url, status: 500, statusText: 'Internal Server Error' })
return eq(
await getJSON('/', { q: 1 }).then(
() => Promise.reject(Error('Should fail')),
(err) => err.message,
),
'Internal Server Error',
)
})
// if fetch fail, the error should not be handled
t(async ({ eq }) => {
const error = `oops: ${Math.random()}`
fetch = (url) => Promise.reject(Error(error))
return eq(
await getJSON('/', { q: 1 }).then(
() => Promise.reject(Error('Should fail')),
(err) => err.message,
),
error,
)
})
export const setup = () => globalThis.fetch

View File

@ -0,0 +1,14 @@
export const tests = []
const t = (f) => tests.push(f)
t(({ eq }) => eq(firstDayWeek(1, '1000'), '01-01-1000'))
t(({ eq }) => eq(firstDayWeek(52, '1000'), '22-12-1000'))
t(({ eq }) => eq(firstDayWeek(2, '0001'), '08-01-0001'))
t(({ eq }) => eq(firstDayWeek(43, '1983'), '17-10-1983'))
t(({ eq }) => eq(firstDayWeek(23, '0091'), '04-06-0091'))
Object.freeze(tests)

View File

@ -0,0 +1,60 @@
// fake `getJSON` function
let getJSON = async (url) => url
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// queryServers with main server be fastest
t(async ({ eq, ctx }) => {
ctx.setTimings({ pouet_backup: 2 })
return eq(await queryServers('pouet', ctx.r), `/pouet?q=${ctx.r}`)
})
// queryServers with backup server be fastest
t(async ({ eq, ctx }) => {
ctx.setTimings({ pouet: 2 })
return eq(await queryServers('pouet', ctx.r), `/pouet_backup?q=${ctx.r}`)
})
// gougleSearch fast enough
t(async ({ eq, ctx }) => {
ctx.setTimings({ web_backup: 3, image: 2, video_backup: 4 })
return eq(await gougleSearch(ctx.r), {
web: `/web?q=${ctx.r}`,
image: `/image_backup?q=${ctx.r}`,
video: `/video?q=${ctx.r}`,
})
})
// gougleSearch fast enough, alternate timings
t(async ({ eq, ctx }) => {
ctx.setTimings({ web: 3, image_backup: 1, video: 4 })
return eq(await gougleSearch(ctx.r), {
web: `/web_backup?q=${ctx.r}`,
image: `/image?q=${ctx.r}`,
video: `/video_backup?q=${ctx.r}`,
})
})
// gougleSearch too slow !
t(async ({ eq, ctx }) => {
ctx.setTimings({ web: 85, web_backup: 99 })
return eq(
await gougleSearch(ctx.r).then(
() => Promise.reject(Error('Should fail')),
(err) => err.message,
),
'timeout',
)
})
Object.freeze(tests)
export const setup = () => ({
r: Math.random().toString(36).slice(2),
setTimings: (timings) =>
(getJSON = (url) =>
new Promise((s) =>
setTimeout(s, timings[url.split(/\/([^?]+)?/)[1]] || 0, url),
)),
})

View File

@ -0,0 +1,85 @@
export const tests = []
const t = (f) => tests.push(f)
const run = async ({ step, start, end, duration, waitTime = 15 }) => {
let arr = []
const round = (nbr) => Math.round(nbr * 100) / 100
const callback = (el) =>
arr.push(Array.isArray(el) ? el.map(round) : round(el))
interpolation({ step, start, end, callback, duration })
await new Promise((s) => setTimeout(s, waitTime))
return arr
}
// testing duration time, forbid loops
t(async ({ eq }) => {
const { length } = await run({ step: 5, start: 0, end: 4, duration: 28 })
return eq(length, 2)
})
// testing duration time stamp
t(async ({ eq }) => {
const { length } = await run({
step: 5,
start: 0,
end: 4,
duration: 10,
waitTime: 0,
})
return eq(length, 0)
})
// testing the amount of times the callback was called
t(async ({ eq }) => {
const { length } = await run({ step: 5, start: 0, end: 1, duration: 10 })
return eq(length, 5)
})
// testing the interpolation points
t(async ({ eq }) =>
eq(await run({ step: 5, start: 0, end: 1, duration: 10 }), [
[0, 2],
[0.2, 4],
[0.4, 6],
[0.6, 8],
[0.8, 10],
]),
)
// testing with different values
t(async ({ eq }) =>
eq(await run({ step: 3, start: 1, end: 2, duration: 10 }), [
[1, 3.33],
[1.33, 6.67],
[1.67, 10],
]),
)
// testing with `duration` inferior to `step`
t(async ({ eq }) =>
eq(await run({ step: 10, start: 2, end: 6, duration: 4 }), [
[2, 0.4],
[2.4, 0.8],
[2.8, 1.2],
[3.2, 1.6],
[3.6, 2],
[4, 2.4],
[4.4, 2.8],
[4.8, 3.2],
[5.2, 3.6],
[5.6, 4],
]),
)
// testing with `start` superior to `end`
// inverted straight line
t(async ({ eq }) =>
eq(await run({ step: 5, start: 6, end: 2, duration: 6, waitTime: 10 }), [
[6, 1.2],
[5.2, 2.4],
[4.4, 3.6],
[3.6, 4.8],
[2.8, 6],
]),
)
Object.freeze(tests)

120
js/tests/is-winner_test.js Normal file
View File

@ -0,0 +1,120 @@
const db = (() => {
//countries that won the FIFA World Cup
const countries = [
{ id: 1, name: 'Brazil', continent: 'South America' },
{ id: 2, name: 'Germany', continent: 'Europe' },
{ id: 3, name: 'Italy', continent: 'Europe' },
{ id: 4, name: 'Argentina', continent: 'South America' },
{ id: 5, name: 'France', continent: 'Europe' },
{ id: 6, name: 'Uruguay', continent: 'South America' },
{ id: 7, name: 'England', continent: 'Europe' },
{ id: 8, name: 'Spain', continent: 'Europe' },
]
//Information about the wins
const results = [
{ id: 1, countryId: 6, year: 1930, score: '4-2' },
{ id: 2, countryId: 3, year: 1934, score: '2-1' },
{ id: 3, countryId: 3, year: 1938, score: '4-2' },
{ id: 4, countryId: 6, year: 1950, score: '2-1' },
{ id: 5, countryId: 2, year: 1954, score: '3-2' },
{ id: 6, countryId: 1, year: 1958, score: '5-2' },
{ id: 7, countryId: 1, year: 1962, score: '3-1' },
{ id: 8, countryId: 7, year: 1966, score: '4-2' },
{ id: 9, countryId: 1, year: 1970, score: '4-1' },
{ id: 10, countryId: 2, year: 1974, score: '2-1' },
{ id: 11, countryId: 4, year: 1978, score: '3-1' },
{ id: 12, countryId: 3, year: 1982, score: '3-1' },
{ id: 13, countryId: 4, year: 1986, score: '3-2' },
{ id: 14, countryId: 2, year: 1990, score: '1-0' },
{ id: 15, countryId: 1, year: 1994, score: '3-2p' },
{ id: 16, countryId: 5, year: 1998, score: '3-0' },
{ id: 17, countryId: 1, year: 2002, score: '2-0' },
{ id: 18, countryId: 3, year: 2006, score: '5-3p' },
{ id: 19, countryId: 8, year: 2010, score: '1-0' },
{ id: 20, countryId: 2, year: 2014, score: '1-0' },
{ id: 21, countryId: 5, year: 2018, score: '4-2' },
]
return {
//returns the information of the country
getWinner: async (countryName) => {
const match = countries.find((country) => country.name === countryName)
if (!match) throw Error('Country Not Found')
return match
},
//returns the information of the wins of that country
getResults: async (countryId) => {
const match = results.filter((result) => result.countryId === countryId)
if (!match.length) throw Error('Results Not Found')
return match
},
addCountry: (country) => countries.push(country),
addResults: (result) => results.push(result),
}
})()
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
// testing correct continent but wrong number of times
t(async ({ eq }) =>
eq(
await isWinner('England'),
'England is not what we are looking for because of the number of times it was champion',
),
)
// testing non winner country
t(async ({ eq }) =>
eq(await isWinner('Colombia'), 'Colombia never was a winner'),
)
// testing wrong continent country
t(async ({ eq }) =>
eq(
await isWinner('Uruguay'),
'Uruguay is not what we are looking for because of the continent',
),
)
// testing no country
t(async ({ eq }) => eq(await isWinner(''), ' never was a winner'))
// testing correct number of times but wrong continent
t(async ({ eq }) =>
eq(
await isWinner('Brazil'),
'Brazil is not what we are looking for because of the continent',
),
)
// testing correct number of times and correct continent
t(async ({ eq }) =>
eq(
await isWinner('Germany'),
'Germany won the FIFA World Cup in 1954, 1974, 1990, 2014 winning by 3-2, 2-1, 1-0, 1-0',
),
)
// testing correct number of times and correct continent, for the fake country
t(async ({ eq, ctx }) =>
eq(
await isWinner(ctx.name),
`${ctx.name} won the FIFA World Cup in 2022, 2026, 2030 winning by 1-0, 3-1, 2-1`,
),
)
Object.freeze(tests)
export const setup = () => {
const seed = Math.random()
const name = seed.toString(36).slice(2)
db.addCountry({ id: 9, name, continent: 'Europe' })
db.addResults({ countryId: 9, year: 2022, score: '1-0' })
db.addResults({ countryId: 9, year: 2026, score: '3-1' })
db.addResults({ countryId: 9, year: 2030, score: '2-1' })
return { name }
}

View File

@ -0,0 +1,34 @@
export const tests = []
const t = (f) => tests.push(f)
const fail = (q) =>
q.then(
(v) => Promise.reject('should fail'),
(e) => e.message,
)
t(async ({ eq, ctx }) => eq(await retry(0, ctx.failNTimes(0))(ctx.r), [ctx.r]))
t(async ({ eq, ctx }) => eq(await retry(3, ctx.failNTimes(3))(ctx.r), [ctx.r]))
t(async ({ eq, ctx }) =>
eq(await retry(10, ctx.failNTimes(5))(ctx.r, ctx.r), [ctx.r, ctx.r]),
)
t(async ({ eq, ctx }) =>
eq(await fail(retry(3, ctx.failNTimes(9))(ctx.r)), `x:${ctx.r}`),
)
t(async ({ eq, ctx }) => eq(await timeout(2, ctx.delayed(0))(ctx.r), [ctx.r]))
t(async ({ eq, ctx }) =>
eq(await timeout(2, ctx.delayed(0))(ctx.r, ctx.r), [ctx.r, ctx.r]),
)
t(async ({ eq, ctx }) =>
eq(await fail(timeout(2, ctx.delayed(4))(ctx.r)), 'timeout'),
)
Object.freeze(tests)
export const setup = () => ({
r: Math.random().toString(36).slice(2),
failNTimes: (n) => async (...v) =>
--n < 0 ? v : Promise.reject(Error(`x:${v}`)),
delayed: (delay) => (...v) => new Promise((s) => setTimeout(s, delay, v)),
})

142
js/tests/mapper_test.js Normal file
View File

@ -0,0 +1,142 @@
Array.prototype.map = undefined
Array.prototype.flatMap = undefined
Array.prototype.flat = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
const add1 = (el) => el + 1
const sub3 = (el) => el - 3
const mult2 = (el) => el * 2
const doAll = (el) => sub3(mult2(add1(el)))
const posValsIndex = (el, i) => (el >= 0 ? `${i}: ${el}` : undefined)
const indexValsArray = (el, i, arr) =>
`${el} is at index: ${i} out of ${arr.length - 1}`
const arrayFormatSentence = (item, index, arr) => {
if (index === arr.length - 2) return `and ${arr[arr.length - 2]} `
if (index === arr.length - 1) {
return `are ${String(arr.length - 1)} ${item}.`
}
return `${item}, `
}
// map
t(({ eq, ctx }) =>
eq(map(ctx.numbers, add1), [11, -9, 21, -94, 87, 103, 36, 90, 111]),
)
t(({ eq, ctx }) =>
eq(map(ctx.numbers, mult2), [20, -20, 40, -190, 172, 204, 70, 178, 220]),
)
t(({ eq, ctx }) =>
eq(map(ctx.numbers, sub3), [7, -13, 17, -98, 83, 99, 32, 86, 107]),
)
t(({ eq, ctx }) =>
eq(map(ctx.numbers, doAll), [19, -21, 39, -191, 171, 203, 69, 177, 219]),
)
t(({ eq, ctx }) =>
eq(map(ctx.numbers, posValsIndex), [
'0: 10',
undefined,
'2: 20',
undefined,
'4: 86',
'5: 102',
'6: 35',
'7: 89',
'8: 110',
]),
)
t(({ eq, ctx }) =>
eq(map(ctx.numbers, indexValsArray), [
'10 is at index: 0 out of 8',
'-10 is at index: 1 out of 8',
'20 is at index: 2 out of 8',
'-95 is at index: 3 out of 8',
'86 is at index: 4 out of 8',
'102 is at index: 5 out of 8',
'35 is at index: 6 out of 8',
'89 is at index: 7 out of 8',
'110 is at index: 8 out of 8',
]),
)
t(({ eq, ctx }) =>
eq(
map(ctx.sentences[0], arrayFormatSentence).join(''),
'Colombia, Mexico, and El Salvador are 3 Spanish speaking countries.',
),
)
t(({ eq, ctx }) =>
eq(
map(ctx.sentences[1], arrayFormatSentence).join(''),
'Perou, Brazil, Argentina, and Venezuela are 4 countries in South America.',
),
)
t(({ eq, ctx }) =>
eq(
map(ctx.sentences[2], arrayFormatSentence).join(''),
'France, Portugal, and Italy are 3 members of the EU.',
),
)
// flatMap
t(({ eq, ctx }) =>
eq(flatMap(ctx.mixed, add1), ['101', -9, 21, -94, 87, '1021', '35,891', 111]),
)
t(({ eq, ctx }) =>
eq(flatMap(ctx.mixed, posValsIndex), [
'0: 10',
undefined,
'2: 20',
undefined,
'4: 86',
'5: 102',
undefined,
'7: 110',
]),
)
t(({ eq, ctx }) =>
eq(flatMap(ctx.nested, indexValsArray), [
'5 is at index: 0 out of 7',
'4 is at index: 1 out of 7',
'-3 is at index: 2 out of 7',
'20 is at index: 3 out of 7',
'17 is at index: 4 out of 7',
'-33 is at index: 5 out of 7',
'-4 is at index: 6 out of 7',
'18 is at index: 7 out of 7',
]),
)
Object.freeze(tests)
export const setup = () => {
const numbers = [10, -10, 20, -95, 86, 102, 35, 89, 110]
const mixed = [[10], -10, 20, -95, 86, [102], [35, 89], 110]
const nested = [[5], [4], [-3], [20], [17], [-33], [-4], [18]]
const sentences = [
['Colombia', 'Mexico', 'El Salvador', 'Spanish speaking countries'],
['Perou', 'Brazil', 'Argentina', 'Venezuela', 'countries in South America'],
['France', 'Portugal', 'Italy', 'members of the EU'],
]
Object.getPrototypeOf([]).proto = ' [avoid for..in] '
Object.freeze(numbers)
Object.freeze(mixed)
Object.freeze(nested)
Object.freeze(sentences[0])
Object.freeze(sentences[1])
Object.freeze(sentences[2])
return { numbers, mixed, nested, sentences }
}

View File

@ -0,0 +1,23 @@
export const tests = []
const t = (f) => tests.push(f)
t(() => matchCron('* * * * 1', new Date('2020-06-01 00:00:00')))
t(() => matchCron('* * * 2 *', new Date('2021-02-01 00:00:00')))
t(() => matchCron('* * 9 * *', new Date('2020-06-09 00:00:00')))
t(() => matchCron('* 3 * * *', new Date('2020-05-31 03:00:00')))
t(() => matchCron('1 * * * *', new Date('2020-05-30 19:01:00')))
t(() => matchCron('3 3 * 3 3', new Date('2021-03-03 03:03:00')))
t(() => matchCron('* * * * *', new Date()))
t(({ ctx }) => matchCron('* 7 * * *', new Date(`201${ctx}-01-01 07:00:00`)))
t(() => !matchCron('* * * * 1', new Date('2020-06-02 00:00:00')))
t(() => !matchCron('* * * 2 *', new Date('2021-03-01 00:00:00')))
t(() => !matchCron('* * 8 * *', new Date('2020-06-09 00:00:00')))
t(() => !matchCron('* 2 * * *', new Date('2020-05-31 03:00:00')))
t(() => !matchCron('1 * * * *', new Date('2020-05-30 19:00:00')))
t(() => !matchCron('3 3 * 3 3', new Date('2021-03-02 03:03:00')))
t(({ ctx }) => !matchCron('* 7 * * *', new Date(`201${ctx}-01-01 06:00:00`)))
Object.freeze(tests)
export const setup = () => Math.ceil(Math.random() * 9)

View File

@ -33,7 +33,7 @@ t(() => cantEdit(() => (nested.obj.update = 5)))
t(() => nested.obj.update === undefined)
// nested.arr is not frozen and can be changed
t(() => nested.arr.push('hot stuff'))
t(() => nested.arr.length === 4)
t(() => cantEdit(() => nested.arr.push('hot stuff')))
t(() => nested.arr.length === 3)
Object.freeze(tests)

71
js/tests/race_test.js Normal file
View File

@ -0,0 +1,71 @@
Promise.race = undefined
// /*/ // ⚡
export const tests = []
const t = (f) => tests.push(f)
//// RACE
// empty array should never resolve, just hang, forever...
t(async ({ eq, wait }) => {
let notCalled = true
race([]).then(() => (notCalled = false))
await wait(5)
return eq(notCalled, true)
})
// it should return the first value to resolve
t(async ({ eq, wait }) =>
eq(await race([Promise.resolve(2), wait(5).then(() => 5)]), 2),
)
// it should not wait for every results to wait
t(async ({ eq, wait }) => {
const start = Date.now()
const result = await race([Promise.resolve(2), wait(50)])
if (Date.now() - start > 5) throw Error("that's too long !")
return eq(result, 2)
})
// it should fail if the first promise reject
t(async ({ eq, wait }) =>
eq(
await race([wait(5), Promise.reject(Error('oops'))]).catch(
(err) => err.message,
),
'oops',
),
)
// it should not fail if the first promise did not reject
t(async ({ eq, wait, ctx }) =>
eq(
await race([
wait(5).then(() => Promise.reject(Error('oops'))),
Promise.resolve(ctx),
]).catch((err) => err.message),
ctx,
),
)
//// SOME
// empty array returns an empty array
t(async ({ eq }) => eq(await some([], 10), []))
// a count of less than 1 also returns an empty array
t(async ({ eq }) => eq(await some([1, 2, 3], 0), []))
// it should return the first value to resolve
t(async ({ eq, wait }) =>
eq(await some([Promise.resolve(2), wait(5).then(() => 5)], 1), [2]),
)
// it should not wait for every results to wait, the order should be preserved.
t(async ({ eq, wait }) => {
const start = Date.now()
const result = await some([wait(1), wait(50), Promise.resolve(5)], 2)
if (Date.now() - start > 5) throw Error("that's too long !")
return eq(result, [undefined, 5])
})
Object.freeze(tests)
export const setup = Math.random

View File

@ -0,0 +1,33 @@
export const tests = []
const t = (f) => tests.push(f)
// isFriday
t(() => isFriday(new Date('2014-08-29')))
t(() => isFriday(new Date('2020-07-17')))
t(() => !isFriday(new Date('1992-08-26')))
t(() => !isFriday(new Date('2000-08-26')))
// isWeekend
t(() => isWeekend(new Date('2014-09-06')))
t(() => isWeekend(new Date('2020-05-30')))
t(() => !isWeekend(new Date('1929-02-13')))
t(() => !isWeekend(new Date('1990-01-30')))
// isLeapYear
t(() => isLeapYear(new Date('1804-02-01')))
t(() => isLeapYear(new Date('2008-02-01')))
t(() => isLeapYear(new Date('2216-02-01')))
t(() => !isLeapYear(new Date('1993-02-01')))
t(() => !isLeapYear(new Date('1999-02-01')))
// isLastDayOfMonth
t(() => isLastDayOfMonth(new Date('2020-02-29')))
t(() => isLastDayOfMonth(new Date('2020-12-31')))
t(() => isLastDayOfMonth(new Date('2019-02-28')))
t(() => isLastDayOfMonth(new Date('1998-02-28')))
t(() => isLastDayOfMonth(new Date('1980-02-29')))
t(() => !isLastDayOfMonth(new Date('2020-12-30')))
t(() => !isLastDayOfMonth(new Date('2020-02-28')))
t(() => !isLastDayOfMonth(new Date('2019-02-29')))
Object.freeze(tests)

View File

@ -0,0 +1,293 @@
export const tests = []
const t = (f) => tests.push(f)
const check = ({ filterCalls }, eq, a, b) => {
const result = eq(a, b)
const len = filterCalls.length
filterCalls.length = 0
return len ? result : false
}
t(({ eq, ctx }) =>
check(ctx, eq, filterShortStateName(ctx.arr1), [
'Alaska',
'Hawaii',
'Idaho',
'Iowa',
'Kansas',
'Maine',
'Nevada',
'Ohio',
'Oregon',
'Texas',
'Utah',
]),
)
t(({ eq, ctx }) =>
check(ctx, eq, filterStartVowel(ctx.arr1), [
'Alabama',
'Alaska',
'Arizona',
'Arkansas',
'Idaho',
'Illinois',
'Indiana',
'Iowa',
'Ohio',
'Oklahoma',
'Oregon',
'Utah',
]),
)
t(({ eq, ctx }) =>
check(ctx, eq, filter5Vowels(ctx.arr1), [
'California',
'Louisiana',
'North Carolina',
'South Carolina',
'South Dakota',
'West Virginia',
]),
)
t(({ eq, ctx }) =>
check(ctx, eq, filter1DistinctVowel(ctx.arr1), [
'Alabama',
'Alaska',
'Arkansas',
'Kansas',
'Maryland',
'Mississippi',
'New Jersey',
'Tennessee',
]),
)
t(({ eq, ctx }) =>
check(ctx, eq, multiFilter(ctx.arr2), [
{ tag: 'CA', name: 'California', capital: 'Sacramento', region: 'West' },
{ tag: 'HI', name: 'Hawaii', capital: 'Honolulu', region: 'West' },
{
tag: 'MO',
name: 'Missouri',
capital: 'Jefferson City',
region: 'Midwest',
},
{
tag: 'PA',
name: 'Pennsylvania',
capital: 'Harrisburg',
region: 'Northeast',
},
{
tag: 'RI',
name: 'Rhode Island',
capital: 'Providence',
region: 'Northeast',
},
]),
)
Object.freeze(tests)
export const setup = () => {
const filterCalls = []
const _filter = Array.prototype.filter
Array.prototype.filter = function () {
filterCalls.push(this)
return _filter.apply(this, arguments)
}
const arr1 = Object.freeze([
'Alabama',
'Alaska',
'Arizona',
'Arkansas',
'California',
'Colorado',
'Connecticut',
'Delaware',
'Florida',
'Georgia',
'Hawaii',
'Idaho',
'Illinois',
'Indiana',
'Iowa',
'Kansas',
'Kentucky',
'Louisiana',
'Maine',
'Maryland',
'Massachusetts',
'Michigan',
'Minnesota',
'Mississippi',
'Missouri',
'Montana',
'Nebraska',
'Nevada',
'New Hampshire',
'New Jersey',
'New Mexico',
'New York',
'North Carolina',
'North Dakota',
'Ohio',
'Oklahoma',
'Oregon',
'Pennsylvania',
'Rhode Island',
'South Carolina',
'South Dakota',
'Tennessee',
'Texas',
'Utah',
'Vermont',
'Virginia',
'Washington',
'West Virginia',
'Wisconsin',
'Wyoming',
])
const arr2 = Object.freeze(
[
{ tag: 'AL', name: 'Alabama', capital: 'Montgomery', region: 'South' },
{ tag: 'AK', name: 'Alaska', capital: 'Juneau', region: 'West' },
{ tag: 'AZ', name: 'Arizona', capital: 'Phoenix', region: 'West' },
{ tag: 'AR', name: 'Arkansas', capital: 'Little Rock', region: 'South' },
{ tag: 'CA', name: 'California', capital: 'Sacramento', region: 'West' },
{ tag: 'CO', name: 'Colorado', capital: 'Denver', region: 'West' },
{
tag: 'CT',
name: 'Connecticut',
capital: 'Hartford',
region: 'Northeast',
},
{ tag: 'DE', name: 'Delaware', capital: 'Dover', region: 'South' },
{
tag: 'DC',
name: 'District Of Columbia',
capital: 'Washington',
region: 'South',
},
{ tag: 'FL', name: 'Florida', capital: 'Tallahassee', region: 'South' },
{ tag: 'GA', name: 'Georgia', capital: 'Atlanta', region: 'South' },
{ tag: 'HI', name: 'Hawaii', capital: 'Honolulu', region: 'West' },
{ tag: 'ID', name: 'Idaho', capital: 'Boise', region: 'West' },
{
tag: 'IL',
name: 'Illinois',
capital: 'Springfield',
region: 'Midwest',
},
{
tag: 'IN',
name: 'Indiana',
capital: 'Indianapolis',
region: 'Midwest',
},
{ tag: 'IA', name: 'Iowa', capital: 'Des Moines', region: 'Midwest' },
{ tag: 'KS', name: 'Kansas', capital: 'Topeka', region: 'Midwest' },
{ tag: 'KY', name: 'Kentucky', capital: 'Frankfort', region: 'South' },
{ tag: 'LA', name: 'Louisiana', capital: 'Baton Rouge', region: 'South' },
{ tag: 'ME', name: 'Maine', capital: 'Augusta', region: 'Northeast' },
{ tag: 'MD', name: 'Maryland', capital: 'Annapolis', region: 'South' },
{
tag: 'MA',
name: 'Massachusetts',
capital: 'Boston',
region: 'Northeast',
},
{ tag: 'MI', name: 'Michigan', capital: 'Lansing', region: 'Midwest' },
{ tag: 'MN', name: 'Minnesota', capital: 'St. Paul', region: 'Midwest' },
{ tag: 'MS', name: 'Mississippi', capital: 'Jackson', region: 'South' },
{
tag: 'MO',
name: 'Missouri',
capital: 'Jefferson City',
region: 'Midwest',
},
{ tag: 'MT', name: 'Montana', capital: 'Helena', region: 'West' },
{ tag: 'NE', name: 'Nebraska', capital: 'Lincoln', region: 'Midwest' },
{ tag: 'NV', name: 'Nevada', capital: 'Carson City', region: 'West' },
{
tag: 'NH',
name: 'New Hampshire',
capital: 'Concord',
region: 'Northeast',
},
{
tag: 'NJ',
name: 'New Jersey',
capital: 'Trenton',
region: 'Northeast',
},
{ tag: 'NM', name: 'New Mexico', capital: 'Santa Fe', region: 'West' },
{ tag: 'NY', name: 'New York', capital: 'Albany', region: 'Northeast' },
{
tag: 'NC',
name: 'North Carolina',
capital: 'Raleigh',
region: 'South',
},
{
tag: 'ND',
name: 'North Dakota',
capital: 'Bismarck',
region: 'Midwest',
},
{ tag: 'OH', name: 'Ohio', capital: 'Colombus', region: 'Midwest' },
{
tag: 'OK',
name: 'Oklahoma',
capital: 'Oklahoma City',
region: 'South',
},
{ tag: 'OR', name: 'Oregon', capital: 'Salem', region: 'West' },
{
tag: 'PA',
name: 'Pennsylvania',
capital: 'Harrisburg',
region: 'Northeast',
},
{
tag: 'RI',
name: 'Rhode Island',
capital: 'Providence',
region: 'Northeast',
},
{
tag: 'SC',
name: 'South Carolina',
capital: 'Columbia',
region: 'South',
},
{ tag: 'SD', name: 'South Dakota', capital: 'Pierre', region: 'Midwest' },
{ tag: 'TN', name: 'Tennessee', capital: 'Nashville', region: 'South' },
{ tag: 'TX', name: 'Texas', capital: 'Austin', region: 'South' },
{ tag: 'UT', name: 'Utah', capital: 'Salt Lake City', region: 'West' },
{
tag: 'VT',
name: 'Vermont',
capital: 'Montpelier',
region: 'Northeast',
},
{ tag: 'VA', name: 'Virginia', capital: 'Richmond', region: 'South' },
{ tag: 'WA', name: 'Washington', capital: 'Olympia', region: 'West' },
{
tag: 'WV',
name: 'West Virginia',
capital: 'Charleston',
region: 'South',
},
{ tag: 'WI', name: 'Wisconsin', capital: 'Madison', region: 'Midwest' },
{ tag: 'WY', name: 'Wyoming', capital: 'Cheyenne', region: 'West' },
].map((e) => Object.freeze(e)),
)
return { filterCalls, arr1, arr2 }
}

197
js/tests/using-map_test.js Normal file
View File

@ -0,0 +1,197 @@
export const tests = []
const t = (f) => tests.push(f)
// citiesOnly
t(({ eq, ctx }) =>
eq(citiesOnly(ctx.states), [
'Los Angeles',
'San Francisco',
'Miami',
'New York City',
'Juneau',
'Boston',
'Jackson',
'Utqiagvik',
'Albuquerque',
]),
)
t(({ eq, ctx }) => eq(ctx.mapCalls[0], ctx.states))
// upperCasingStates
t(({ eq, ctx }) =>
eq(upperCasingStates(ctx.cities), [
'Alabama',
'New Jersey',
'Alaska',
'New York',
'California',
'New Hampshire',
'Ohio',
'Texas',
'West Virginia',
]),
)
t(({ eq, ctx }) => eq(ctx.mapCalls.includes(ctx.cities), true))
// farenheitToCelsius
t(({ eq, ctx }) =>
eq(farenheitToCelsius(ctx.temps), [
'30°C',
'37°C',
'5°C',
'12°C',
'-13°C',
'21°C',
'-19°C',
]),
)
t(({ eq, ctx }) => eq(ctx.mapCalls.includes(ctx.temps), true))
// trimTemp
t(({ eq, ctx }) =>
eq(trimTemp(ctx.states), [
{
city: 'Los Angeles',
state: 'california',
region: 'West',
temperature: '101°F',
},
{
city: 'San Francisco',
state: 'california',
region: 'West',
temperature: '84°F',
},
{ city: 'Miami', state: 'Florida', region: 'South', temperature: '112°F' },
{
city: 'New York City',
state: 'new york',
region: 'North East',
temperature: '0°F',
},
{ city: 'Juneau', state: 'Alaska', region: 'West', temperature: '21°F' },
{
city: 'Boston',
state: 'massachussetts',
region: 'North East',
temperature: '45°F',
},
{
city: 'Jackson',
state: 'mississippi',
region: 'South',
temperature: '70°F',
},
{ city: 'Utqiagvik', state: 'Alaska', region: 'West', temperature: '-1°F' },
{
city: 'Albuquerque',
state: 'new mexico',
region: 'West',
temperature: '95°F',
},
]),
)
t(({ eq, ctx }) => eq(ctx.mapCalls.includes(ctx.states), true))
// tempForecasts
t(({ eq, ctx }) =>
eq(tempForecasts(ctx.states), [
'38°Celsius in Los Angeles, California',
'28°Celsius in San Francisco, California',
'44°Celsius in Miami, Florida',
'-18°Celsius in New York City, New York',
'-7°Celsius in Juneau, Alaska',
'7°Celsius in Boston, Massachussetts',
'21°Celsius in Jackson, Mississippi',
'-19°Celsius in Utqiagvik, Alaska',
'35°Celsius in Albuquerque, New Mexico',
]),
)
export const setup = () => {
const mapCalls = []
const _map = Array.prototype.map
Array.prototype.map = function () {
mapCalls.push(this)
return _map.apply(this, arguments)
}
const states = [
{
city: 'Los Angeles',
temperature: '101 °F',
state: 'california',
region: 'West',
},
{
city: 'San Francisco',
temperature: '84 °F',
state: 'california',
region: 'West',
},
{
city: 'Miami',
temperature: ' 112 °F',
state: 'Florida',
region: 'South',
},
{
city: 'New York City',
temperature: ' 0 °F',
state: 'new york',
region: 'North East',
},
{ city: 'Juneau', temperature: ' 21° F', state: 'Alaska', region: 'West' },
{
city: 'Boston',
temperature: '45 °F',
state: 'massachussetts',
region: 'North East',
},
{
city: 'Jackson',
temperature: ' 70°F ',
state: 'mississippi',
region: 'South',
},
{
city: 'Utqiagvik',
temperature: ' -1 °F',
state: 'Alaska',
region: 'West',
},
{
city: 'Albuquerque',
temperature: ' 95 °F',
state: 'new mexico',
region: 'West',
},
]
const cities = [
'alabama',
'new jersey',
'alaska',
'new york',
'california',
'new hampshire',
'ohio',
'texas',
'west virginia',
]
Object.getPrototypeOf([]).proto = ' [avoid for..in] '
const temps = ['86°F', '100°F', '41°F', '55°F', '10°F', '70°F', '-2°F']
Object.freeze(states)
Object.freeze(cities)
Object.freeze(temps)
return { mapCalls, states, cities, temps }
}
Object.freeze(tests)

View File

@ -1,6 +1,6 @@
## Abs(olute)
## Abs
### Instruction
### Instructions
Create a `isPositive` function that takes a number as
parameter and return true if the given number is

View File

@ -1,4 +1,4 @@
## Capitalize
## Capitalizer
### Instructions

View File

@ -1,6 +1,6 @@
## Chunk
## Chunky
### Instruction
### Instructions
Create the `chunk` function that returns an array of elements
split into groups the length of the given size.

View File

@ -1,6 +1,6 @@
## curry entries
## Curry Entries
### Instruction
### Instructions
This exercise consists in creating curry functions to apply in the objects
entries.

View File

@ -1,4 +1,4 @@
## Cut corners
## Cut Corners
### Instructions

19
subjects/date-is.en.md Normal file
View File

@ -0,0 +1,19 @@
## Date Is
### Instructions
Create the following functions:
- `isValid`, this function must return false if its an Invalid Date
- `isAfter`, this function will receive two dates and return true if the first date is bigger then the second date
- `isBefore`, this function will receive two dates and return true if the first date is lesser then the second date
- `isFuture`, will return true if the date given as parameter is higher then the present date
- `isPast`, will return true if the date given as parameter less then the present date
### Notions
- https://date-fns.org/v2.14.0/docs/isValid
- https://date-fns.org/v2.14.0/docs/isAfter
- https://date-fns.org/v2.14.0/docs/isBefore
- https://date-fns.org/v2.14.0/docs/isFuture
- https://date-fns.org/v2.14.0/docs/isPast

View File

@ -1,4 +1,4 @@
## Day of the Year
## Day Of The Year
### Instructions

View File

@ -1,11 +1,12 @@
## debouncing
## Debounce
## Instruction
### Instructions
Create two functions that will work like `_.debounce` from lodash
- `debounce`, this function doesn't need to take care of the options
- `opDebounce`, this function will take care of the `leading` options
### Notions
- https://lodash.com/docs/4.17.15#debounce

View File

@ -1,4 +1,4 @@
## deep-copy
## Deep Copy
### Instructions

25
subjects/filter.en.md Normal file
View File

@ -0,0 +1,25 @@
## Filter
### Instructions
- Create a `filter` function that takes an array as first argument, a function as second,
and that works like the method [].filter
- Create a `reject` function that takes an array as first argument, a function as second,
and that works like the reject function from lodash.
- Create a `partition` function that takes an array as first argument, a function as second,
and that works like the partition function from lodash.
### Notions
- https://devdocs.io/javascript/global_objects/array/filter
- https://lodash.com/docs/4.17.15#reject
- https://lodash.com/docs/4.17.15#partition
### Code provided
```js
Array.prototype.filter = undefined
```

View File

@ -1,4 +1,6 @@
### Instruction
## Find Expression
### Instructions
Create a function called `findExpression` that takes a number as parameter and returns a string

View File

@ -1,6 +1,6 @@
## flags
## Flagger
### Instruction
### Instructions
Create a function called `flags` that receives an object and outputs
the specific aliases and descriptions from the properties of that object.

17
subjects/for-each.en.md Normal file
View File

@ -0,0 +1,17 @@
## For Each
### Instructions
Create a `forEach` function that takes an array as first argument, a function as second,
and that works like the method .forEach
### Notions
- https://devdocs.io/javascript/global_objects/array/foreach
### Code provided
```js
Array.prototype.forEach = undefined
```

View File

@ -1,4 +1,4 @@
## fusion
## Fusion
### Instructions

28
subjects/get-json.en.md Normal file
View File

@ -0,0 +1,28 @@
## Get Json
### Instructions
In this exercise, we will focus on building complex async flows with promises.
Create a `getJSON` function that takes 2 parameters:
- `path`, that will be the url called by your function
- `params` *optional*, that will be the search parameters appended to your url
`getJSON` must construct a valid url with the `path` and stringified `params`
and call `fetch` with it.
If the response is not ok, your function must throw an error using
the response status message.
The response body must then be read and parsed from json.
The parsed object contains one of those 2 properties:
- `"data"` the actual data to return
- `"error"` the error message to throw
### Notions
- https://nan-academy.github.io/js-training/examples/promise.js
- https://devdocs.io/dom/fetch_api/using_fetch
- https://devdocs.io/dom/urlsearchparams
- https://devdocs.io/javascript/global_objects/json

View File

@ -0,0 +1,7 @@
## Get Some Time
### Instructions
Create a function `firstDayWeek` that receives a week of the year
(from 1 to 53) and a year (as a string), and returns the first day
of that week, in the format: 'dd-mm-yyyy'.

View File

@ -0,0 +1,42 @@
## Gougle Search
### Instructions
Create the `queryServers` function, that takes 2 arguments:
- `serverName` a string of the name of the server
- `q` a string of the query given by the user
You have to construct 2 urls, using `q` as a search parameter,
prepending a `'/'` and for the 2nd appending `'_backup'`.
Then return the first value of those 2 calls
```js
queryServers('pouet', 'hello+world')
// return the fastest of those 2 calls:
// -> getJSON('/pouet?q=hello+world')
// -> getJSON('/pouet_backup?q=hello+world')
```
Create a `gougleSearch` function that takes a single query argument.
It must call `queryServers` in concurrently on 3 servers:
`'web'`, `'image'` and `'video'`.
A timeout of 80milliseconds must be set for the whole operation.
You must return the value from each servers in an object
using a the server name as key.
### Notions
- https://devdocs.io/javascript/global_objects/promise/race
- https://devdocs.io/javascript/global_objects/promise/all
### Code provided
```js
// fake `getJSON` function
let getJSON = async (url) => url
```

View File

@ -1,6 +1,6 @@
## greedy-url
## Greedy Url
### Instruction
### Instructions
Write 3 functions :

View File

@ -1,6 +1,6 @@
## Has City
### Instruction
### Instructions
Create a function `hasCity` that given a country and an array of cities
of that country and it returns whether a city is part of that country or not.

View File

@ -0,0 +1,45 @@
## Interpolation
### Instructions
Create a function called `interpolation` that takes an object with 5 properties
`step`, `start`, `end`, `callback` and `duration`.
This function must calculate the interpolation points, (x, y),
from the `start` position to `end` position depending on the number of `steps`.
All the points must be calculated in the duration time.
For each interpolation point you must execute and pass as parameters to the callback the interpolation point ([x, y])
### Example
```
steps = 5
start = 0
end = 1
duration = 10
t
|
10 |___________________. <- execute callback([1.0, 10])
| |
| |
8 |_______________. |
| | |
| | |
6 |___________. | |
| | | |
| | | |
4 |_______. | | |
| | | | |
| | | | |
2 |___. | | | |
| | | | | |
|___|___|___|___|___|__d
0 0.2 0.4 0.6 0.8 1
```
### Notions
- https://javascript.info/settimeout-setinterval

View File

@ -1,6 +1,6 @@
## Ion Out
### Instruction
### Instructions
Make a function `ionOut` that receives a string and returns an array with every
word containing 'ion' following a t, without the 'ion'.

83
subjects/is-winner.en.md Normal file
View File

@ -0,0 +1,83 @@
## Is Winner
### Instructions
Create a function `isWinner` that, by making use of `winners` "API", should
return a resolved Promise with the string:
- `<country> + ' never was a winner'`, if the country passed
in `isWinner` has never won a the FIFA World Cup
- `<country> + ' is not what we are looking for because of the continent'`,
if the country passed in `isWinner` is not from the european
continent
- `<country> + ' is not what we are looking for because of the number of
times it was champion'`, if the country passed in `isWinner` was champion
less than 3 times
- `<country> + ' won the FIFA World Cup in ' + <year(s)> + 'winning by '
+ <results>`, otherwise.
If the country was champion in more than one year, the years should be
displayed like : '1000, 1004, 1008'. The same goes for the results
### Code provided
```js
const db = (() => {
//countries that won the FIFA World Cup
const countries = [
{ id: 1, name: 'Brazil', continent: 'South America' },
{ id: 2, name: 'Germany', continent: 'Europe' },
{ id: 3, name: 'Italy', continent: 'Europe' },
{ id: 4, name: 'Argentina', continent: 'South America' },
{ id: 5, name: 'France', continent: 'Europe' },
{ id: 6, name: 'Uruguay', continent: 'South America' },
{ id: 7, name: 'England', continent: 'Europe' },
{ id: 8, name: 'Spain', continent: 'Europe' },
]
//Information about the wins
const results = [
{ id: 1, countryId: 6, year: 1930, score: '4-2' },
{ id: 2, countryId: 3, year: 1934, score: '2-1' },
{ id: 3, countryId: 3, year: 1938, score: '4-2' },
{ id: 4, countryId: 6, year: 1950, score: '2-1' },
{ id: 5, countryId: 2, year: 1954, score: '3-2' },
{ id: 6, countryId: 1, year: 1958, score: '5-2' },
{ id: 7, countryId: 1, year: 1962, score: '3-1' },
{ id: 8, countryId: 7, year: 1966, score: '4-2' },
{ id: 9, countryId: 1, year: 1970, score: '4-1' },
{ id: 10, countryId: 2, year: 1974, score: '2-1' },
{ id: 11, countryId: 4, year: 1978, score: '3-1' },
{ id: 12, countryId: 3, year: 1982, score: '3-1' },
{ id: 13, countryId: 4, year: 1986, score: '3-2' },
{ id: 14, countryId: 2, year: 1990, score: '1-0' },
{ id: 15, countryId: 1, year: 1994, score: '3-2p' },
{ id: 16, countryId: 5, year: 1998, score: '3-0' },
{ id: 17, countryId: 1, year: 2002, score: '2-0' },
{ id: 18, countryId: 3, year: 2006, score: '5-3p' },
{ id: 19, countryId: 8, year: 2010, score: '1-0' },
{ id: 20, countryId: 2, year: 2014, score: '1-0' },
{ id: 21, countryId: 5, year: 2018, score: '4-2' },
]
return {
//returns the information of the country
getWinner: async (countryName) => {
const match = countries.find((country) => country.name === countryName)
if (!match) throw Error('Country Not Found')
return match
},
//returns the information of the wins of that country
getResults: async (countryId) => {
const match = results.filter((result) => result.countryId === countryId)
if (!match.length) throw Error('Results Not Found')
return match
},
addCountry: (country) => countries.push(country),
addResults: (result) => results.push(result),
}
})()
```

View File

@ -1,6 +1,6 @@
## It's a match
## Its A Match
### Instruction
### Instructions
Create 4 regular expression in variables:

View File

@ -0,0 +1,30 @@
## Keep Trying Or Giveup
### Instructions
Create a `retry` function, that takes 2 arguments
- a `count`, that tells how many retries must be done
- an async `callback`, that will be call every try
and it return a new function, passing arguments given to the
callback on every tries.
> for count of 3, the function will be called at most 4 times:
> the initial call + 3 retries.
Create a `timeout` function, that takes 2 arguments
- a `delay`, that tells how long to wait
- an async `callback`, that will be call
and it return a new function, passing arguments given to the callback
and either the async callback resolve before the delay is reached,
in that case we return the value from the callback,
or reject an error using the message `"timeout"`
### Notions
- https://nan-academy.github.io/js-training/examples/promise.js
- https://devdocs.io/dom/windoworworkerglobalscope/settimeout
- https://devdocs.io/javascript/global_objects/promise/race

View File

@ -1,6 +1,6 @@
## Letter Space Number
### Instruction
### Instructions
Make a function called `letterSpaceNumber` that receives a string and returns an
array with every instance of a letter, followed by a space, followed by a number

View File

@ -1,4 +1,4 @@
## manipulate-entries
## Manipulate Entries
### Instructions

View File

@ -1,4 +1,4 @@
## manipulate-keys
## Manipulate Keys
### Instructions

View File

@ -1,4 +1,4 @@
## manipulate-values
## Manipulate Values
### Instructions

23
subjects/mapper.en.md Normal file
View File

@ -0,0 +1,23 @@
## Mapper
### Instructions
- Create a `map` function that takes an array as first argument, a function as second,
and that works like the method .map
- Create a `flatMap` function that takes an array as first argument, a function as second,
and that works like the method .flatMap
### Notions
- https://devdocs.io/javascript/global_objects/array/map
- https://devdocs.io/javascript/global_objects/array/flatmap
### Code provided
```js
Array.prototype.map = undefined
Array.prototype.flatMap = undefined
Array.prototype.flat = undefined
```

32
subjects/match-cron.en.md Normal file
View File

@ -0,0 +1,32 @@
## Match Cron
### Instructions
Create a function called `matchCron` it takes a valid cron schedule string
and a valid date. \
It returns true if the date match the pattern
> You only have to implement numbers and `*`. \
> other complex patterns are not required.
Only valid pattern will be tested.
### Example
```js
matchCron('9 * * * *', new Date('2020-05-30 18:09:00')) // -> true
matchCron('9 * * * *', new Date('2020-05-30 19:09:00')) // -> true
matchCron('9 * * * *', new Date('2020-05-30 19:21:00')) // -> false
// | | | | |
// | | | | +- Day of the Week (range: 1-7, 1 standing for Monday)
// | | | +--- Month of the Year (range: 1-12)
// | | +----- Day of the Month (range: 1-31)
// | +------- Hour (range: 0-23)
// +--------- Minute (range: 0-59)
```
### Notions
- https://crontab.guru/
- https://devdocs.io/javascript/global_objects/date

View File

@ -1,6 +1,6 @@
## molecules-cells
## Molecules Cells
### Instruction
### Instructions
Write two functions:
- `RNA` that given a DNA strand it must return is complement RNA

View File

@ -1,4 +1,4 @@
## More or less
## More Or Less
### Instructions

View File

@ -1,6 +1,6 @@
## Mutability
### Instruction
### Instructions
Create a copy of the person object called clone1.
Create an other copy of the person object called clone2.
@ -11,7 +11,7 @@ Increase by one the property age of `person`
and set his contry to `'FR'`.
## Notions
### Notions
- https://nan-academy.github.io/js-training/examples/set.js
- https://nan-academy.github.io/js-training/examples/get.js

View File

@ -1,4 +1,4 @@
## NASA
## Nasa
### Instructions

View File

@ -1,4 +1,4 @@
## neuron
## Neuron
### Instructions

View File

@ -1,4 +1,4 @@
## Pick-Omit
## Pick Omit
### Instructions

View File

@ -1,4 +1,4 @@
## Primitive
## Primitives
### Instructions

View File

@ -1,6 +1,6 @@
## pronoun
## Pronoun
### Instruction
### Instructions
Create a function called `pronoun` that has a string as parameter. This function returns an object
that will have all the pronouns, present in the string, as keys. Each key will have a sub object with the

View File

@ -1,4 +1,4 @@
## pyramid
## Pyramid
### Instructions

21
subjects/race.en.md Normal file
View File

@ -0,0 +1,21 @@
## Race
### Instructions
Create a function `race` that works like `Promise.race`
Create a function `some` that takes an array of promises or values
and a number and return the first resolved values up to the number given.
> Empty array or a count of 0 return a promise resolving to `undefined`
### Notions
- https://nan-academy.github.io/js-training/examples/promise.js
- https://devdocs.io/javascript/global_objects/promise/race
### Code provided
```js
Promise.race = undefined
```

View File

@ -0,0 +1,16 @@
## Rebecca Black
### Instructions
Create the following functions:
- `isFriday` returns true if the date is a friday
- `isWeekend` returns true if the date is a day of the weekend
- `isLeapYear` returns true if the year is a leap year
- `isLastDayOfMonth` returns true if the date is the last day of the month
### Notions
- https://date-fns.org/v2.14.0/docs/isWeekend
- https://date-fns.org/v2.14.0/docs/isAfter
- https://date-fns.org/v2.14.0/docs/isLastDayOfMonth

View File

@ -1,4 +1,4 @@
## replica
## Replica
### Instructions

View File

@ -1,4 +1,4 @@
## Reverse
## Reverser
### Instructions

View File

@ -1,6 +1,6 @@
## same-amount
## Same Amount
### Instruction
### Instructions
Create a `sameAmount` function that takes three parameter,
a data string and 2 regexes.

View File

@ -1,4 +1,4 @@
## series
## Series
### Instructions

View File

@ -1,4 +1,4 @@
## Curry Easy
## Sweet Curry
### Instructions

View File

@ -1,4 +1,4 @@
## throttling
## Throttle
### Instructions

View File

@ -1,4 +1,4 @@
## triangle
## Triangle
### Instructions

View File

@ -1,12 +1,12 @@
## Title
## Unbreakable
### Instruction
### Instructions
Implement 2 functions:
- `split` that works like the string method `.split` but take the string as
it's first argument.
- `join` that works like the string method `.split` but take the array as
- `join` that works like the string method `.join` but take the array as
it's first argument.

View File

@ -0,0 +1,46 @@
## Using Filter
### Instructions
- Create a function `filterShortStateName` that takes an array of
strings and that returns the ones with less than 7 characters.
> Example: `'Iowa'` only contains 4 characters
- Create a function `filterStartVowel` that takes an array of strings
and that returns only the ones that start with a vowel (a,e,i,o,u).
> Example: `'Alabama'` starts with a vowel
- Create a function `filter5Vowels` that takes an array of strings
and that returns only the ones which contain at least 5
vowels (a,e,i,o,u).
> Example: `'California'` contains at least 5 vowels
- Create a function `filter1DistinctVowel` that takes an array of
strings and that returns only the ones which vowels are of only
one distinct one (a,e,i,o,u).
> Example: `'Alabama'` only contains 1 distinct vowels `'a'`.
- Create a function `multiFilter` that takes an array of
objects and that returns only the ones which:
- the key `capital` contains at least 8 characters.
- the key `name` does not start with a vowel
- the key `tag` has at least one vowel.
- the key `region` is not `'South'`
Example of an array of objects matching the criterias:
[
{ tag: 'CA', name: 'California', capital: 'Sacramento', region: 'West' },
{ tag: 'PA', name: 'Pennsylvania', capital: 'Harrisburg', region: 'Northeast' }
]
### Notions
- https://devdocs.io/javascript/global_objects/array/filter

102
subjects/using-map.en.md Normal file
View File

@ -0,0 +1,102 @@
## Using Map
### Instructions
-Create a function named 'citiesOnly' which takes an array of objects
and which return an array of strings from the key `city`.
Example:
```js
[
{
city: 'Los Angeles',
temperature: ' 101 °F ',
},
{
city: 'San Francisco',
temperature: ' 84 ° F ',
},
]
```
returns
```js
['Los Angeles', 'San Francisco']
```
-Create a function named 'upperCasingStates' which takes an array of strings
and which Upper Case each words of a string.
The function returns then an array of strings.
Example:
```js
['alabama', 'new jersey']
```
returns
```js
['Alabama', 'New Jersey']
```
-Create a function named 'fahrenheitToCelsius' which takes an array
of fahrenheit temperatures which converts them to Celsius.
Round down the result.
The function then returns the result as an array of strings like below:
example:
```js
['68°F', '59°F', '25°F']
```
returns
```js
['20°C', '15°C', '-4°C']
```
-Create a function named 'trimTemp' which takes an array of objects
and which removes the spaces from the string in the key `temperature`.
The function then returns an array of objects with the modification.
Example:
```js
[
{ city: 'Los Angeles', temperature: ' 101 °F '},
{ city: 'San Francisco', temperature: ' 84 ° F '},
]
```
returns
```js
[
{ city: 'Los Angeles', temperature: '101°F' },
{ city: 'San Francisco', temperature: '84°F' },
]
```
-Create a 'tempForecasts' function which will take an array of objects, and which will
return an array of strings formatted as below:
```js
[
{
city: 'Pasadena',
temperature: ' 101 °F',
state: 'california',
region: 'West',
}
]
```
returns
```js
['38°Celsius in Pasadena, California']
```
### Notions
- https://devdocs.io/javascript/global_objects/array/map

View File

@ -1,6 +1,6 @@
## Using Reduce
### Instruction
### Instructions
Create three functions :
- `adder` that receives an array and adds its elements.

View File

@ -1,6 +1,6 @@
## valid-ip
## Valid Ip
### Instruction
### Instructions
Write a function called `findIP` that search for a valid IP, with or without a port, in a string passed as parameter

View File

@ -1,6 +1,6 @@
## Vowel Dots
### Instruction
### Instructions
Create a function called vowelDots that receives a string and adds a `.` after
every vowel ('y' is not considered a vowel here) using a regex called `vowels`.

View File

@ -1,4 +1,4 @@
## 何 !?
## 何
### Instructions