Quramy / jest-prisma

Jest environment for integrated testing with Prisma client

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

If an error occurs during transaction, processing cannot continue

hokaccha opened this issue · comments

When handling a unique constraint error, such as the following, executing a query after a unique constraint error occurs will result in an error.

// user.ts
import { PrismaClient } from "@prisma/client";

/**
 * Creates a user. Returns true if the creation succeeds or the user already exists.
 */
export async function ensureUser(
  prisma: PrismaClient,
  data: {
    id: number;
    name: string;
  }
): Promise<boolean> {
  try {
    await prisma.user.create({ data });
    return true;
  } catch (err: any) {
    const uniqConstraintFailed = err.code === "P2002";

    if (uniqConstraintFailed) {
      return true;
    } else {
      console.error(err);
      return false;
    }
  }
}
// user.test.ts
test("ensureUser", async () => {
  const data = { id: 1, name: "foo" };

  // succeed
  expect(await ensureUser(jestPrisma.client, data)).toBe(true);

  // succeed
  expect(await ensureUser(jestPrisma.client, data)).toBe(true);

  // fail
  expect(await jestPrisma.client.user.count()).toBe(1);
});
$ jest
 FAIL  ./app.test.ts
  User
    ✕ ensureUser (16 ms)

  ● User › ensureUser

    PrismaClientUnknownRequestError:
    Invalid `jestPrisma.client.user.count()` invocation in
    /path/to/app.test.ts:12:41

       9 const data = { id: 1, name: "foo" };
      10 expect(await ensureUser(jestPrisma.client, data)).toBe(true);
      11 expect(await ensureUser(jestPrisma.client, data)).toBe(true);
    → 12 expect(await jestPrisma.client.user.count(
    Error occurred during query execution:
    ConnectorError(ConnectorError { user_facing_error: None, kind: QueryError(PostgresError { code: "25P02", message: "current transaction is aborted, commands ignored until end of transaction block", severity: "ERROR", detail: None, column: None, hint: None }), transient: false })

I suspect this is due to PostgresSQL's limitation that if an error occurs during a transaction, subsequent queries cannot be issued.

@hokaccha Thanks for your reporting.

I reproduced this message.

And I can suppress the 25P02 error using nested transaction like this:

/* user.test.ts */
test("ensureUser", async () => {
  const data = { id: 1, name: "foo" };

  // succeed
  expect(await ensureUser(jestPrisma.client, data)).toBe(true);

  try {
    await jestPrisma.client.$transaction(async () => {
      // succeed
      expect(await ensureUser(jestPrisma.client, data)).toBe(true);
      throw new Error();
    });
  } catch {}

  expect(await jestPrisma.client.user.count()).toBe(1);
});
/* jest.config.mjs */
export default {
  testEnvironment: "@quramy/jest-prisma-node/environment",
  testEnvironmentOptions: {
    enableExperimentalRollbackInTransaction: true, // Enable nested $transaction in test code
  },
};

Here is full example: https://github.com/Quramy/jest-prisma-repro-141/pull/1/files .

And I can suppress the 25P02 error using nested transaction.

I see, it seems like this problem can be solved this way. Thank you.

As far as I'm concerned, it's okay to close this issue, but I'll leave the decision up to you 🙏

it's okay to close this issue, but I'll leave the decision up to you

Thanks. I'll write about this problem and the workaround to README's tips section.