From 52adf5c8fd94b93c5bc01450379e4d745c38e6a6 Mon Sep 17 00:00:00 2001 From: Clement Denis Date: Sun, 31 May 2020 17:21:17 +0200 Subject: [PATCH] adding more javascript subjects (+fixes) --- js/tests/date-is_test.js | 56 +++ js/tests/filter_test.js | 485 +++++++++++++++++++++++++ js/tests/for-each_test.js | 33 ++ js/tests/get-json_test.js | 70 ++++ js/tests/get-some-time_test.js | 14 + js/tests/gougle-search_test.js | 60 +++ js/tests/interpolation_test.js | 85 +++++ js/tests/is-winner_test.js | 120 ++++++ js/tests/keep-trying-or-giveup_test.js | 34 ++ js/tests/mapper_test.js | 142 ++++++++ js/tests/match-cron_test.js | 23 ++ js/tests/nested_test.js | 4 +- js/tests/race_test.js | 71 ++++ js/tests/rebecca-black_test.js | 33 ++ js/tests/using-filter_test.js | 293 +++++++++++++++ js/tests/using-map_test.js | 197 ++++++++++ subjects/abs.en.md | 4 +- subjects/capitalizer.en.md | 2 +- subjects/chunky.en.md | 4 +- subjects/curry-entries.en.md | 4 +- subjects/cut-corners.en.md | 2 +- subjects/date-is.en.md | 19 + subjects/day-of-the-year.en.md | 2 +- subjects/debounce.en.md | 5 +- subjects/deep-copy.en.md | 2 +- subjects/filter.en.md | 25 ++ subjects/find-expression.en.md | 4 +- subjects/flagger.en.md | 4 +- subjects/for-each.en.md | 17 + subjects/fusion.en.md | 2 +- subjects/get-json.en.md | 28 ++ subjects/get-some-time.en.md | 7 + subjects/gougle-search.en.md | 42 +++ subjects/greedy-url.en.md | 4 +- subjects/has-city.en.md | 2 +- subjects/interpolation.en.md | 45 +++ subjects/ion-out.en.md | 2 +- subjects/is-winner.en.md | 83 +++++ subjects/its-a-match.en.md | 4 +- subjects/keep-trying-or-giveup.en.md | 30 ++ subjects/letter-space-number.en.md | 2 +- subjects/manipulate-entries.en.md | 2 +- subjects/manipulate-keys.en.md | 2 +- subjects/manipulate-values.en.md | 2 +- subjects/mapper.en.md | 23 ++ subjects/match-cron.en.md | 32 ++ subjects/molecules-cells.en.md | 4 +- subjects/more-or-less.en.md | 2 +- subjects/mutability.en.md | 4 +- subjects/nasa.en.md | 2 +- subjects/neuron.en.md | 2 +- subjects/pick-omit.en.md | 2 +- subjects/primitives.en.md | 2 +- subjects/pronoun.en.md | 4 +- subjects/pyramid.en.md | 2 +- subjects/race.en.md | 21 ++ subjects/rebecca-black.en.md | 16 + subjects/replica.en.md | 2 +- subjects/reverser.en.md | 2 +- subjects/same-amount.en.md | 4 +- subjects/series.en.md | 2 +- subjects/sweet-curry.en.md | 2 +- subjects/throttle.en.md | 2 +- subjects/triangle.en.md | 2 +- subjects/unbreakable.en.md | 6 +- subjects/using-filter.en.md | 46 +++ subjects/using-map.en.md | 102 ++++++ subjects/using-reduce.en.md | 2 +- subjects/valid-ip.en.md | 4 +- subjects/vowel-dots.en.md | 2 +- subjects/何.en.md | 2 +- 71 files changed, 2311 insertions(+), 56 deletions(-) create mode 100644 js/tests/date-is_test.js create mode 100644 js/tests/filter_test.js create mode 100644 js/tests/for-each_test.js create mode 100644 js/tests/get-json_test.js create mode 100644 js/tests/get-some-time_test.js create mode 100644 js/tests/gougle-search_test.js create mode 100644 js/tests/interpolation_test.js create mode 100644 js/tests/is-winner_test.js create mode 100644 js/tests/keep-trying-or-giveup_test.js create mode 100644 js/tests/mapper_test.js create mode 100644 js/tests/match-cron_test.js create mode 100644 js/tests/race_test.js create mode 100644 js/tests/rebecca-black_test.js create mode 100644 js/tests/using-filter_test.js create mode 100644 js/tests/using-map_test.js create mode 100644 subjects/date-is.en.md create mode 100644 subjects/filter.en.md create mode 100644 subjects/for-each.en.md create mode 100644 subjects/get-json.en.md create mode 100644 subjects/get-some-time.en.md create mode 100644 subjects/gougle-search.en.md create mode 100644 subjects/interpolation.en.md create mode 100644 subjects/is-winner.en.md create mode 100644 subjects/keep-trying-or-giveup.en.md create mode 100644 subjects/mapper.en.md create mode 100644 subjects/match-cron.en.md create mode 100644 subjects/race.en.md create mode 100644 subjects/rebecca-black.en.md create mode 100644 subjects/using-filter.en.md create mode 100644 subjects/using-map.en.md diff --git a/js/tests/date-is_test.js b/js/tests/date-is_test.js new file mode 100644 index 00000000..4dd7e843 --- /dev/null +++ b/js/tests/date-is_test.js @@ -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) diff --git a/js/tests/filter_test.js b/js/tests/filter_test.js new file mode 100644 index 00000000..a98708af --- /dev/null +++ b/js/tests/filter_test.js @@ -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) diff --git a/js/tests/for-each_test.js b/js/tests/for-each_test.js new file mode 100644 index 00000000..ab7dcaa3 --- /dev/null +++ b/js/tests/for-each_test.js @@ -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) diff --git a/js/tests/get-json_test.js b/js/tests/get-json_test.js new file mode 100644 index 00000000..805f8f1c --- /dev/null +++ b/js/tests/get-json_test.js @@ -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 diff --git a/js/tests/get-some-time_test.js b/js/tests/get-some-time_test.js new file mode 100644 index 00000000..324f2ff7 --- /dev/null +++ b/js/tests/get-some-time_test.js @@ -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) diff --git a/js/tests/gougle-search_test.js b/js/tests/gougle-search_test.js new file mode 100644 index 00000000..856f2d6e --- /dev/null +++ b/js/tests/gougle-search_test.js @@ -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), + )), +}) diff --git a/js/tests/interpolation_test.js b/js/tests/interpolation_test.js new file mode 100644 index 00000000..cc49a643 --- /dev/null +++ b/js/tests/interpolation_test.js @@ -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) diff --git a/js/tests/is-winner_test.js b/js/tests/is-winner_test.js new file mode 100644 index 00000000..9f729035 --- /dev/null +++ b/js/tests/is-winner_test.js @@ -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 } +} diff --git a/js/tests/keep-trying-or-giveup_test.js b/js/tests/keep-trying-or-giveup_test.js new file mode 100644 index 00000000..dfb64f2d --- /dev/null +++ b/js/tests/keep-trying-or-giveup_test.js @@ -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)), +}) diff --git a/js/tests/mapper_test.js b/js/tests/mapper_test.js new file mode 100644 index 00000000..93f3ea74 --- /dev/null +++ b/js/tests/mapper_test.js @@ -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 } +} diff --git a/js/tests/match-cron_test.js b/js/tests/match-cron_test.js new file mode 100644 index 00000000..1ee5f8e9 --- /dev/null +++ b/js/tests/match-cron_test.js @@ -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) diff --git a/js/tests/nested_test.js b/js/tests/nested_test.js index 00626240..6bac5297 100644 --- a/js/tests/nested_test.js +++ b/js/tests/nested_test.js @@ -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) diff --git a/js/tests/race_test.js b/js/tests/race_test.js new file mode 100644 index 00000000..d9e4c6d6 --- /dev/null +++ b/js/tests/race_test.js @@ -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 diff --git a/js/tests/rebecca-black_test.js b/js/tests/rebecca-black_test.js new file mode 100644 index 00000000..8abca667 --- /dev/null +++ b/js/tests/rebecca-black_test.js @@ -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) diff --git a/js/tests/using-filter_test.js b/js/tests/using-filter_test.js new file mode 100644 index 00000000..df5d4f92 --- /dev/null +++ b/js/tests/using-filter_test.js @@ -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 } +} diff --git a/js/tests/using-map_test.js b/js/tests/using-map_test.js new file mode 100644 index 00000000..d204c62a --- /dev/null +++ b/js/tests/using-map_test.js @@ -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) diff --git a/subjects/abs.en.md b/subjects/abs.en.md index deb88af4..890153b8 100644 --- a/subjects/abs.en.md +++ b/subjects/abs.en.md @@ -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 diff --git a/subjects/capitalizer.en.md b/subjects/capitalizer.en.md index 60af74fb..dc191130 100644 --- a/subjects/capitalizer.en.md +++ b/subjects/capitalizer.en.md @@ -1,4 +1,4 @@ -## Capitalize +## Capitalizer ### Instructions diff --git a/subjects/chunky.en.md b/subjects/chunky.en.md index 3e8c442c..d6579f92 100644 --- a/subjects/chunky.en.md +++ b/subjects/chunky.en.md @@ -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. diff --git a/subjects/curry-entries.en.md b/subjects/curry-entries.en.md index 55489a1d..bad7fe95 100644 --- a/subjects/curry-entries.en.md +++ b/subjects/curry-entries.en.md @@ -1,6 +1,6 @@ -## curry entries +## Curry Entries -### Instruction +### Instructions This exercise consists in creating curry functions to apply in the objects entries. diff --git a/subjects/cut-corners.en.md b/subjects/cut-corners.en.md index 1086f59a..9f67642b 100644 --- a/subjects/cut-corners.en.md +++ b/subjects/cut-corners.en.md @@ -1,4 +1,4 @@ -## Cut corners +## Cut Corners ### Instructions diff --git a/subjects/date-is.en.md b/subjects/date-is.en.md new file mode 100644 index 00000000..248ab9f7 --- /dev/null +++ b/subjects/date-is.en.md @@ -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 \ No newline at end of file diff --git a/subjects/day-of-the-year.en.md b/subjects/day-of-the-year.en.md index 785a5554..4890512f 100644 --- a/subjects/day-of-the-year.en.md +++ b/subjects/day-of-the-year.en.md @@ -1,4 +1,4 @@ -## Day of the Year +## Day Of The Year ### Instructions diff --git a/subjects/debounce.en.md b/subjects/debounce.en.md index dfa3ce21..3e217a3d 100644 --- a/subjects/debounce.en.md +++ b/subjects/debounce.en.md @@ -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 \ No newline at end of file diff --git a/subjects/deep-copy.en.md b/subjects/deep-copy.en.md index 18f588d9..be1938d7 100644 --- a/subjects/deep-copy.en.md +++ b/subjects/deep-copy.en.md @@ -1,4 +1,4 @@ -## deep-copy +## Deep Copy ### Instructions diff --git a/subjects/filter.en.md b/subjects/filter.en.md new file mode 100644 index 00000000..12e439d5 --- /dev/null +++ b/subjects/filter.en.md @@ -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 +``` diff --git a/subjects/find-expression.en.md b/subjects/find-expression.en.md index 5f6c1c0c..cdb697df 100644 --- a/subjects/find-expression.en.md +++ b/subjects/find-expression.en.md @@ -1,4 +1,6 @@ -### Instruction +## Find Expression + +### Instructions Create a function called `findExpression` that takes a number as parameter and returns a string diff --git a/subjects/flagger.en.md b/subjects/flagger.en.md index aaa82a60..9e2c5438 100644 --- a/subjects/flagger.en.md +++ b/subjects/flagger.en.md @@ -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. diff --git a/subjects/for-each.en.md b/subjects/for-each.en.md new file mode 100644 index 00000000..d897da7f --- /dev/null +++ b/subjects/for-each.en.md @@ -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 +``` diff --git a/subjects/fusion.en.md b/subjects/fusion.en.md index 83093ae2..7ebb1672 100644 --- a/subjects/fusion.en.md +++ b/subjects/fusion.en.md @@ -1,4 +1,4 @@ -## fusion +## Fusion ### Instructions diff --git a/subjects/get-json.en.md b/subjects/get-json.en.md new file mode 100644 index 00000000..d64b7f56 --- /dev/null +++ b/subjects/get-json.en.md @@ -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 \ No newline at end of file diff --git a/subjects/get-some-time.en.md b/subjects/get-some-time.en.md new file mode 100644 index 00000000..e6eb286c --- /dev/null +++ b/subjects/get-some-time.en.md @@ -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'. \ No newline at end of file diff --git a/subjects/gougle-search.en.md b/subjects/gougle-search.en.md new file mode 100644 index 00000000..5ffd6505 --- /dev/null +++ b/subjects/gougle-search.en.md @@ -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 +``` diff --git a/subjects/greedy-url.en.md b/subjects/greedy-url.en.md index 55061535..bd21d700 100644 --- a/subjects/greedy-url.en.md +++ b/subjects/greedy-url.en.md @@ -1,6 +1,6 @@ -## greedy-url +## Greedy Url -### Instruction +### Instructions Write 3 functions : diff --git a/subjects/has-city.en.md b/subjects/has-city.en.md index 35424fbb..f579604d 100644 --- a/subjects/has-city.en.md +++ b/subjects/has-city.en.md @@ -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. diff --git a/subjects/interpolation.en.md b/subjects/interpolation.en.md new file mode 100644 index 00000000..40d7fe5f --- /dev/null +++ b/subjects/interpolation.en.md @@ -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 \ No newline at end of file diff --git a/subjects/ion-out.en.md b/subjects/ion-out.en.md index d57388f0..df6ff4f1 100644 --- a/subjects/ion-out.en.md +++ b/subjects/ion-out.en.md @@ -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'. diff --git a/subjects/is-winner.en.md b/subjects/is-winner.en.md new file mode 100644 index 00000000..b230e8d2 --- /dev/null +++ b/subjects/is-winner.en.md @@ -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: + +- ` + ' never was a winner'`, if the country passed +in `isWinner` has never won a the FIFA World Cup + +- ` + ' is not what we are looking for because of the continent'`, + if the country passed in `isWinner` is not from the european +continent + +- ` + ' 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 + +- ` + ' won the FIFA World Cup in ' + + 'winning by ' ++ `, 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), + } +})() +``` diff --git a/subjects/its-a-match.en.md b/subjects/its-a-match.en.md index d33874f6..4de2e0b5 100644 --- a/subjects/its-a-match.en.md +++ b/subjects/its-a-match.en.md @@ -1,6 +1,6 @@ -## It's a match +## Its A Match -### Instruction +### Instructions Create 4 regular expression in variables: diff --git a/subjects/keep-trying-or-giveup.en.md b/subjects/keep-trying-or-giveup.en.md new file mode 100644 index 00000000..35cc7f4c --- /dev/null +++ b/subjects/keep-trying-or-giveup.en.md @@ -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 \ No newline at end of file diff --git a/subjects/letter-space-number.en.md b/subjects/letter-space-number.en.md index b787533d..8f9d48de 100644 --- a/subjects/letter-space-number.en.md +++ b/subjects/letter-space-number.en.md @@ -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 diff --git a/subjects/manipulate-entries.en.md b/subjects/manipulate-entries.en.md index 609d6a53..4af4692c 100644 --- a/subjects/manipulate-entries.en.md +++ b/subjects/manipulate-entries.en.md @@ -1,4 +1,4 @@ -## manipulate-entries +## Manipulate Entries ### Instructions diff --git a/subjects/manipulate-keys.en.md b/subjects/manipulate-keys.en.md index 45966108..ba4e126c 100644 --- a/subjects/manipulate-keys.en.md +++ b/subjects/manipulate-keys.en.md @@ -1,4 +1,4 @@ -## manipulate-keys +## Manipulate Keys ### Instructions diff --git a/subjects/manipulate-values.en.md b/subjects/manipulate-values.en.md index 1820418a..3a6f79d5 100644 --- a/subjects/manipulate-values.en.md +++ b/subjects/manipulate-values.en.md @@ -1,4 +1,4 @@ -## manipulate-values +## Manipulate Values ### Instructions diff --git a/subjects/mapper.en.md b/subjects/mapper.en.md new file mode 100644 index 00000000..fc0cf61a --- /dev/null +++ b/subjects/mapper.en.md @@ -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 +``` diff --git a/subjects/match-cron.en.md b/subjects/match-cron.en.md new file mode 100644 index 00000000..6929ae14 --- /dev/null +++ b/subjects/match-cron.en.md @@ -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 \ No newline at end of file diff --git a/subjects/molecules-cells.en.md b/subjects/molecules-cells.en.md index 0149f9e0..78b33e33 100644 --- a/subjects/molecules-cells.en.md +++ b/subjects/molecules-cells.en.md @@ -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 diff --git a/subjects/more-or-less.en.md b/subjects/more-or-less.en.md index 198fff3f..38bf873e 100644 --- a/subjects/more-or-less.en.md +++ b/subjects/more-or-less.en.md @@ -1,4 +1,4 @@ -## More or less +## More Or Less ### Instructions diff --git a/subjects/mutability.en.md b/subjects/mutability.en.md index 68b9fc88..ac6f95e9 100644 --- a/subjects/mutability.en.md +++ b/subjects/mutability.en.md @@ -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 diff --git a/subjects/nasa.en.md b/subjects/nasa.en.md index d1a2b3e8..9fbb0b65 100644 --- a/subjects/nasa.en.md +++ b/subjects/nasa.en.md @@ -1,4 +1,4 @@ -## NASA +## Nasa ### Instructions diff --git a/subjects/neuron.en.md b/subjects/neuron.en.md index 1b2a47a3..83897f8e 100644 --- a/subjects/neuron.en.md +++ b/subjects/neuron.en.md @@ -1,4 +1,4 @@ -## neuron +## Neuron ### Instructions diff --git a/subjects/pick-omit.en.md b/subjects/pick-omit.en.md index cd3e5f43..3ee4a4a1 100644 --- a/subjects/pick-omit.en.md +++ b/subjects/pick-omit.en.md @@ -1,4 +1,4 @@ -## Pick-Omit +## Pick Omit ### Instructions diff --git a/subjects/primitives.en.md b/subjects/primitives.en.md index f5ed9abb..9f24a2e3 100644 --- a/subjects/primitives.en.md +++ b/subjects/primitives.en.md @@ -1,4 +1,4 @@ -## Primitive +## Primitives ### Instructions diff --git a/subjects/pronoun.en.md b/subjects/pronoun.en.md index d5f6aa2c..7aba9a46 100644 --- a/subjects/pronoun.en.md +++ b/subjects/pronoun.en.md @@ -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 diff --git a/subjects/pyramid.en.md b/subjects/pyramid.en.md index 01bbf318..5cbff573 100644 --- a/subjects/pyramid.en.md +++ b/subjects/pyramid.en.md @@ -1,4 +1,4 @@ -## pyramid +## Pyramid ### Instructions diff --git a/subjects/race.en.md b/subjects/race.en.md new file mode 100644 index 00000000..9150c7dc --- /dev/null +++ b/subjects/race.en.md @@ -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 +``` diff --git a/subjects/rebecca-black.en.md b/subjects/rebecca-black.en.md new file mode 100644 index 00000000..26158ccc --- /dev/null +++ b/subjects/rebecca-black.en.md @@ -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 \ No newline at end of file diff --git a/subjects/replica.en.md b/subjects/replica.en.md index edd33d97..afda5449 100644 --- a/subjects/replica.en.md +++ b/subjects/replica.en.md @@ -1,4 +1,4 @@ -## replica +## Replica ### Instructions diff --git a/subjects/reverser.en.md b/subjects/reverser.en.md index ec0a55e5..77d48f2f 100644 --- a/subjects/reverser.en.md +++ b/subjects/reverser.en.md @@ -1,4 +1,4 @@ -## Reverse +## Reverser ### Instructions diff --git a/subjects/same-amount.en.md b/subjects/same-amount.en.md index e762f7fc..12f14690 100644 --- a/subjects/same-amount.en.md +++ b/subjects/same-amount.en.md @@ -1,6 +1,6 @@ -## same-amount +## Same Amount -### Instruction +### Instructions Create a `sameAmount` function that takes three parameter, a data string and 2 regexes. diff --git a/subjects/series.en.md b/subjects/series.en.md index 64cdaad3..b5c2746d 100644 --- a/subjects/series.en.md +++ b/subjects/series.en.md @@ -1,4 +1,4 @@ -## series +## Series ### Instructions diff --git a/subjects/sweet-curry.en.md b/subjects/sweet-curry.en.md index 489b7964..00563474 100644 --- a/subjects/sweet-curry.en.md +++ b/subjects/sweet-curry.en.md @@ -1,4 +1,4 @@ -## Curry Easy +## Sweet Curry ### Instructions diff --git a/subjects/throttle.en.md b/subjects/throttle.en.md index ca205028..f0daa892 100644 --- a/subjects/throttle.en.md +++ b/subjects/throttle.en.md @@ -1,4 +1,4 @@ -## throttling +## Throttle ### Instructions diff --git a/subjects/triangle.en.md b/subjects/triangle.en.md index 2c22f181..aabc3686 100644 --- a/subjects/triangle.en.md +++ b/subjects/triangle.en.md @@ -1,4 +1,4 @@ -## triangle +## Triangle ### Instructions diff --git a/subjects/unbreakable.en.md b/subjects/unbreakable.en.md index cb722335..f25a4702 100644 --- a/subjects/unbreakable.en.md +++ b/subjects/unbreakable.en.md @@ -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. diff --git a/subjects/using-filter.en.md b/subjects/using-filter.en.md new file mode 100644 index 00000000..bf9b3a14 --- /dev/null +++ b/subjects/using-filter.en.md @@ -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 \ No newline at end of file diff --git a/subjects/using-map.en.md b/subjects/using-map.en.md new file mode 100644 index 00000000..65b84eae --- /dev/null +++ b/subjects/using-map.en.md @@ -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 \ No newline at end of file diff --git a/subjects/using-reduce.en.md b/subjects/using-reduce.en.md index b0078809..b6e39f19 100644 --- a/subjects/using-reduce.en.md +++ b/subjects/using-reduce.en.md @@ -1,6 +1,6 @@ ## Using Reduce -### Instruction +### Instructions Create three functions : - `adder` that receives an array and adds its elements. diff --git a/subjects/valid-ip.en.md b/subjects/valid-ip.en.md index aeb17dde..450f8529 100644 --- a/subjects/valid-ip.en.md +++ b/subjects/valid-ip.en.md @@ -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 diff --git a/subjects/vowel-dots.en.md b/subjects/vowel-dots.en.md index 6ed96801..eacad58b 100644 --- a/subjects/vowel-dots.en.md +++ b/subjects/vowel-dots.en.md @@ -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`. diff --git a/subjects/何.en.md b/subjects/何.en.md index c9f1236b..fc7583b2 100644 --- a/subjects/何.en.md +++ b/subjects/何.en.md @@ -1,4 +1,4 @@ -## 何 !? +## 何 ### Instructions