Last active
April 4, 2019 13:50
-
-
Save jmporchet/e77ca1d84eba9f39f479b8645b5d4b1d to your computer and use it in GitHub Desktop.
Spread operator vs lodash's cloneDeep()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is an illustration of when NOT to use the spread operator to copy variables. | |
// Check https://codesandbox.io/s/6w749171mz for a working copy of the code | |
import { cloneDeep } from "lodash"; | |
import { | |
getDrinkNutrientsFromResult, | |
mapRecipesToNutrients | |
} from "../nutrition"; | |
describe("helper methods", () => { | |
const recipes = [ | |
{ | |
id: 1, | |
state: "ready", | |
createdAt: "2019-03-19T01:01:01.000Z", | |
nutrients: [ | |
{ key: "chromium", value: 1116.47 }, | |
{ key: "biotin", value: 0.01 } | |
] | |
}, | |
{ | |
id: 2, | |
state: "in_progress", | |
createdAt: "2019-03-19T01:01:01.000Z", | |
nutrients: [ | |
{ key: "chromium", value: 1116.47 }, | |
{ key: "biotin", value: 0.01 } | |
] | |
} | |
]; | |
const expectedData = [ | |
{ key: "biotin", unit: "mg", value: 0.01 }, | |
{ key: "chromium", unit: "mg", value: 1116.47 } | |
// ... | |
]; | |
const nutrientNames = [ | |
"biotin", | |
"chromium" | |
// ... | |
]; | |
let recipesList, expected; | |
beforeEach(() => { | |
// cloneDeep will copy all the elements by value recursively, instead of passing them by reference | |
// | |
recipesList = cloneDeep(recipes); | |
expected = cloneDeep(expectedData); | |
// The tests would break, because even though recipesList is a new variable | |
// teh rest operator will copy all the elements by REFERENCE | |
// | |
// recipesList = [...recipes]; | |
}); | |
it("should get the nutrients from a recipe", () => { | |
// mutates the element | |
recipesList.find(recipe => recipe.state === "in_progress").createdAt = | |
"2019-03-20T22:13:13.889Z"; | |
expect(getDrinkNutrientsFromResult(recipesList)).toEqual(expected); | |
}); | |
it("should behave gracefully when an expected element is not in the recipe", () => { | |
// mutates the elements | |
recipesList.find(r => r.id === 1).nutrients[0] = null; | |
expected.find(n => n.key === "chromium").value = 0; | |
expect(getDrinkNutrientsFromResult(recipesList)).toEqual(expected); | |
}); | |
// putting this test last will make it fail if using the spread operator | |
// because chromium's value has been modified to 0 from line 67. | |
// cloneDeep() clones the elements too, this way the problem doesn't happen anymore | |
// | |
it("should map recipes to nutrients correctly", () => { | |
expect(mapRecipesToNutrients(recipesList, nutrientNames)).toEqual(expected); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment