Exercise: Pet Adoption Profiles

Finish five functions for a pet adoption site, building profile lines with destructuring and safe copies with spread, and let the tests check each one.

Apprentice · JavaScript · Updated

Happy Tails Rescue is putting its pets online, and the volunteers need the code behind each pet's profile: a one-line summary for the listing page, a way to show only the dogs (or only the cats), and safe ways to update a pet. "Safe" is the important word. When Mochi the cat is adopted, the adoption papers need a copy that says so, while the listing keeps the original until the paperwork is done. Every task is a function for you to finish, and tests check each one as you go.

Before you start

You need Node.js, version 24 or later. In a terminal, node --version shows the version you have. Nothing else needs installing: the tests use the test runner that comes with Node.

Get the exercise code

In the Exercise box beside the lesson, choose Get the starter on GitHub to open its GitHub repository. Click Code, then Download ZIP, and unzip it into your objects-practice folder (or any folder you like). The folder holds:

  • pets.js: the five functions you'll finish.
  • listing.js: prints the shelter's listing with your functions, so you can watch them work. You don't need to change it.
  • pets.test.js: the tests that check your functions. You don't need to change these.
  • package.json: tells Node that these files share functions with import and export. You don't need to change it.

Open the folder in VS Code, and open a terminal there with Terminal > New Terminal.

What to do

Every function is already written down with its name and parameters, and returns an empty value for now: '', [] or {}. The comment above it says what it should return, with examples:

/*
 * Return a copy of the pet with adopted set to true. The pet you're given stays as it is,
 * because the listing still needs it until the paperwork is done.
 *
 * markAdopted({ name: 'Mochi', species: 'cat', adopted: false })
 *   -> { name: 'Mochi', species: 'cat', adopted: true }
 */
export function markAdopted(pet) {
  return {};
}
  1. profileLine(pet): one line for the listing, such as Biscuit (dog, 3 years): loves fetch, good with kids. Unpack the pet with destructuring. A pet aged 1 is 1 year, and a pet with no traits shows no traits listed yet.
  2. petsOfSpecies(pets, species): a new array with only the pets of one species, in their order.
  3. markAdopted(pet): a copy of the pet with adopted: true.
  4. mergeDetails(pet, updates): a copy of the pet with the updated details merged in, such as Juniper's new age after her birthday.
  5. addTrait(pet, trait): a copy of the pet with one more trait at the end of its list.

The rule for all five: none of them changes what it's given. Make a copy, then change the copy.

Check your work

In the terminal, in the exercise folder:

node --test

At first all 11 tests fail. That's expected: each function you finish turns its tests green. When a test fails, its message says what it expected, for example The pet you were given still says adopted: false. Make a copy, then change the copy.

To see your functions at work, run the listing:

node listing.js

Hints

  • Start with the examples. Each function's comment shows what goes in and what comes out. Work one out by hand before you write code.
  • A default fills a gap. A pet with no traits property still needs a list. Destructuring shows how a default covers a missing property. To turn the list into text, traits.join(', ') glues the items together with a comma and a space between them (String Methods, in chapter 4, covers join fully).
  • "Later wins" does the merging. In Spread and Rest, a property written after a spread replaces the copied one. That's all markAdopted and mergeDetails need.
  • Watch the inner list. A spread copy of a pet shares its traits array with the original. If the original's traits change when you add one, copy the array too.
  • Loop, check, collect. petsOfSpecies is the loop from Arrays of Objects: start with an empty array and push each match.

When you're done

Every test is green, and node listing.js prints:

Happy Tails Rescue: waiting for a home
  Biscuit (dog, 3 years): loves fetch, good with kids
  Mochi (cat, 2 years): lap cat, chatty
  Pepper (rabbit, 1 year): shy
  Juniper (dog, 7 years): calm, house-trained
  Clover (guinea pig, 2 years): no traits listed yet
Dogs: Biscuit, Juniper
Mochi's adoption papers say adopted: true. The listing still says false.
After her birthday: Juniper (dog, 8 years): calm, house-trained (nickname June)
New note: Biscuit (dog, 3 years): loves fetch, good with kids, snores
The listing still has: Biscuit (dog, 3 years): loves fetch, good with kids

Look at the last two lines. Biscuit has a new trait in the copy and the old list in the listing. What would have happened to the last line if addTrait had pushed onto the pet's own traits array?

So what

Copy, then change: that's how real apps update data without breaking the screen that still shows the old version, and it's the habit frameworks such as React expect from you.

Key terms

Related