redwoodjs / redwood

The App Framework for Startups
https://redwoodjs.com
MIT License
17.17k stars 983 forks source link

[RFC]: Globally mock a mutation not in a Cell #6671

Open craineum opened 1 year ago

craineum commented 1 year ago

Summary

I have a mutation that is automatically running via useEffect. Any page/component that is loading this component is then trying to make a request that isn't handled. Adding a .mock.ts file in the component directory is not automatically loading the mock globally since it isn't a Cell.

Motivation

This is probably a pretty narrow use case, but the idea is I want to verify a users email.

The app will email the user a link with a token. When clicked it will load a "verification" component that reads in the token along with the current user then runs a mutation (via useEffect on load) to clear the token (thus verifying the user and their email address).

I can't put this in a cell since there is no initial query to get anything.

For storybook and tests I would like to add a global mock to make thing pass by default so the other components/pages calling this don't need to worry about the mutation that is automatically firing.

Detailed proposal

Possible solutions:

  1. Allow mock files to be loaded from places besides cells.
  2. Have a way to configure loading of global mock files.
  3. Allow cells to call a mutation instead of a query.

Are you interested in working on this?

noire-munich commented 1 year ago

Thank you for this RFC @craineum, verifying a user's email might be a narrow use case to update a framework's code - but it's also a very common one, so it definitely deserves a discussion.

I also find this rather interesting:

Allow cells to call a mutation instead of a query.

A mutation returns a type, so the question of switching a query for a mutation whenever we'd want is relevant.

dac09 commented 1 year ago

Have you looked into mockGraphQLMutation ? https://redwoodjs.com/docs/mocking-graphql-requests

If you want it to be globally available, you could customise your jest config to add a setup file (while also extending the built in one) - and call it in there!

craineum commented 1 year ago

Have you looked into mockGraphQLMutation ? https://redwoodjs.com/docs/mocking-graphql-requests

If you want it to be globally available, you could customise your jest config to add a setup file (while also extending the built in one) - and call it in there!

@dac09 Yeah, I did see this, which it states in that documentation:

Placing your mock-requests in ".mock.js" will cause them to be globally scoped in Storybook, making them available to all stories.

Which made me think creating the mock file was all I needed to do. It doesn't state that this is scoped to "Cells" only. I know this says stories and not tests, so maybe that is the disconnect?

I could load my own, but then I am worried I could be double loading all the Cell mocks if I don't properly address all the files, but exclude the Cell mocks.

It would be handy if this string could be read in from config somewhere.

craineum commented 1 year ago

Was able to get around it by adding the following to my jest.config.js:

const config = {
  ...,
  setupFilesAfterEnv: [path.resolve(__dirname, './jest.setup.js')],
}

Then added a setup file jest.setup.js (which is really a copy and paste of the built-in setup and findCellMock files)

/* eslint-env jest */
const fg = require('fast-glob')

const {
  startMSW,
  setupRequestHandlers,
  closeServer,
} = require('@redwoodjs/testing/dist/web/mockRequests')

const mocks = fg.sync('**/*.mock.{js,ts,jsx,tsx}', {
  cwd: global.__RWJS_TESTROOT_DIR,
  ignore: ['node_modules', '**/*Cell/*'],
  absolute: true,
})

beforeAll(async () => {
  for (const m of mocks) {
    require(m)
  }

  // Have to bounce the server since it is already being run from somewhere else
  //   in order to get it to load the new required files
  await closeServer()
  await startMSW('node')
  setupRequestHandlers() // reset the handlers
})

There is magic happening since I know the other built-in files are being used, like the setting of the global mockGraphQLMutation function.

I think it should still be addressed in the Redwood core configuration of jest.

dac09 commented 1 year ago

The problem with this solution, @craineum - its that cell mocks are specifically setup for queries, not for mutations.

packages/internal/src/build/babelPlugins/babel-plugin-redwood-mock-cell-data.ts will wrap the export in mock files in mockGraphqlQuery - however what you're trying to do is call mockGraphQLMutaiton.

I can understand why you would want mocks to be loaded from everywhere though - but that can have a performance impact.

The way I suggest you do mocks is by using the standard ways of running some code before your tests/stories.

For Jest

that's jest setup (no need to duplicate stuff from inside the framework):

const config = {
  rootDir: '../',
  preset: '@redwoodjs/testing/config/jest/api',
// 👇 Have your file that will run whatever you need to mock here
  setupFilesAfterEnv: ['<rootDir>/api/runGlobalMutationMocks.ts'],
}

For Storybook

Use a loader: https://storybook.js.org/docs/react/writing-stories/loaders#global-loaders

In both cases, you call the mockGraphQLMutaiton and it should be good to go :)