thoughtbot/fishery

Factory use will overwrite the created object of the previous use

drewdrewthis opened this issue · 2 comments

When running tests in Jest with Typescript

Actual

Using the following factory:

import Big from 'big.js';
import { Factory } from 'fishery';
import { Swap } from '../lib/BalancerOpportunityDecorator/types';
import Token from './Token';

const srcToken = Token.build();
const destToken = Token.build();

export default Factory.define<Swap>(() => ({
  srcAmount:  Big(1),
  destAmount: Big(1),
  pool:       {
    id:      '',
    address: '',
    swapFee: Big('0.0015'),
  },
  srcToken,
  destToken,
  rate: Big(1),
}));

Like so:

  const swaps = [
    Factories.Swap.build({
      pool: {
        swapFee: Big('0'),
      },
      srcToken: {
        balance:  Big('25'),
        decimals: 18,
        weight:   Big('0.5'),
      },
      destToken: {
        balance:  Big('75'),
        decimals: 18,
        weight:   Big('0.5'),
      },
    }), Factories.Swap.build({
      pool: {
        swapFee: Big('0'),
      },
      srcToken: {
        balance:  Big('70'),
        decimals: 18,
        weight:   Big('0.5'),
      },
      destToken: {
        balance:  Big('30'),
        decimals: 18,
        weight:   Big('0.5'),
      },
    }),
  ];

Somehow makes swaps[0] be an equal object to swaps[1], where swap[1] passed in properties are the ones used.

ie. swaps[0].srcToken.balance === swaps[1].srcToken.balance === Big('70') as well as the other properties.

Expected

swap[0] !== swap[1]

swaps[1].srcToken.balance === Big('25')

Help?

After some playing, it seems that spreading the built token resolves the issue:

import Big from 'big.js';
import { Factory } from 'fishery';
import { Swap } from '../lib/BalancerOpportunityDecorator/types';
import Token from './Token';

const srcToken = Token.build();
const destToken = Token.build();

export default Factory.define<Swap>(() => ({
  srcAmount:  Big(1),
  destAmount: Big(1),
  pool:       {
    id:      '',
    address: '',
    swapFee: Big('0.0015'),
  },
  srcToken: {
    ...srcToken,
  },
  destToken: {
    ...destToken,
  },
  rate: Big(1),
}));

However, I would still consider this unexpected behavior as one would expect the passed in srcToken to be used instead of somehow overwriting some cached instance.

@drewdrewthis you are creating srcToken and destToken outside of your factory. These objects are being created one time when your JavaScript file is initially loaded and then are reused for every factory. If you want each factory-built object to have its own token, you'd need to create it inside your factory like this:

export default Factory.define<Swap>(() => {
  const srcToken = Token.build();
  const destToken = Token.build();

  return {
    srcAmount:  Big(1),
    destAmount: Big(1),
    pool:       {
      id:      '',
      address: '',
      swapFee: Big('0.0015'),
    },
    srcToken,
    destToken,
    rate: Big(1),
  }
});

I'm going to go ahead and close this, but let me know if this doesn't resolve the issue.