Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Object properties are merged instead overriden #113

Open
rivatove opened this issue Feb 11, 2023 · 3 comments
Open

Object properties are merged instead overriden #113

rivatove opened this issue Feb 11, 2023 · 3 comments
Labels
bug Something isn't working

Comments

@rivatove
Copy link

Description

Object properties are merged instead overriden.

To Reproduce

https://codesandbox.io/s/fishery-test-forked-h29nq6?file=/src/index.test.ts

@rivatove rivatove added the bug Something isn't working label Feb 11, 2023
@stevehanson
Copy link
Contributor

Thank you for sharing this issue. I'm going to share the code from your sandbox inline below to keep the discussion in one place:

import { Factory } from "fishery";

test("Sample test", () => {
  type User = {
    names: Record<string, string>;
  };

  const userFactory = Factory.define<User>(() => ({
    names: { last: "Susan" }
  }));

  expect(
    userFactory.build({ names: { first: "Maria" } })
  ).toEqual({ names: { first: "Maria" } }); // error, names also includes `last: "Susan"`
});

When you call build, the params supplied are deeply merged with the result provided from your factory function. The deep merge behavior is very useful for some common scenarios, but there are some times when it is undesired. For these cases, you can rely on associations (readme) or transientParams (readme).

Here is a Code Sandbox with passing tests for both approaches. In this case, I'd recommend associations, since this is what that feature was built to address.

@mostlylikeable
Copy link

mostlylikeable commented Sep 7, 2024

Just trying to use this library for the first time, and this is one area of annoyance for me as well. I expected that a factory will return the final object, but the fact that any extra params passed in, will also be in the object, is causing somewhat of a pain. I'm not sure what the intended use-cases are for this behavior, but it would be nice to at least have an option allowing me to opt-out of this behavior, and assume that my factory function knows how to create a complete object.

@Mange
Copy link

Mange commented Sep 20, 2024

Maybe this could be solved with sub types. Something like this:

const userFactory = Factory.define<User>(({preventMerging}) => ({
  names: preventMerging({ last: "Susan" })
}));
function mergeObjects(a, b) {
  if (b instanceof PreventMerging) {
    return b.attributes
  }

  if (a instanceof PreventMerging) {
    return b === undefined ? a.attributes : b
  }

  // original code to merge objects
}

(This is a proposal, not something that is implemented!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants