question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using Factories in Factories (use fake data of one factory to generate fake data of another factory)

See original GitHub issue

@samselikoff Hello and thank you so much for the fantastic tool you released to the public:)

Note: I am very new (less than a week) in playing with mirage, but I already found it very useful and incredibly easy to use.

I was able to easily built up a full auth system (using JWT) to mock the auth in the backend.

Now I am a step further, and I would like to create a factory that depends directly from another factory. To be honest, I am a bit confuse about how to proceed and moreover, if “traits” is what I should use or not.

To be very explicit, and probably explain myself in a better way, let’s assume the following:

(1) I have two models, the tenant model and the user model (for which I defined the relationships tenant “hasMany” users and user “belongsTo” tenant).

(2) I created a factory for my tenant model, in which I defined a field called domain (e.g. example.com).

(3) I Created a factory for my user model, in which I defined a password field and an email field.

(4) I use faker to generate fake data.

The following is my code, hope it is helpful to clarify my problem and help you in responding (my code is split in multiple files):

tenant factory

import { Factory } from 'miragejs'
import faker from 'faker'

export default {
  tenant: Factory.extend({
    domain() {
      return faker.fake(
        '{{internet.domainName}}'
      )
    },
    name() {
      return this.domain.split('.')[0]
    },
    tenantId() {
      return this.name + faker.fake('{{random.number}}')
    },
    afterCreate(tenant, server) {
      const users = server.createList('user', 4, { domain: tenant.domain })

      tenant.update({ users })
    }
  })
}

user factory

import { Factory } from 'miragejs'
import faker from 'faker'

export default {
  user: Factory.extend({
    email() {
      return faker.fake(
        '{{name.firstName}}.{{name.lastName}}@' + this.domain
        //'{{name.firstName}}.{{name.lastName}}@{{company.companyName}}.com'
      )
    },
    password() {
      return faker.fake('{{internet.password}}')
    }
  })
}

my models import { Model, hasMany, belongsTo } from ‘miragejs’

export default {
  tenant: Model.extend({
    users: hasMany()
  }),
  user: Model.extend({
    tenant: belongsTo()
  })
}

When I check the mirage response, I get:

tenant -> domain= e.g. example.com, name= e.g. example, tenantId= e.g. example3546

user(this is 1 out of 4) -> email= e.g. jane.doe@example.com, password: myweirdpassword, domain= example.com

As you can see in this way I am able to use a field of one of the factory(tenant) into the field of another factory (user), but I also generate a new extra field in the “receiving” factory, and I don’t want that.

What I am doing wrong? How I can use the “domain” field generated for tenant inside of the email field generated for user? Do you have any suggestions? (I found a post in which there was a similar discussion, but it wasn’t really clear how the issue was solved and if it was ever solved in the first place).

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:13 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
samselikoffcommented, Oct 5, 2020

You don’t have to loop if you’d prefer using a trait: https://miragejs.com/repl/v1/508

You also don’t even have to use a trait (you could just stick that in the root afterCreate, but the trait lets you create Tenants without users (if for example a test calls for that setup).

Regarding two parameters, I’m not sure what you mean. You get an eslint error? You could just not define the second parameter. You don’t need to use it if you have no need for it. So something like this:

afterCreate(user) {
  let email = faker.fake(
  '{{name.firstName}}.{{name.lastName}}@' + user.tenant.domain
  )
  
  user.update({ email })
}

As for skipping the auto-email generation, you could add an if () check to your afterCreate hook. Here’s an example of a tenant with 3 randomly generated users, as well as a bespoke Dinuz user and Acme tenant: https://miragejs.com/repl/v1/509

0reactions
Dinuzcommented, Oct 24, 2020

@samselikoff I do think I figured it out (I would love to help you eventually putting all these efforts in some doc or maybe some example link).

Could you confirm that the following is the correct approach (multiple models, nested relationships etc). The following code comes directly from experimenting and testing it in REPL (took a while, and without REPL I don’t think I would figured it out before giving up on the whole mirage):

import { createServer, Model, belongsTo, hasMany, Factory, association, trait } from "miragejs"
import faker from 'faker'

export default createServer({
  models: {
    tenant: Model.extend({
      users: hasMany()
    }),
    user: Model.extend({
      tenant: belongsTo(),
      basic: belongsTo(),
      avatar: belongsTo()
    }),
    basic: Model.extend({
      user: belongsTo()
    }),
    avatar: Model.extend({
      user: belongsTo()
    })
  },

  factories: {
    tenant: Factory.extend({
      domain() {
        return faker.fake('{{internet.domainName}}')
      },
      name() {
        return this.domain.split('.')[0]
      },  
      withUsers: trait({        
      	afterCreate(tenant, server) {
          server.createList('user', 3, 'withInfoBasic', 'withAvatar', { tenant })
      	}
      })
    }),

    user: Factory.extend({
      tenant: association(),
      emailVerified(){
      	return faker.fake('{{random.boolean}}')
      },
      password(){
      	return faker.fake('{{internet.password}}')
      },
      withInfoBasic: trait({
        afterCreate(user, server) {
        server.create('basic', {user})
        }
      }),
      withAvatar: trait({
        afterCreate(user, server) {
        server.create('avatar', {user})
        }
      })
    }),
    
    basic: Factory.extend({
      user: association,
        afterCreate(basic, server) {
          let firstName = basic.firstName ? basic.firstName : faker.fake('{{name.firstName}}')
          let lastName = basic.lastName ? basic.lastName : faker.fake('{{name.lastName}}')
          basic.update({firstName, lastName})
          let email = basic.user.email ? basic.user.email : firstName +'.'+ lastName + '@' + basic.user.tenant.domain
          let displayName = basic.user.displayName ? basic.user.displayName : firstName + ' ' + lastName
          basic.user.update({email, displayName})
        }
    }),
    
    avatar: Factory.extend({
    	user: association,
      afterCreate(avatar, server) {
      		let avatarImage = avatar.imgUrl ? avatar.imgUrl : faker.fake('{{image.avatar}}')
            avatar.update({avatarImage})
        let avatarUrl = avatar.user.avatarUrl ? avatar.user.avatarUrl : avatarImage
        avatar.user.update({avatarUrl})
      }
    })
  },

  seeds(server) {
    server.create('tenant', 'withUsers')
    
    let userSeed = server.create('user', {email:'hammer@newman.com', emailVerified: 'false', password:'123456'})
    server.create('basic', {user: userSeed, firstName:'Lucas', lastName:'Cohen'})
    server.create('avatar', {user: userSeed})
    
  }
})

The double update in the afterCreate method, and the multiple traits declaration in the top model are completely missing in the documentation.

Looking forward to hearing your opinion.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Generate fake data using Faker and Factory in Laravel
Generate fake data using Faker and Factory in Laravel ... With a bit of setup, It can be done. ... Go to database/factories/ModelFactory.php....
Read more >
Creating fake data in Laravel using factories and faker
If this video has helped you why not buy me a coffee to say thank you? https://www.patreon.com/p_digital...Follow me on twitter: ...
Read more >
Working Effectively with Data Factories Using FactoryBot
Data Factory (or factory in short) is a blueprint that allows us to create an object, or a collection of objects, with predefined...
Read more >
How to Generate Dummy fake data using Factory in laravel 9
You can also create fake dummy data using tinker. just follow above 1 to 3 step. then start tinker and run below commad....
Read more >
Create factory using faker, where one field depends on the ...
where in the code can I perform operations like getting data from database and setting some variables, so that i can use those...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found