aspida / aspida

TypeScript friendly HTTP client wrapper for the browser and node.js.

Home Page:https://github.com/aspida/aspida

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RFC: Mocking-only aspida client.

LumaKernel opened this issue · comments

commented

Description

create-frourio-app is now generating a little subtle testing code.
That is set up Fastify one-off instance. This strategy includes some problems. ( For example, port would conflict if there are multiple tests, not so easy to define. )

I suggest providing mocking-only aspida client, like @aspida/mock.

Main idea is like this. Consider using jest.

import aspida from '@aspida/axios'
import api from 'path-to-aspida-dir/$api'
const apiClient = api({ baseURL: '' } as any) // only for types

jest.mock('@aspida/axios', () => jest.fn())
;(aspida as any).mockReturnValue({
  baseURL: '',
  fetch(_prefix: string, prefix1: string, method: string) {
    if (prefix1 === apiClient.tasks.$path() && method === 'GET') {
      return {
        json: () =>
          Promise.resolve({
            body: [
              { id: 1, label: 'foo task', done: false },
              { id: 2, label: 'bar task', done: true }
            ]
          })
      }
    }
    if (prefix1 === apiClient.token.$path() && method === 'POST') {
      return {
        json: () =>
          Promise.resolve({
            body: false
          })
      }
    }
    throw new Error('Unmocked path.')
  }
})

This is, now not so easy, but works fine.
We may create a type-safe mock library for this idea like following.

import aspida from '@aspida/axios' // NOTE:  The client that project using, @aspida/...
import aspidaMock from '@aspida/mock'
import api from 'path-to-aspida-dir/$api'

// NOTE: For achieving not to depend on jest, mock itself self-contained.
aspida.mock(aspidaMock(api)({
  tasks: {
    $get: [
      { id: 1, label: 'foo task', done: false },
      { id: 2, label: 'bar task', done: true }
    ]
  },
  token: {
    $post: false
  }
}))

// NOTE: We may also want to provide a method to clear.
// aspida.clearMock();

Concise specs

  • Unmocked paths/methods are thrown.

Further considerations

  • Supporting to accept mocking function.
    • e.g. $get: ({body:{id}}) => `test-user-${id}`
  • How does it cost for runtime?
  • It costs if using if (mocked).
  • Use process.env.NODE_ENV === "test" internally to avoid runtime cost for bundler users?
  • Can we use $get as string? Or should we provide like aspidaMock.$get Symbols to support path like $path?
    • token: {[aspidaMock.$get]: false}

I've been struggling with the mock ecosystem for almost a year.
This proposal looks good to me.
If I make it dependent on jest, I'll probably release it as @aspida/jest.

  • Create aspida/aspida-jest repository
  • Publish @aspida/jest
commented

I was assigned to complete this idea. If anyone has questions, suggestions or comments, please leave them here. :)