UNPKG

better-auth

Version:

The most comprehensive authentication library for TypeScript.

775 lines (771 loc) 22.8 kB
'use strict'; const vitest = require('vitest'); const id = require('../shared/better-auth.Bg6iw3ig.cjs'); require('zod'); require('better-call'); require('@better-auth/utils/hash'); require('@noble/ciphers/chacha'); require('@noble/ciphers/utils'); require('@noble/ciphers/webcrypto'); require('@better-auth/utils/base64'); require('jose'); require('@noble/hashes/scrypt'); require('@better-auth/utils'); require('@better-auth/utils/hex'); require('@noble/hashes/utils'); require('../shared/better-auth.CYeOI8C-.cjs'); require('../shared/better-auth.GpOOav9x.cjs'); require('@better-auth/utils/random'); const adapterTests = { CREATE_MODEL: "create model", CREATE_MODEL_SHOULD_ALWAYS_RETURN_AN_ID: "create model should always return an id", FIND_MODEL: "find model", FIND_MODEL_WITHOUT_ID: "find model without id", FIND_MODEL_WITH_SELECT: "find model with select", FIND_MODEL_WITH_MODIFIED_FIELD_NAME: "find model with modified field name", UPDATE_MODEL: "update model", SHOULD_FIND_MANY: "should find many", SHOULD_FIND_MANY_WITH_WHERE: "should find many with where", SHOULD_FIND_MANY_WITH_OPERATORS: "should find many with operators", SHOULD_WORK_WITH_REFERENCE_FIELDS: "should work with reference fields", SHOULD_FIND_MANY_WITH_SORT_BY: "should find many with sortBy", SHOULD_FIND_MANY_WITH_LIMIT: "should find many with limit", SHOULD_FIND_MANY_WITH_OFFSET: "should find many with offset", SHOULD_UPDATE_WITH_MULTIPLE_WHERE: "should update with multiple where", DELETE_MODEL: "delete model", SHOULD_DELETE_MANY: "should delete many", SHOULD_NOT_THROW_ON_DELETE_RECORD_NOT_FOUND: "shouldn't throw on delete record not found", SHOULD_NOT_THROW_ON_RECORD_NOT_FOUND: "shouldn't throw on record not found", SHOULD_FIND_MANY_WITH_CONTAINS_OPERATOR: "should find many with contains operator", SHOULD_SEARCH_USERS_WITH_STARTS_WITH: "should search users with startsWith", SHOULD_SEARCH_USERS_WITH_ENDS_WITH: "should search users with endsWith", SHOULD_PREFER_GENERATE_ID_IF_PROVIDED: "should prefer generateId if provided" }; const { ...numberIdAdapterTestsCopy } = adapterTests; const numberIdAdapterTests = { ...numberIdAdapterTestsCopy, SHOULD_RETURN_A_NUMBER_ID_AS_A_RESULT: "Should return a number id as a result", SHOULD_INCREMENT_THE_ID_BY_1: "Should increment the id by 1" }; delete numberIdAdapterTests.SHOULD_NOT_THROW_ON_DELETE_RECORD_NOT_FOUND; async function adapterTest({ getAdapter, disableTests: disabledTests, testPrefix }, internalOptions) { const adapter = async () => await getAdapter(internalOptions?.predefinedOptions); async function resetDebugLogs() { (await adapter())?.adapterTestDebugLogs?.resetDebugLogs(); } async function printDebugLogs() { (await adapter())?.adapterTestDebugLogs?.printDebugLogs(); } const user = { name: "user", email: "user@email.com", emailVerified: true, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() }; vitest.test.skipIf(disabledTests?.CREATE_MODEL)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.CREATE_MODEL}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).create({ model: "user", data: user }); user.id = res.id; vitest.expect({ name: res.name, email: res.email }).toEqual({ name: user.name, email: user.email }); } ); vitest.test.skipIf(disabledTests?.CREATE_MODEL_SHOULD_ALWAYS_RETURN_AN_ID)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.CREATE_MODEL_SHOULD_ALWAYS_RETURN_AN_ID}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).create({ model: "user", data: { name: "test-name-without-id", email: "test-email-without-id@email.com" } }); vitest.expect(res).toHaveProperty("id"); vitest.expect(typeof res?.id).toEqual("string"); } ); vitest.test.skipIf(disabledTests?.FIND_MODEL)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.FIND_MODEL}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).findOne({ model: "user", where: [ { field: "id", value: user.id } ] }); vitest.expect({ name: res?.name, email: res?.email }).toEqual({ name: user.name, email: user.email }); } ); vitest.test.skipIf(disabledTests?.FIND_MODEL_WITHOUT_ID)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.FIND_MODEL_WITHOUT_ID}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).findOne({ model: "user", where: [ { field: "email", value: user.email } ] }); vitest.expect({ name: res?.name, email: res?.email }).toEqual({ name: user.name, email: user.email }); } ); vitest.test.skipIf(disabledTests?.FIND_MODEL_WITH_MODIFIED_FIELD_NAME)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.FIND_MODEL_WITH_MODIFIED_FIELD_NAME}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const email = "test-email-with-modified-field@email.com"; const adapter2 = await getAdapter( Object.assign( { user: { fields: { email: "email_address" } } }, internalOptions?.predefinedOptions ) ); const user2 = await adapter2.create({ model: "user", data: { email, name: "test-name-with-modified-field", emailVerified: true, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() } }); vitest.expect(user2.email).toEqual(email); const res = await adapter2.findOne({ model: "user", where: [ { field: "email", value: email } ] }); vitest.expect(res).not.toBeNull(); vitest.expect(res?.email).toEqual(email); } ); vitest.test.skipIf(disabledTests?.FIND_MODEL_WITH_SELECT)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.FIND_MODEL_WITH_SELECT}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).findOne({ model: "user", where: [ { field: "id", value: user.id } ], select: ["email"] }); vitest.expect(res).toEqual({ email: user.email }); } ); vitest.test.skipIf(disabledTests?.UPDATE_MODEL)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.UPDATE_MODEL}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const newEmail = "updated@email.com"; const res = await (await adapter()).update({ model: "user", where: [ { field: "id", value: user.id } ], update: { email: newEmail } }); vitest.expect(res).toMatchObject({ email: newEmail, name: user.name }); } ); vitest.test.skipIf(disabledTests?.SHOULD_FIND_MANY)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_FIND_MANY}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).findMany({ model: "user" }); vitest.expect(res.length).toBe(3); } ); vitest.test.skipIf(disabledTests?.SHOULD_FIND_MANY_WITH_WHERE)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_FIND_MANY_WITH_WHERE}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const user2 = await (await adapter()).create({ model: "user", data: { name: "user2", email: "test@email.com", emailVerified: true, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() } }); const res = await (await adapter()).findMany({ model: "user", where: [ { field: "id", value: user2.id } ] }); vitest.expect(res.length).toBe(1); } ); vitest.test.skipIf(disabledTests?.SHOULD_FIND_MANY_WITH_OPERATORS)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_FIND_MANY_WITH_OPERATORS}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const newUser = await (await adapter()).create({ model: "user", data: { name: "user", email: "test-email2@email.com", emailVerified: true, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() } }); const res = await (await adapter()).findMany({ model: "user", where: [ { field: "id", operator: "in", value: [user.id, newUser.id] } ] }); vitest.expect(res.length).toBe(2); } ); vitest.test.skipIf(disabledTests?.SHOULD_WORK_WITH_REFERENCE_FIELDS)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_WORK_WITH_REFERENCE_FIELDS}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); let token = null; const user2 = await (await adapter()).create({ model: "user", data: { name: "user", email: "my-email@email.com", emailVerified: true, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() } }); const session = await (await adapter()).create({ model: "session", data: { token: id.generateId(), createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date(), userId: user2.id, expiresAt: /* @__PURE__ */ new Date() } }); token = session.token; const res = await (await adapter()).findOne({ model: "session", where: [ { field: "userId", value: user2.id } ] }); const resToken = await (await adapter()).findOne({ model: "session", where: [ { field: "token", value: token } ] }); vitest.expect(res).toMatchObject({ userId: user2.id }); vitest.expect(resToken).toMatchObject({ userId: user2.id }); } ); vitest.test.skipIf(disabledTests?.SHOULD_FIND_MANY_WITH_SORT_BY)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_FIND_MANY_WITH_SORT_BY}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); await (await adapter()).create({ model: "user", data: { name: "a", email: "a@email.com", emailVerified: true, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() } }); const res = await (await adapter()).findMany({ model: "user", sortBy: { field: "name", direction: "asc" } }); vitest.expect(res[0].name).toBe("a"); const res2 = await (await adapter()).findMany({ model: "user", sortBy: { field: "name", direction: "desc" } }); vitest.expect(res2[res2.length - 1].name).toBe("a"); } ); vitest.test.skipIf(disabledTests?.SHOULD_FIND_MANY_WITH_LIMIT)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_FIND_MANY_WITH_LIMIT}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).findMany({ model: "user", limit: 1 }); vitest.expect(res.length).toBe(1); } ); vitest.test.skipIf(disabledTests?.SHOULD_FIND_MANY_WITH_OFFSET)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_FIND_MANY_WITH_OFFSET}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).findMany({ model: "user", offset: 2 }); vitest.expect(res.length).toBe(5); } ); vitest.test.skipIf(disabledTests?.SHOULD_UPDATE_WITH_MULTIPLE_WHERE)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_UPDATE_WITH_MULTIPLE_WHERE}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); await (await adapter()).updateMany({ model: "user", where: [ { field: "name", value: user.name }, { field: "email", value: user.email } ], update: { email: "updated@email.com" } }); const updatedUser = await (await adapter()).findOne({ model: "user", where: [ { field: "email", value: "updated@email.com" } ] }); vitest.expect(updatedUser).toMatchObject({ name: user.name, email: "updated@email.com" }); } ); vitest.test.skipIf(disabledTests?.DELETE_MODEL)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.DELETE_MODEL}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); await (await adapter()).delete({ model: "user", where: [ { field: "id", value: user.id } ] }); const findRes = await (await adapter()).findOne({ model: "user", where: [ { field: "id", value: user.id } ] }); vitest.expect(findRes).toBeNull(); } ); vitest.test.skipIf(disabledTests?.SHOULD_DELETE_MANY)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_DELETE_MANY}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); for (const i of ["to-be-delete-1", "to-be-delete-2", "to-be-delete-3"]) { await (await adapter()).create({ model: "user", data: { name: "to-be-deleted", email: `email@test-${i}.com`, emailVerified: true, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() } }); } const findResFirst = await (await adapter()).findMany({ model: "user", where: [ { field: "name", value: "to-be-deleted" } ] }); vitest.expect(findResFirst.length).toBe(3); await (await adapter()).deleteMany({ model: "user", where: [ { field: "name", value: "to-be-deleted" } ] }); const findRes = await (await adapter()).findMany({ model: "user", where: [ { field: "name", value: "to-be-deleted" } ] }); vitest.expect(findRes.length).toBe(0); } ); vitest.test.skipIf(disabledTests?.SHOULD_NOT_THROW_ON_DELETE_RECORD_NOT_FOUND)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_NOT_THROW_ON_DELETE_RECORD_NOT_FOUND}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); await (await adapter()).delete({ model: "user", where: [ { field: "id", value: "100000" } ] }); } ); vitest.test.skipIf(disabledTests?.SHOULD_NOT_THROW_ON_RECORD_NOT_FOUND)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_NOT_THROW_ON_RECORD_NOT_FOUND}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).findOne({ model: "user", where: [ { field: "id", value: "100000" } ] }); vitest.expect(res).toBeNull(); } ); vitest.test.skipIf(disabledTests?.SHOULD_FIND_MANY_WITH_CONTAINS_OPERATOR)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_FIND_MANY_WITH_CONTAINS_OPERATOR}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).findMany({ model: "user", where: [ { field: "name", operator: "contains", value: "user2" } ] }); vitest.expect(res.length).toBe(1); } ); vitest.test.skipIf(disabledTests?.SHOULD_SEARCH_USERS_WITH_STARTS_WITH)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_SEARCH_USERS_WITH_STARTS_WITH}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).findMany({ model: "user", where: [ { field: "name", operator: "starts_with", value: "us" } ] }); vitest.expect(res.length).toBe(3); } ); vitest.test.skipIf(disabledTests?.SHOULD_SEARCH_USERS_WITH_ENDS_WITH)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_SEARCH_USERS_WITH_ENDS_WITH}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).findMany({ model: "user", where: [ { field: "name", operator: "ends_with", value: "er2" } ] }); vitest.expect(res.length).toBe(1); } ); vitest.test.skipIf(disabledTests?.SHOULD_PREFER_GENERATE_ID_IF_PROVIDED)( `${testPrefix ? `${testPrefix} - ` : ""}${adapterTests.SHOULD_PREFER_GENERATE_ID_IF_PROVIDED}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const customAdapter = await getAdapter( Object.assign( { advanced: { database: { generateId: () => "mocked-id" } } }, internalOptions?.predefinedOptions ) ); const res = await customAdapter.create({ model: "user", data: { name: "user4", email: "user4@email.com", emailVerified: true, createdAt: /* @__PURE__ */ new Date(), updatedAt: /* @__PURE__ */ new Date() } }); vitest.expect(res.id).toBe("mocked-id"); } ); } async function runAdapterTest(opts) { return adapterTest(opts); } async function runNumberIdAdapterTest(opts) { const cleanup = []; const adapter = async () => await opts.getAdapter({ advanced: { database: { useNumberId: true } } }); vitest.describe("Should run number id specific tests", async () => { let idNumber = -1; async function resetDebugLogs() { (await adapter())?.adapterTestDebugLogs?.resetDebugLogs(); } async function printDebugLogs() { (await adapter())?.adapterTestDebugLogs?.printDebugLogs(); } vitest.test.skipIf(opts.disableTests?.SHOULD_RETURN_A_NUMBER_ID_AS_A_RESULT)( `${opts.testPrefix ? `${opts.testPrefix} - ` : ""}${numberIdAdapterTests.SHOULD_RETURN_A_NUMBER_ID_AS_A_RESULT}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { printDebugLogs(); }); const res = await (await adapter()).create({ model: "user", data: { name: "user", email: "user@email.com" } }); cleanup.push({ modelName: "user", id: res.id }); vitest.expect(typeof res.id).toBe("string"); vitest.expect(parseInt(res.id)).toBeGreaterThan(0); idNumber = parseInt(res.id); } ); vitest.test.skipIf(opts.disableTests?.SHOULD_INCREMENT_THE_ID_BY_1)( `${opts.testPrefix ? `${opts.testPrefix} - ` : ""}${numberIdAdapterTests.SHOULD_INCREMENT_THE_ID_BY_1}`, async ({ onTestFailed }) => { resetDebugLogs(); onTestFailed(() => { console.log(`ID number from last create: ${idNumber}`); printDebugLogs(); }); const res = await (await adapter()).create({ model: "user", data: { name: "user2", email: "user2@email.com" } }); cleanup.push({ modelName: "user", id: res.id }); vitest.expect(parseInt(res.id)).toBe(idNumber + 1); } ); }); vitest.describe("Should run normal adapter tests with number id enabled", async () => { vitest.beforeAll(async () => { for (const { modelName, id } of cleanup) { await (await adapter()).delete({ model: modelName, where: [{ field: "id", value: id }] }); } }); await adapterTest( { ...opts, disableTests: { ...opts.disableTests, SHOULD_PREFER_GENERATE_ID_IF_PROVIDED: true } }, { predefinedOptions: { advanced: { database: { useNumberId: true } } } } ); }); } exports.runAdapterTest = runAdapterTest; exports.runNumberIdAdapterTest = runNumberIdAdapterTest;