thoughtbot/fishery

Factory cannot build class with methods

Closed this issue · 2 comments

Description

Many of my classes have methods in them, not just properties. It seems that the documentation for Fishery does not say anything about building Factories for classes with methods and in general, it seems that this just does not work.

To Reproduce

import { Factory } from "fishery";

class Thingy {
  foo: string;
  bar: number;

  constructor(foo: string, bar: number) {
      this.foo = foo;
      this.bar = bar;
  }

  to_string(): string {
      return `${this.foo}: ${this.bar}`;
  }
}

const thingyFactory = Factory.define<Thingy>(() => ({
  foo: 'frog',
  bar: 7
}));

Produces the following error when trying to use thingyFactory:

Property 'to_string' is missing in type '{ foo: string; bar: number; }' but required in type 'Thingy'.typescript(2741)

Are classes with methods not supported?

Hi, you can set up your factory to return your custom class. Fishery provides little "magic". It will use whatever is returned by your factory as the return object when you call build. After getting the object from the factory, Fishery layers in any passed params using Object.assign, which works fine with classes. Here is a code sandbox demonstrating this with your example. And the code inline for reference:

import { Factory } from "fishery";
class Thingy {
  foo: string;
  bar: number;

  constructor(foo: string, bar: number) {
    this.foo = foo;
    this.bar = bar;
  }

  hello(): string {
    return `Hello ${this.foo}`;
  }
}

test("this works", () => {
  const userFactory = Factory.define<Thingy>(() => {
    return new Thingy("frog", 7);
  });

  expect(userFactory.build().foo).toEqual("frog");
  expect(userFactory.build({ foo: "dog" }).foo).toEqual("dog");
  expect(userFactory.build().hello()).toEqual("Hello frog");
});

I'm going to close this issue, but feel free to open it if needed.

Thank you for the help, this indeed did what I needed.