bgantzler / ember-mirage

Aids in setting up mirage for ember testing
MIT License
4 stars 5 forks source link

Support auto discovery for mirage and ember-data entities via import.meta.glob #39

Open enspandi opened 3 months ago

enspandi commented 3 months ago

Add back support for auto discovering mirage/ember-data entities with the support of import.meta.glob.

The idea is to use a createConfig util from ember-mirage to create the initial config and pass that directly to createServer from miragejs.

Currently ember-cli-mirage and ember-mirage handled 3 additional config values automatically which need to be set manually now:

See example below how those can be set.

Note1: If ember-data model/serializer auto discovery is not used, the ember-data store does not have to be set

Note2: Currently miragejs makes a few assumption based on the config you set, like scenarios in which it might not load the factories, even if you pass them:

https://github.com/miragejs/miragejs/blob/9644e898a5f4d1a4cf33525c1fac96d67ea019c5/lib/server.js#L298-L305

^ TBD - If better to pass scenarios for now and don't try to invoke the default scenario ourselves.

Example:

// app/route/application.js
import { macroCondition, isDevelopingApp, isTesting } from '@embroider/macros';

export default class extends Route {
  beforeModel() {
    if (macroCondition(isDevelopingApp())) {
      const createServer = (await import('../mirage/config')).default;
      const server = await createServer(this.store);

      if (!isTesting()) {
        // See Note2: TBD if we should pass `scenarios` key to miragejs instead and have it execute it
        const defaultScenario = (await import('../mirage/scenarios/default.js'))
          .default;
        defaultScenario(server);
      }
    }
  }
}
// app/mirage/config.js
import { pluralize, singularize } from 'active-inflector';
import createConfig from 'ember-mirage/create-config';
import { createServer } from 'miragejs';

export default async function (store) {
  const mirageConfig = await createConfig(
    {
      factories: import.meta.glob('./factories/*'),
      fixtures: import.meta.glob('./fixtures/*'),
      models: import.meta.glob('./models/*'),
      serializers: import.meta.glob('./serializers/*'),
      identityManagers: import.meta.glob('./identity-managers/*')
    },
    {
      store,
      models: import.meta.glob('../models/*.ts')
    }
  );

  return createServer({
    ...mirageConfig,
    routes,
    inflector: { singularize, pluralize },
    environment: config.environment,
    logging: true
  });
}

Work in progress:

bgantzler commented 3 months ago

@NullVoxPopuli i don't care if we add this back in, but I specifically left it out as ED models I would presume be going away. And the replacement would not be discoverable in the same way. Also this discoverable happens at start and I think I heard @runspired say the model fragments could be registered at run time.

Your call if you want to approve this.

cah-brian-gantzler commented 3 months ago

What you have is a per test, but the opt in is already provided in the server config. You could do

import { createServer } from 'miragejs';

// Would embroider allow this to be import from another addon, doesnt have to be in this addon? 
// and still allow access to the files?
import autoDiscoverModels from 'ember-mirage/auto-discover-models'; 

export default function (config) {
  let { environment, trackRequests, inflector } = config;

  let finalConfig = {
    environment,
    trackRequests,
    identityManagers: {},
    inflector,

    fixtures: {},
    models: autoDiscoverModels(),

    routes() {
    },

  };

  return createServer(finalConfig);
}
cah-brian-gantzler commented 3 months ago

You can even merge in miragejs models over the auto discovered ones if you wanted to customize them a bit

models: {
     ...autoDiscoverModels(),
     blogPost: Model.extend({
      author: belongsTo(),
    }),

    author: Model,
}
NullVoxPopuli commented 3 months ago

@enspandi thanks for submitting this PR! apologies for not providing more detailed feedback sooner.

If you have any questions, please feel free to contact me on discord <3

mansona commented 2 weeks ago

Hey folks 👋 I'm just checking in to see if we can unblock this? I suspect a bunch of people are going to want to migrate to Vite soon and having this working would be super amazing

NullVoxPopuli commented 2 weeks ago

@mansona this comment is still valid: https://github.com/bgantzler/ember-mirage/pull/39#discussion_r1668810628

ef4 commented 2 weeks ago

I agree with the suggestion to keep the ember-data support separate from the basic loading of the /mirage dir.

Having just implemented all of this manually in an app, the main thing that I needed is the readModules logic.

I changed that function so it takes the set of modules as an argument, and then it can drop right into the mirage config like:

const modules = readModules(
  './',
  import.meta.glob('./**/*.{js,ts}', { eager: true }),
);
createServer({ routes, ...modules, timing: 0 })

Without this, people are going to need to rename their files to match the quirky rules implemented by readModules.

enspandi commented 6 days ago

Sorry for taking so long... thx for all the feedback :pray:

Moving the ember-data code outside the mirage create-config is great idea :+1: .

The new mirage config could look like this:

import createConfig from 'ember-mirage/create-config';
import { importEmberDataModels } from 'ember-mirage/ember-data';
import { createServer } from 'miragejs';

import config from '../config/environment';

const mirageConfig = await createConfig(
  {
    factories: import.meta.glob('./factories/*'),
    fixtures: import.meta.glob('./fixtures/*'),
    models: import.meta.glob('./models/*'),
    serializers: import.meta.glob('./serializers/*'),
    identityManagers: import.meta.glob('./identity-managers/*')
  }
);

return createServer({
  ...mirageConfig,
  models: {
    // use ember-data model auto discovery
    ...importEmberDataModels(store, import.meta.glob('../models/*')),
    ...mirageConfig.models,
  },
  // apply ember-data serializer config details to mirage serializers
  serializers: applyEmberDataSerializers(store, mirageConfig.serializers),
  routes,
  inflector: { singularize, pluralize },
  environment: config.environment,
  logging: true
});

In the end it looks a bit similar to the config from ember-cli-mirage - hope this will be useful... https://github.com/miragejs/ember-cli-mirage/blob/e5691c5b2f40014894b2464de64b93b8308655b5/packages/ember-cli-mirage-docs/app/templates/docs/advanced/server-configuration.md?plain=1#L119

And I see it could also be useful to add the change from https://github.com/miragejs/ember-cli-mirage/blob/e5691c5b2f40014894b2464de64b93b8308655b5/packages/ember-cli-mirage/addon/utils/read-modules.js#L58 to get the right name for mirage for factories...

NullVoxPopuli commented 5 days ago

That looks good! Got some red in ci tho