From 34310c8cc7e9c7abde17cfbd4e5cd6619cddf0ab Mon Sep 17 00:00:00 2001 From: Octowl Date: Fri, 5 Oct 2018 21:22:24 +0300 Subject: [PATCH] Add task file and tests --- functions.js | 184 ++++++++++++++++++++++++++++++++++++++++++ functions.spec.js | 198 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 382 insertions(+) create mode 100644 functions.js create mode 100644 functions.spec.js diff --git a/functions.js b/functions.js new file mode 100644 index 0000000..77b610a --- /dev/null +++ b/functions.js @@ -0,0 +1,184 @@ +/************************************************************** + * getBookById(bookId, books): + * - receives a bookId + * - recieves an array of book objects + * - returns the book object that matches that id + * - returns undefined if no matching book is found + ****************************************************************/ +function getBookById(bookId, books) { + // Your code goes here + // return books.find(book => book.id === bookId); +} + +/************************************************************** + * getAuthorByName(authorName, authors): + * - receives an authorName + * - recieves an array of author objects + * - returns the author that matches that name (CASE INSENSITIVE) + * - returns undefined if no matching author is found + ****************************************************************/ +function getAuthorByName(authorName, authors) { + // Your code goes here + // return authors.find( + // author => author.name.toLowerCase() === authorName.toLowerCase() + // ); +} + +/************************************************************** + * bookCountsByAuthor(authors): + * - receives an array of authors + * - returns an array of objects with the format: + * [{ author: , bookCount: }] + ****************************************************************/ +function bookCountsByAuthor(authors) { + // Your code goes here + // return authors.map(author => ({ + // author: author.name, + // bookCount: author.books.length + // })); +} + +/************************************************************** + * booksByColor(books): + * - receives an array of books + * - returns an object where the keys ar colors + * and the values are arrays of book titles: + * { : [] } + ****************************************************************/ +function booksByColor(books) { + const colors = {}; + + // Your code goes here + // books.forEach(book => { + // if (colors[book.color]) { + // colors[book.color].push(book.title); + // } else { + // colors[book.color] = [book.title]; + // } + // }); + + return colors; +} + +/************************************************************** + * titlesByAuthorName(authorName, authors, books): + * - receives an authorName + * - recieves an array of author objects + * - recieves an array of book objects + * - returns an array of the titles of the books written by that author: + * ["The Hitchhikers Guide", "The Meaning of Liff"] + ****************************************************************/ +function titlesByAuthorName(authorName, authors, books) { + // Your code goes here + // const author = getAuthorByName(authorName, authors); + // if (!author) return []; + // return author.books.map(bookId => getBookById(bookId, books).title); +} + +/************************************************************** + * mostProlificAuthor(authors): + * - receives a list of authors + * - returns the name of the author with the most books + * + * Note: assume there will never be a tie + ****************************************************************/ +function mostProlificAuthor(authors) { + // Your code goes here + // let prolificAuthor = authors[0]; + // authors.forEach(author => { + // if (author.books.length > prolificAuthor.books.length) { + // prolificAuthor = author; + // } + // }); + // return prolificAuthor.name; + /* One-liner using reduce and a ternary operator */ + // return authors.reduce((a, b) => (a.books.length > b.books.length ? a : b)) + // .name; +} + +/************************************************************** + * relatedBooks(bookId, books): + * - receives a bookId + * - receives a list of authors + * - receives a list of books + * - returns a list of the titles of all the books by + * the same author as the book with bookId + * (including the original book) + * + * NOTES: YOU NEED TO TAKE INTO ACCOUNT BOOKS WITH MULTIPLE AUTHORS + * BONUS: REMOVE DUPLICATE BOOKS + ****************************************************************/ +function relatedBooks(bookId, authors, books) { + // Your code goes here + // const book = getBookById(bookId, books); + // let titles = []; + // book.authors.forEach( + // author => + // (titles = titles.concat(titlesByAuthorName(author.name, authors, books))) + // ); + // /* BONUS */ + // // titles = [...new Set(titles)]; + // return titles; + /* "One-liner" using reduce */ + // return getBookById(bookId, books).authors.reduce( + // (titles, author) => [ + // ...new Set(titles.concat(titlesByAuthorName(author.name, authors, books))) + // ], + // [] + // ); +} + +/************************************************************** + * friendliestAuthor(authors): + * - receives a list of authors + * - returns the name of the author that has + * co-authored the greatest number of books + ****************************************************************/ +function friendliestAuthor(authors) { + // authors.forEach(author => { + // author.coauthoringCount = 0; + // authors.forEach(secondAuthor => { + // if (secondAuthor.name !== author.name) { + // const sharedBooks = secondAuthor.books.filter(bookId => + // author.books.includes(bookId) + // ); + // author.coauthoringCount += sharedBooks.length; + // } + // }); + // }); + // let friendlyAuthor = authors[0]; + // authors.forEach(author => { + // if (author.coauthoringCount > friendlyAuthor.coauthoringCount) { + // friendlyAuthor = author; + // } + // }); + // return friendlyAuthor.name; +} + +module.exports = { + getBookById, + getAuthorByName, + bookCountsByAuthor, + booksByColor, + titlesByAuthorName, + mostProlificAuthor, + relatedBooks, + friendliestAuthor +}; + +/** + * Uncomment the following lines if you + * want to manually test your code + */ + +// const authors = require("./authors.json"); +// const books = require("./books.json"); + +// console.log(getBookById(12, books)); +// console.log(getAuthorByName("J.K. Rowling", authors)); +// console.log(bookCountsByAuthor(authors)); +// console.log(booksByColor(books)); +// console.log(titlesByAuthorName("George R.R. Martin", authors, books)); +// console.log(mostProlificAuthor(authors)); +// console.log(relatedBooks(50, books)); +// console.log(friendliestAuthor(authors)); diff --git a/functions.spec.js b/functions.spec.js new file mode 100644 index 0000000..05ef624 --- /dev/null +++ b/functions.spec.js @@ -0,0 +1,198 @@ +/************************** + * + * THIS IS A TESTING FILE + * + * DO NOT MODIFY THIS FILE + * + ***************************/ + +import { + getBookById, + getAuthorByName, + bookCountsByAuthor, + booksByColor, + titlesByAuthorName, + mostProlificAuthor, + relatedBooks, + friendliestAuthor +} from "./functions"; + +// Data +import authors from "./authors.json"; +import books from "./books.json"; + +describe("getBookById(bookId, books)", () => { + test("returns the correct book", () => { + const expected = books[Math.floor(Math.random() * books.length)]; + const result = getBookById(expected.id, books); + expect(result).toBe(expected); + }); + + test("returns undefined if the book is not found", () => { + const result = getBookById(10000, books); + expect(result).toBeUndefined(); + }); +}); + +describe("getAuthorByName(authorName, authors)", () => { + test("returns the correct author", () => { + const expected = authors[Math.floor(Math.random() * authors.length)]; + const result = getAuthorByName(expected.name, authors); + expect(result).toBe(expected); + }); + + test("is case insensitive", () => { + const expected = authors[Math.floor(Math.random() * authors.length)]; + let result = getAuthorByName(expected.name.toLowerCase(), authors); + expect(result).toBe(expected); + result = getAuthorByName(expected.name.toUpperCase(), authors); + expect(result).toBe(expected); + }); + + test("returns undefined if the author is not found", () => { + const result = getAuthorByName("Dr Patatis", authors); + expect(result).toBeUndefined(); + }); +}); + +describe("bookCountsByAuthor(authors)", () => { + test("returns the correct number of objects", () => { + const expected = authors.length; + const result = bookCountsByAuthor(authors).length; + expect(result).toBe(expected); + }); + + test("returns the correct format", () => { + const result = bookCountsByAuthor(authors).every(author => { + const keys = Object.keys(author); + return keys.includes("author") && keys.includes("bookCount"); + }); + expect(result).toBe(true); + }); + + test("returns the correct data", () => { + const expected = [ + { author: "Margaret Atwood", bookCount: 4 }, + { author: "Lauren Beukes", bookCount: 2 } + ]; + const result = bookCountsByAuthor(authors.slice(0, 2)); + expect(result).toEqual(expected); + }); +}); + +describe("booksByColor(books)", () => { + test("returns the correct number of colors", () => { + const expected = 2; + const onlyGreenAndBlueBooks = books.filter( + book => book.color === "green" || book.color === "blue" + ); + const result = Object.keys(booksByColor(onlyGreenAndBlueBooks)).length; + expect(result).toBe(expected); + }); + + test("returns the correct format", () => { + const result = Object.values(booksByColor(books)).every(bookList => + Array.isArray(bookList) + ); + expect(result).toBe(true); + }); + + test("returns the correct data", () => { + const expected = { + white: [ + "12 Rules for Life: An Antidote to Chaos", + "A Dance With Dragons" + ], + yellow: ["A Clash of Kings"], + red: ["A Feast for Crows"] + }; + const result = booksByColor(books.slice(0, 4)); + expect(result).toEqual(expected); + }); +}); + +describe("titlesByAuthorName(authorName, authors, books)", () => { + test("returns the correct list of books", () => { + let expected = ["The Shining Girls", "Zoo City"].sort(); + let result = titlesByAuthorName("Lauren Beukes", authors, books).sort(); + expect(result).toEqual(expected); + expected = ["Jane Eyre"]; + result = titlesByAuthorName("Charlotte Brontë", authors, books); + expect(result).toEqual(expected); + }); + + test("is case-insensitive", () => { + let expected = ["The Shining Girls", "Zoo City"].sort(); + let result = titlesByAuthorName("LaUreN BEukeS", authors, books).sort(); + expect(result).toEqual(expected); + expected = ["Jane Eyre"]; + result = titlesByAuthorName("CHaRlOttE BRontë", authors, books); + expect(result).toEqual(expected); + }); + + test("returns an empty array if the author is not found", () => { + const result = titlesByAuthorName("Dr Patatis", authors, books); + expect(result).toEqual([]); + }); +}); + +describe("mostProlificAuthor(authors)", () => { + test("returns the correct author name", () => { + const expected = "Agatha Christie"; + const result = mostProlificAuthor(authors.slice(0, 5)); + expect(result).toBe(expected); + }); +}); + +describe("relatedBooks(bookId, authors, books)", () => { + test("returns the correct books", () => { + const expected = ["The Shining Girls", "Zoo City"].sort(); + const result = relatedBooks(37, authors, books).sort(); + expect(result).toEqual(expected); + }); + + test("can handle co-authored books - returns the titles of books by BOTH authors", () => { + const expected = [ + "Good Omens", + "Good Omens", + "Neverwhere", + "Coraline", + "The Color of Magic", + "The Hogfather", + "Wee Free Men", + "The Long Earth", + "The Long War", + "The Long Mars" + ].sort(); + const result = relatedBooks(46, authors, books).sort(); + expect(result).toEqual(expected); + }); + + /** + * Remove the x to unskip and run the bonus test. + * Add an x to the previous test to skip it + */ + xtest("BONUS - removes duplicate books", () => { + const expected = [ + "Good Omens", + "Neverwhere", + "Coraline", + "The Color of Magic", + "The Hogfather", + "Wee Free Men", + "The Long Earth", + "The Long War", + "The Long Mars" + ].sort(); + const result = relatedBooks(46, authors, books).sort(); + expect(result).toEqual(expected); + }); +}); + +describe("friendliestAuthor(authors)", () => { + test("returns the correct author", () => { + const expected = "Terry Pratchett"; + const result = friendliestAuthor(authors); + expect(result).toEqual(expected); + }); +});