🍔

Prisma.$extendでprismaをmock化する

2023/12/20に公開

以前$useを利用してprismaをmock化する記事を書いたが、$useがdeprecatedになってしまった。

代替として利用できる$extendに書き換えた場合をやってみる

$useを使っていたもの

まずおさらいとして、$useを使っていた場合は下記のようなものだった

const mockedPrismaClient = () => {
  const prismaClient = new PrismaClient()
  prismaClient.$use(async (params, next) => {
    return {
      id: "foo",
      name: "hoge"
    } as Task
  })
  return prismaClient
}

test("Task test", async () => {
  const prismaClient = mockedPrismaClient()
  const task = await getTaskById(prismaClient, "foo")
  expect(task?.name).toBe("hoge")
})

$extendsを使う

$extensを使う場合、下記のような形になる。
$useの場合はグローバルなPrismaClientに影響を与えていたが、$extendsの場合は拡張したインスタンスのみが拡張される

const mockedPrismaClientWithExtend = () => {
  return new PrismaClient().$extends({
    query: {
      task: {
        async findUnique({ }) {
          return {
            id: "a",
            name: "hoge"
          } as Task
        }
      }
    }
  })
  return mockPrismaClient
}

test("Task test", async () => {
  const prismaClient = mockedPrismaClientWithExtend()
  const task = await getTaskById(prismaClient, "foo")
  expect(task?.name).toBe("hoge")
})

とりあえず全部null返したいみたいな場合は$allOperationsを使うと良い

const mockPrismaClient: PrismaClient = new PrismaClient().$extends({
  query: {
    $allOperations: async () => {
      return null
    },
  }
})

この$extends、型としてはPrismaClientの互換性がなくなってしまう。
今回はテスト内のモック目的で、特にメソッドが増えたりもしないので、@ts-ignoreで回避するので十分そうと判断した。

// @ts-ignore
const mockPrismaClient: PrismaClient = new PrismaClient().$extends({
  ...
})

個人的にアプリケーションのコード中に$extendsを使う予定はないのであまり深堀りしていないが、公式ドキュメントにはtypeofを利用した方法が記載されている

GitHubで編集を提案

Discussion