diff --git a/index.js b/index.js index 28090f12..ce11f6d4 100644 --- a/index.js +++ b/index.js @@ -1,3 +1,4 @@ + /** * [Exercise 1] trimProperties copies an object trimming its properties * @param {object} obj - an object with properties that are strings @@ -7,7 +8,11 @@ * trimProperties({ name: ' jane ' }) // returns a new object { name: 'jane' } */ function trimProperties(obj) { - // ✨ implement + let trimmedObj = {}; + for (const prop in obj) { + trimmedObj = {...trimmedObj, [prop]: obj[prop].trim()}; + } + return trimmedObj; } /** @@ -19,7 +24,10 @@ function trimProperties(obj) { * trimPropertiesMutation({ name: ' jane ' }) // returns the object mutated in place { name: 'jane' } */ function trimPropertiesMutation(obj) { - // ✨ implement + for (const prop in obj) { + obj[prop] = obj[prop].trim(); + } + return obj; } /** @@ -31,7 +39,11 @@ function trimPropertiesMutation(obj) { * findLargestInteger([{ integer: 1 }, { integer: 3 }, { integer: 2 }]) // returns 3 */ function findLargestInteger(integers) { - // ✨ implement + const intArr = []; + integers.forEach(obj => { + intArr.push(obj.integer); + }); + return Math.max(...intArr); } class Counter { @@ -40,7 +52,8 @@ class Counter { * @param {number} initialNumber - the initial state of the count */ constructor(initialNumber) { - // ✨ initialize whatever properties are needed + this.initialNumber = initialNumber; + this.countDownCount = 0; } /** @@ -56,7 +69,16 @@ class Counter { * counter.countDown() // returns 0 */ countDown() { - // ✨ implement + this.countDownCount++; + if (this.countDownCount === 1) { + return this.initialNumber; + } else { + if (this.initialNumber - (this.countDownCount -1) <= 0) { + return 0; + } else { + return this.initialNumber - (this.countDownCount - 1); + } + } } } @@ -65,7 +87,8 @@ class Seasons { * [Exercise 5A] Seasons creates a seasons object */ constructor() { - // ✨ initialize whatever properties are needed + this.seasons = ["summer", "fall", "winter", "spring"]; + this.count = -1; } /** @@ -81,7 +104,8 @@ class Seasons { * seasons.next() // returns "summer" */ next() { - // ✨ implement + this.count++; + return this.seasons[this.count % 4]; } } @@ -93,9 +117,11 @@ class Car { * @param {number} mpg - miles the car can drive per gallon of gas */ constructor(name, tankSize, mpg) { - this.odometer = 0 // car initilizes with zero miles - this.tank = tankSize // car initiazes full of gas - // ✨ initialize whatever other properties are needed + this.car = name; + this.odometer = 0; // car initilizes with zero miles + this.tank = tankSize; // car initiazes full of gas + this.fuel = tankSize; + this.mpg = mpg; } /** @@ -112,7 +138,13 @@ class Car { * focus.drive(200) // returns 600 (ran out of gas after 100 miles) */ drive(distance) { - // ✨ implement + let fuelUsed = distance / this.mpg; + if (this.fuel - fuelUsed <= 0){ + fuelUsed = fuelUsed + (this.fuel - fuelUsed); + } + this.fuel -= fuelUsed; + this.odometer += Math.round(fuelUsed * this.mpg); + return this.odometer; } /** @@ -127,7 +159,11 @@ class Car { * focus.refuel(99) // returns 600 (tank only holds 20) */ refuel(gallons) { - // ✨ implement + if (gallons >= this.tank) { + this.fuel = this.tank; + } else { + this.fuel = gallons; + } } } @@ -151,7 +187,15 @@ class Car { * }) */ function isEvenNumberAsync(number) { - // ✨ implement + if (!number || typeof number !== "number") { + return Promise.reject('number must be a number'); + } else { + if (number % 2 === 0) { + return Promise.resolve(true); + } else { + return Promise.resolve(false); + } + } } module.exports = { @@ -162,4 +206,4 @@ module.exports = { Counter, Seasons, Car, -} +}; \ No newline at end of file diff --git a/index.test.js b/index.test.js index b9d30ded..3a65623b 100644 --- a/index.test.js +++ b/index.test.js @@ -1,62 +1,183 @@ -const utils = require('./index') +const utils = require('./index'); describe('[Exercise 1] trimProperties', () => { test('[1] returns an object with the properties trimmed', () => { // EXAMPLE - const input = { foo: ' foo ', bar: 'bar ', baz: ' baz' } - const expected = { foo: 'foo', bar: 'bar', baz: 'baz' } - const actual = utils.trimProperties(input) - expect(actual).toEqual(expected) - }) - test.todo('[2] returns a copy, leaving the original object intact') -}) + const input = { foo: ' foo ', bar: 'bar ', baz: ' baz' }; + const expected = { foo: 'foo', bar: 'bar', baz: 'baz' }; + const actual = utils.trimProperties(input); + expect(actual).toEqual(expected); + }); + test('[2] returns a copy, leaving the original object intact' , () => { + const input = { foo: 'foo ', bar: ' bar ', baz: ' baz' }; + utils.trimProperties(input); + const output = { foo: 'foo', bar: 'bar', baz: 'baz' }; + expect(input).not.toEqual(output); + }); +}); describe('[Exercise 2] trimPropertiesMutation', () => { - test.todo('[3] returns an object with the properties trimmed') - test.todo('[4] the object returned is the exact same one we passed in') -}) + test('[3] returns an object with the properties trimmed', () => { + const input = { foo: ' foo ', bar: 'bar ', baz: ' baz' }; + const expected = { foo: 'foo', bar: 'bar', baz: 'baz' }; + const actual = utils.trimPropertiesMutation(input); + expect(actual).toEqual(expected); + }); + test('[4] the object returned is the exact same one we passed in', () => { + const input = { foo: ' foo ', bar: 'bar ', baz: ' baz' }; + utils.trimPropertiesMutation(input); + const output = { foo: 'foo', bar: 'bar', baz: 'baz' }; + expect(input).toEqual(output); + }); +}); describe('[Exercise 3] findLargestInteger', () => { - test.todo('[5] returns the largest number in an array of objects { integer: 2 }') -}) + test('[5] returns the largest number in an array of objects { integer: 2 }', () => { + const integers = [ + {integer: 1}, + {integer: 2}, + {integer: 5} + ]; + const largest = utils.findLargestInteger(integers); + expect(largest).toBe(5); + }); + + test('[5a] returns the largest number in an array of objects { integer: 2 }', () => { + const integers = [ + {integer: 4}, + {integer: 2}, + {integer: 5}, + {integer: 5}, + {integer: 17}, + {integer: 17}, + ]; + const largest = utils.findLargestInteger(integers); + expect(largest).toBe(17); + }); +}); describe('[Exercise 4] Counter', () => { - let counter + let counter; beforeEach(() => { - counter = new utils.Counter(3) // each test must start with a fresh couter - }) - test.todo('[6] the FIRST CALL of counter.countDown returns the initial count') - test.todo('[7] the SECOND CALL of counter.countDown returns the initial count minus one') - test.todo('[8] the count eventually reaches zero but does not go below zero') -}) + counter = new utils.Counter(3); // each test must start with a fresh couter + }); + test('[6] the FIRST CALL of counter.countDown returns the initial count', () => { + const count = counter.countDown(); + expect(count).toBe(3); + }); + test('[7] the SECOND CALL of counter.countDown returns the initial count minus one', () => { + counter.countDown(); + const count = counter.countDown(); + expect(count).toBe(2); + }); + test('[8] the count eventually reaches zero but does not go below zero', () => { + counter.countDown(); + counter.countDown(); + counter.countDown(); + counter.countDown(); + counter.countDown(); + const count = counter.countDown(); + expect(count).toBe(0); + }); +}); describe('[Exercise 5] Seasons', () => { - let seasons + let seasons; beforeEach(() => { - seasons = new utils.Seasons() // each test must start with fresh seasons - }) - test.todo('[9] the FIRST call of seasons.next returns "summer"') - test.todo('[10] the SECOND call of seasons.next returns "fall"') - test.todo('[11] the THIRD call of seasons.next returns "winter"') - test.todo('[12] the FOURTH call of seasons.next returns "spring"') - test.todo('[13] the FIFTH call of seasons.next returns again "summer"') - test.todo('[14] the 40th call of seasons.next returns "spring"') -}) + seasons = new utils.Seasons(); // each test must start with fresh seasons + }); + test('[9] the FIRST call of seasons.next returns "summer"', () => { + const season = seasons.next(); + expect(season).toBe("summer"); + }); + test('[10] the SECOND call of seasons.next returns "fall"', () => { + seasons.next(); + const season = seasons.next(); + expect(season).toBe("fall"); + }); + test('[11] the THIRD call of seasons.next returns "winter"', () => { + let season; + for (let i = 0; i<3; i++) { + season = seasons.next(); + } + expect(season).toBe("winter"); + }); + test('[12] the FOURTH call of seasons.next returns "spring"', () => { + let season; + for (let i = 0; i<4; i++) { + season = seasons.next(); + } + expect(season).toBe("spring"); + }); + test('[13] the FIFTH call of seasons.next returns again "summer"', () => { + let season; + for (let i = 0; i<5; i++) { + season = seasons.next(); + } + expect(season).toBe("summer"); + }); + test('[14] the 40th call of seasons.next returns "spring"', () => { + let season; + for (let i = 0; i<40; i++) { + season = seasons.next(); + } + expect(season).toBe("spring"); + }); +}); describe('[Exercise 6] Car', () => { - let focus + let focus; beforeEach(() => { - focus = new utils.Car('focus', 20, 30) // each test must start with a fresh car - }) - test.todo('[15] driving the car returns the updated odometer') - test.todo('[16] driving the car uses gas') - test.todo('[17] refueling allows to keep driving') - test.todo('[18] adding fuel to a full tank has no effect') -}) + focus = new utils.Car('focus', 20, 30); // each test must start with a fresh car + }); + test('[15] driving the car returns the updated odometer', () => { + focus.drive(10); + expect(focus.odometer).toBe(10); + }); + test('[16] driving the car uses gas', () => { + focus.drive(30); + const gasLeft = 19; //30 miles at 30 mpg uses 1 gallon. Tank holds 20; + expect(focus.fuel).toBe(gasLeft); + }); + test('[17] refueling allows to keep driving', () => { + focus.drive(610); //run out of gas + expect(focus.odometer).toBe(600); //600 max miles on tank + focus.drive(1); + expect(focus.odometer).toBe(600); + focus.refuel(100); //fills tank + focus.drive(610); //full tank only goes 600 miles. + expect(focus.odometer).toBe(1200); + }); + test('[18] adding fuel to a full tank has no effect', () => { + focus.refuel(200); + expect(focus.fuel).toBe(20); //20 is tank size; + }); +}); describe('[Exercise 7] isEvenNumberAsync', () => { - test.todo('[19] resolves true if passed an even number') - test.todo('[20] resolves false if passed an odd number') - test.todo('[21] rejects an error with the message "number must be a number" if passed a non-number type') - test.todo('[22] rejects an error with the message "number must be a number" if passed NaN') -}) + test('[19] resolves true if passed an even number', async () => { + const evenNumber = 4; + const result = await utils.isEvenNumberAsync(evenNumber); + expect(result).toBe(true); + }); + test('[20] resolves false if passed an odd number', async () => { + const oddNumber = 5; + const result = await utils.isEvenNumberAsync(oddNumber); + expect(result).toBe(false); + }); + test('[21] rejects an error with the message "number must be a number" if passed a non-number type', () => { + const string = "5"; + utils.isEvenNumberAsync(string) + .then() + .catch(err => { + expect(err).toBe("number must be a number"); + }); + }); + test('[22] rejects an error with the message "number must be a number" if passed NaN', () => { + utils.isEvenNumberAsync(NaN) + .then() + .catch(err => { + expect(err).toBe("number must be a number"); + }); + }); +}); \ No newline at end of file