@better-auth/test-utils 1.7.0-rc.1 → 1.7.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{create-test-suite.d.mts → adapter/create-test-suite.d.mts} +0 -1
- package/dist/{create-test-suite.mjs → adapter/create-test-suite.mjs} +3 -2
- package/dist/{suites → adapter/suites}/auth-flow.d.mts +4 -5
- package/dist/{suites → adapter/suites}/auth-flow.mjs +6 -6
- package/dist/{suites → adapter/suites}/basic.d.mts +10 -18
- package/dist/{suites → adapter/suites}/basic.mjs +57 -2
- package/dist/{suites → adapter/suites}/case-insensitive.d.mts +5 -8
- package/dist/{suites → adapter/suites}/index.d.mts +2 -1
- package/dist/adapter/suites/joins.d.mts +23 -0
- package/dist/{suites → adapter/suites}/joins.mjs +2 -2
- package/dist/adapter/suites/number-id.d.mts +23 -0
- package/dist/{suites → adapter/suites}/transactions.d.mts +4 -5
- package/dist/adapter/suites/uuid.d.mts +23 -0
- package/dist/{test-adapter.d.mts → adapter/test-adapter.d.mts} +1 -12
- package/dist/{test-adapter.mjs → adapter/test-adapter.mjs} +15 -11
- package/dist/adapter.d.mts +10 -9
- package/dist/adapter.mjs +9 -9
- package/dist/scim.d.mts +34 -0
- package/dist/scim.mjs +416 -0
- package/package.json +11 -6
- package/dist/suites/joins.d.mts +0 -24
- package/dist/suites/number-id.d.mts +0 -24
- package/dist/suites/uuid.d.mts +0 -24
- /package/dist/{suites → adapter/suites}/case-insensitive.mjs +0 -0
- /package/dist/{suites → adapter/suites}/number-id.mjs +0 -0
- /package/dist/{suites → adapter/suites}/transactions.mjs +0 -0
- /package/dist/{suites → adapter/suites}/uuid.mjs +0 -0
|
@@ -3,7 +3,6 @@ import { Account, Session, User, Verification } from "@better-auth/core/db";
|
|
|
3
3
|
import { DBAdapter } from "@better-auth/core/db/adapter";
|
|
4
4
|
import { Auth } from "better-auth";
|
|
5
5
|
import { BetterAuthOptions } from "@better-auth/core";
|
|
6
|
-
|
|
7
6
|
//#region src/adapter/create-test-suite.d.ts
|
|
8
7
|
/**
|
|
9
8
|
* Test entry type that supports both callback and object formats.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getAuthTables } from "@better-auth/core/db";
|
|
1
|
+
import { createLocalAccountIssuer, getAuthTables } from "@better-auth/core/db";
|
|
2
2
|
import { createAdapterFactory, deepmerge, initGetDefaultModelName } from "@better-auth/core/db/adapter";
|
|
3
3
|
import { TTY_COLORS } from "@better-auth/core/env";
|
|
4
4
|
import { generateId } from "@better-auth/core/utils/id";
|
|
@@ -229,7 +229,8 @@ const createTestSuite = (suiteName, config, tests) => {
|
|
|
229
229
|
id,
|
|
230
230
|
createdAt: randomDate,
|
|
231
231
|
updatedAt: /* @__PURE__ */ new Date(),
|
|
232
|
-
|
|
232
|
+
issuer: createLocalAccountIssuer("test"),
|
|
233
|
+
providerAccountId: generateId(),
|
|
233
234
|
providerId: "test",
|
|
234
235
|
userId: generateId(),
|
|
235
236
|
accessToken: generateId(),
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Logger } from "../test-adapter.mjs";
|
|
2
2
|
import { TestSuiteStats } from "../create-test-suite.mjs";
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import "../../adapter.mjs";
|
|
5
4
|
//#region src/adapter/suites/auth-flow.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* This test suite tests basic authentication flow using the adapter.
|
|
@@ -13,11 +12,11 @@ declare const authFlowTestSuite: (options?: ({
|
|
|
13
12
|
} & {
|
|
14
13
|
showDB?: () => Promise<void>;
|
|
15
14
|
}) | undefined) => (helpers: {
|
|
16
|
-
adapter: () => Promise<
|
|
15
|
+
adapter: () => Promise<import("better-auth").DBAdapter<import("better-auth").BetterAuthOptions>>;
|
|
17
16
|
log: Logger;
|
|
18
17
|
adapterDisplayName: string;
|
|
19
|
-
getBetterAuthOptions: () =>
|
|
20
|
-
modifyBetterAuthOptions: (options:
|
|
18
|
+
getBetterAuthOptions: () => import("better-auth").BetterAuthOptions;
|
|
19
|
+
modifyBetterAuthOptions: (options: import("better-auth").BetterAuthOptions) => Promise<import("better-auth").BetterAuthOptions>;
|
|
21
20
|
cleanup: () => Promise<void>;
|
|
22
21
|
runMigrations: () => Promise<void>;
|
|
23
22
|
prefixTests?: string | undefined;
|
|
@@ -24,8 +24,7 @@ const authFlowTestSuite = createTestSuite("auth-flow", { defaultBetterAuthOption
|
|
|
24
24
|
name: user.name,
|
|
25
25
|
image: user.image || ""
|
|
26
26
|
} });
|
|
27
|
-
|
|
28
|
-
console.log(`signUpEmail took ${end - start}ms (without hashing)`);
|
|
27
|
+
console.log(`signUpEmail took ${Date.now() - start}ms (without hashing)`);
|
|
29
28
|
expect(result.user).toBeDefined();
|
|
30
29
|
expect(result.user.email).toBe(user.email);
|
|
31
30
|
expect(result.user.name).toBe(user.name);
|
|
@@ -49,11 +48,13 @@ const authFlowTestSuite = createTestSuite("auth-flow", { defaultBetterAuthOption
|
|
|
49
48
|
email: user.email,
|
|
50
49
|
password
|
|
51
50
|
} });
|
|
52
|
-
|
|
53
|
-
console.log(`signInEmail took ${end - start}ms (without hashing)`);
|
|
51
|
+
console.log(`signInEmail took ${Date.now() - start}ms (without hashing)`);
|
|
54
52
|
expect(result.user).toBeDefined();
|
|
55
53
|
expect(result.user.id).toBe(signUpResult.user.id);
|
|
56
54
|
},
|
|
55
|
+
/**
|
|
56
|
+
* @see https://github.com/better-auth/better-auth/issues/10054
|
|
57
|
+
*/
|
|
57
58
|
"should reset password with a single-use token": async () => {
|
|
58
59
|
let resetToken = "";
|
|
59
60
|
await modifyBetterAuthOptions({ emailAndPassword: {
|
|
@@ -115,8 +116,7 @@ const authFlowTestSuite = createTestSuite("auth-flow", { defaultBetterAuthOption
|
|
|
115
116
|
setCookieToHeader(headers)({ response });
|
|
116
117
|
const start = Date.now();
|
|
117
118
|
const result = await auth.api.getSession({ headers });
|
|
118
|
-
|
|
119
|
-
console.log(`getSession took ${end - start}ms`);
|
|
119
|
+
console.log(`getSession took ${Date.now() - start}ms`);
|
|
120
120
|
const signUpResult = await response.json();
|
|
121
121
|
signUpResult.user.createdAt = new Date(signUpResult.user.createdAt);
|
|
122
122
|
signUpResult.user.updatedAt = new Date(signUpResult.user.updatedAt);
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { Logger } from "../test-adapter.mjs";
|
|
2
2
|
import { TestSuiteStats, createTestSuite } from "../create-test-suite.mjs";
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import "../../adapter.mjs";
|
|
5
4
|
//#region src/adapter/suites/basic.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* This test suite tests the basic CRUD operations of the adapter.
|
|
8
7
|
*/
|
|
9
8
|
declare const normalTestSuite: (options?: ({
|
|
10
|
-
disableTests?: Partial<Record<"init - tests" | "create - should create a model" | "create - should always return an id" | "create - should use generateId if provided" | "create - should return null for nullable foreign keys" | "create - should apply default values to fields" | "findOne - should find a model" | "findOne - should not apply defaultValue if value not found" | "findOne - should find a model using a reference field" | "findOne - should not throw on record not found" | "findOne - should find a model without id" | "findOne - should find a model with join" | "findOne - should find a model with modified field name" | "findOne - should find a model with modified model name" | "findOne - should find a model with additional fields" | "findOne - should select fields" | "findOne - should select fields with one-to-many join" | "findOne - should select fields with one-to-one join" | "findOne - should select fields with multiple joins" | "findOne - should find model with date field" | "findOne - should perform backwards joins" | "findOne - should return an object for one-to-one joins" | "findOne - should return an array for one-to-many joins" | "findOne - should work with both one-to-one and one-to-many joins" | "findOne - should return null for failed base model lookup that has joins" | "findOne - should join a model with modified field name" | "findMany - should find many models" | "findMany - should find many models with date fields" | "findMany - should find many models with join" | "findMany - should find many with join and limit" | "findMany - should select fields" | "findMany - should select fields with one-to-many join" | "findMany - should select fields with one-to-one join" | "findMany - should select fields with multiple joins" | "findMany - should find many with join and offset" | "findMany - should find many with join and sortBy" | "findMany - should find many with join and where clause" | "findMany - should find many with join, where, limit, and offset" | "findMany - should find many with one-to-one join" | "findMany - should find many with both one-to-one and one-to-many joins" | "findMany - should return an empty array when no models are found" | "findMany - should return empty array when base records don't exist with joins" | "findMany - should find many models with starts_with operator" | "findMany - starts_with should not interpret regex patterns" | "findMany - ends_with should not interpret regex patterns" | "findMany - contains should not interpret regex patterns" | "findMany - should find many models with ends_with operator" | "findMany - should find many models with contains operator" | "findMany - should handle multiple where conditions with different operators" | "findMany - should find many models with contains operator (using symbol)" | "findMany - should find many models with eq operator" | "findMany - should find many models with ne operator" | "findMany - should find many models with gt operator" | "findMany - should find many models with gte operator" | "findMany - should find many models with lte operator" | "findMany - should find many models with lt operator" | "findMany - should find many models with in operator" | "findMany - should find many models with not_in operator" | "findMany - should find many models with sortBy" | "findMany - should find many models with limit" | "findMany - should find many models with offset" | "findMany - should find many models with limit and offset" | "findMany - should find many models with sortBy and offset" | "findMany - should find many models with sortBy and limit" | "findMany - should find many models with sortBy and limit and offset" | "findMany - should find many models with sortBy and limit and offset and where" | "update - should update a model" | "update - should return null when where is empty" | "updateMany - should update all models when where is empty" | "updateMany - should update many models with a specific where" | "updateMany - should update many models with a multiple where" | "incrementOne - guarded set transition returns the row on a matching guard and null on a guard miss" | "delete - should delete a model" | "delete - should not throw on record not found" | "delete - should delete by non-unique field" | "deleteMany - should delete many models" | "deleteMany - starts_with should not interpret regex patterns" | "deleteMany - ends_with should not interpret regex patterns" | "deleteMany - contains should not interpret regex patterns" | "deleteMany - should delete many models with numeric values" | "deleteMany - should delete many models with boolean values" | "count - should count many models" | "count - should return 0 with no rows to count" | "count - should count with where clause" | "update - should correctly return record when updating a field used in where clause" | "update - should handle updating multiple fields including where clause field" | "update - should work when updated field is not in where clause" | "findOne - backwards join should only return single record not array" | "findMany - backwards join should only return single record not array" | "findOne - backwards join with modified field name (session base, users-table join)" | "findOne - multiple joins should return result even when some joined tables have no matching rows" | "findOne - should be able to perform a limited join" | "findOne - should be able to perform a complex limited join" | "findMany - should be able to perform a limited join" | "findMany - should be able to perform a complex limited join" | "findOne - should return null for one-to-one join when joined record doesn't exist" | "findMany - should return null for one-to-one join when joined records don't exist" | "findMany - should return empty array for one-to-many join when joined records don't exist" | "findMany - should handle mixed joins correctly when some are missing" | "create - should support arrays" | "create - should support json" | "update - should support multiple where conditions under AND connector with unique field" | "findMany - eq operator with null value (single condition) should use IS NULL" | "findMany - eq and ne operators with null value in AND group should use IS NULL / IS NOT NULL" | "findMany - eq and ne operators with null value in OR group should use IS NULL / IS NOT NULL" | "update - should return updated record when where condition uses null value" | "update - should return null when a multi-predicate where matches no row", boolean> & {
|
|
9
|
+
disableTests?: Partial<Record<"init - tests" | "create - should create a model" | "create - should always return an id" | "create - should enforce the issuer-scoped account identity key" | "create - should use generateId if provided" | "create - should return null for nullable foreign keys" | "create - should apply default values to fields" | "findOne - should find a model" | "findOne - should not apply defaultValue if value not found" | "findOne - should find a model using a reference field" | "findOne - should not throw on record not found" | "findOne - should find a model without id" | "findOne - should find a model with join" | "findOne - should find a model with modified field name" | "findOne - should find a model with modified model name" | "findOne - should find a model with additional fields" | "findOne - should select fields" | "findOne - should select fields with one-to-many join" | "findOne - should select fields with one-to-one join" | "findOne - should select fields with multiple joins" | "findOne - should find model with date field" | "findOne - should perform backwards joins" | "findOne - should return an object for one-to-one joins" | "findOne - should return an array for one-to-many joins" | "findOne - should work with both one-to-one and one-to-many joins" | "findOne - should return null for failed base model lookup that has joins" | "findOne - should join a model with modified field name" | "findMany - should find many models" | "findMany - should find many models with date fields" | "findMany - should find many models with join" | "findMany - should find many with join and limit" | "findMany - should select fields" | "findMany - should select fields with one-to-many join" | "findMany - should select fields with one-to-one join" | "findMany - should select fields with multiple joins" | "findMany - should find many with join and offset" | "findMany - should find many with join and sortBy" | "findMany - should find many with join and where clause" | "findMany - should find many with join, where, limit, and offset" | "findMany - should find many with one-to-one join" | "findMany - should find many with both one-to-one and one-to-many joins" | "findMany - should return an empty array when no models are found" | "findMany - should return empty array when base records don't exist with joins" | "findMany - should find many models with starts_with operator" | "findMany - starts_with should not interpret regex patterns" | "findMany - ends_with should not interpret regex patterns" | "findMany - contains should not interpret regex patterns" | "findMany - should find many models with ends_with operator" | "findMany - should find many models with contains operator" | "findMany - should handle multiple where conditions with different operators" | "findMany - should find many models with contains operator (using symbol)" | "findMany - should find many models with eq operator" | "findMany - should find many models with ne operator" | "findMany - should find many models with gt operator" | "findMany - should find many models with gte operator" | "findMany - should find many models with lte operator" | "findMany - should find many models with lt operator" | "findMany - should find many models with in operator" | "findMany - should find many models with not_in operator" | "findMany - should find many models with sortBy" | "findMany - should find many models with limit" | "findMany - should find many models with offset" | "findMany - should find many models with limit and offset" | "findMany - should find many models with sortBy and offset" | "findMany - should find many models with sortBy and limit" | "findMany - should find many models with sortBy and limit and offset" | "findMany - should find many models with sortBy and limit and offset and where" | "update - should update a model" | "update - should return null when where is empty" | "updateMany - should update all models when where is empty" | "updateMany - should update many models with a specific where" | "updateMany - should update many models with a multiple where" | "incrementOne - guarded set transition returns the row on a matching guard and null on a guard miss" | "delete - should delete a model" | "delete - should not throw on record not found" | "delete - should delete by non-unique field" | "deleteMany - should delete many models" | "deleteMany - starts_with should not interpret regex patterns" | "deleteMany - ends_with should not interpret regex patterns" | "deleteMany - contains should not interpret regex patterns" | "deleteMany - should delete many models with numeric values" | "deleteMany - should delete many models with boolean values" | "count - should count many models" | "count - should return 0 with no rows to count" | "count - should count with where clause" | "update - should correctly return record when updating a field used in where clause" | "update - should handle updating multiple fields including where clause field" | "update - should work when updated field is not in where clause" | "findOne - backwards join should only return single record not array" | "findMany - backwards join should only return single record not array" | "findOne - backwards join with modified field name (session base, users-table join)" | "findOne - multiple joins should return result even when some joined tables have no matching rows" | "findOne - should be able to perform a limited join" | "findOne - should be able to perform a complex limited join" | "findMany - should be able to perform a limited join" | "findMany - should be able to perform a complex limited join" | "findOne - should return null for one-to-one join when joined record doesn't exist" | "findMany - should return null for one-to-one join when joined records don't exist" | "findMany - should return empty array for one-to-many join when joined records don't exist" | "findMany - should handle mixed joins correctly when some are missing" | "create - should support arrays" | "create - should support json" | "update - should support multiple where conditions under AND connector with unique field" | "findMany - eq operator with null value (single condition) should use IS NULL" | "findMany - eq and ne operators with null value in AND group should use IS NULL / IS NOT NULL" | "findMany - eq and ne operators with null value in OR group should use IS NULL / IS NOT NULL" | "update - should return updated record when where condition uses null value" | "update - should return null when a multi-predicate where matches no row", boolean> & {
|
|
11
10
|
ALL?: boolean;
|
|
12
11
|
}> | undefined;
|
|
13
12
|
} & {
|
|
14
13
|
showDB?: () => Promise<void>;
|
|
15
14
|
}) | undefined) => (helpers: {
|
|
16
|
-
adapter: () => Promise<
|
|
15
|
+
adapter: () => Promise<import("better-auth").DBAdapter<import("better-auth").BetterAuthOptions>>;
|
|
17
16
|
log: Logger;
|
|
18
17
|
adapterDisplayName: string;
|
|
19
|
-
getBetterAuthOptions: () =>
|
|
20
|
-
modifyBetterAuthOptions: (options:
|
|
18
|
+
getBetterAuthOptions: () => import("better-auth").BetterAuthOptions;
|
|
19
|
+
modifyBetterAuthOptions: (options: import("better-auth").BetterAuthOptions) => Promise<import("better-auth").BetterAuthOptions>;
|
|
21
20
|
cleanup: () => Promise<void>;
|
|
22
21
|
runMigrations: () => Promise<void>;
|
|
23
22
|
prefixTests?: string | undefined;
|
|
@@ -25,21 +24,14 @@ declare const normalTestSuite: (options?: ({
|
|
|
25
24
|
customIdGenerator?: (() => any | Promise<any> | undefined) | undefined;
|
|
26
25
|
transformIdOutput?: ((id: any) => string | undefined) | undefined;
|
|
27
26
|
}) => Promise<void>;
|
|
28
|
-
declare const getNormalTestSuiteTests: ({
|
|
29
|
-
adapter,
|
|
30
|
-
generate,
|
|
31
|
-
insertRandom,
|
|
32
|
-
modifyBetterAuthOptions,
|
|
33
|
-
sortModels,
|
|
34
|
-
customIdGenerator,
|
|
35
|
-
getBetterAuthOptions,
|
|
36
|
-
transformGeneratedModel,
|
|
37
|
-
transformIdOutput
|
|
38
|
-
}: Parameters<Parameters<typeof createTestSuite>[2]>[0], debugTools?: {
|
|
27
|
+
declare const getNormalTestSuiteTests: ({ adapter, generate, insertRandom, modifyBetterAuthOptions, sortModels, customIdGenerator, getBetterAuthOptions, transformGeneratedModel, transformIdOutput }: Parameters<Parameters<typeof createTestSuite>[2]>[0], debugTools?: {
|
|
39
28
|
showDB?: () => Promise<void>;
|
|
40
29
|
}) => {
|
|
41
30
|
"create - should create a model": () => Promise<void>;
|
|
42
31
|
"create - should always return an id": () => Promise<void>;
|
|
32
|
+
"create - should enforce the issuer-scoped account identity key": ({ skip }: {
|
|
33
|
+
skip: (note?: string | undefined) => never;
|
|
34
|
+
}) => Promise<void>;
|
|
43
35
|
"create - should use generateId if provided": () => Promise<void>;
|
|
44
36
|
"create - should return null for nullable foreign keys": {
|
|
45
37
|
migrateBetterAuth: {
|
|
@@ -207,6 +199,6 @@ declare const getNormalTestSuiteTests: ({
|
|
|
207
199
|
"update - should return updated record when where condition uses null value": () => Promise<void>;
|
|
208
200
|
"update - should return null when a multi-predicate where matches no row": () => Promise<void>;
|
|
209
201
|
};
|
|
210
|
-
declare const enableJoinTests: Partial<Record<"create - should create a model" | "create - should always return an id" | "create - should use generateId if provided" | "create - should return null for nullable foreign keys" | "create - should apply default values to fields" | "findOne - should find a model" | "findOne - should not apply defaultValue if value not found" | "findOne - should find a model using a reference field" | "findOne - should not throw on record not found" | "findOne - should find a model without id" | "findOne - should find a model with join" | "findOne - should find a model with modified field name" | "findOne - should find a model with modified model name" | "findOne - should find a model with additional fields" | "findOne - should select fields" | "findOne - should select fields with one-to-many join" | "findOne - should select fields with one-to-one join" | "findOne - should select fields with multiple joins" | "findOne - should find model with date field" | "findOne - should perform backwards joins" | "findOne - should return an object for one-to-one joins" | "findOne - should return an array for one-to-many joins" | "findOne - should work with both one-to-one and one-to-many joins" | "findOne - should return null for failed base model lookup that has joins" | "findOne - should join a model with modified field name" | "findMany - should find many models" | "findMany - should find many models with date fields" | "findMany - should find many models with join" | "findMany - should find many with join and limit" | "findMany - should select fields" | "findMany - should select fields with one-to-many join" | "findMany - should select fields with one-to-one join" | "findMany - should select fields with multiple joins" | "findMany - should find many with join and offset" | "findMany - should find many with join and sortBy" | "findMany - should find many with join and where clause" | "findMany - should find many with join, where, limit, and offset" | "findMany - should find many with one-to-one join" | "findMany - should find many with both one-to-one and one-to-many joins" | "findMany - should return an empty array when no models are found" | "findMany - should return empty array when base records don't exist with joins" | "findMany - should find many models with starts_with operator" | "findMany - starts_with should not interpret regex patterns" | "findMany - ends_with should not interpret regex patterns" | "findMany - contains should not interpret regex patterns" | "findMany - should find many models with ends_with operator" | "findMany - should find many models with contains operator" | "findMany - should handle multiple where conditions with different operators" | "findMany - should find many models with contains operator (using symbol)" | "findMany - should find many models with eq operator" | "findMany - should find many models with ne operator" | "findMany - should find many models with gt operator" | "findMany - should find many models with gte operator" | "findMany - should find many models with lte operator" | "findMany - should find many models with lt operator" | "findMany - should find many models with in operator" | "findMany - should find many models with not_in operator" | "findMany - should find many models with sortBy" | "findMany - should find many models with limit" | "findMany - should find many models with offset" | "findMany - should find many models with limit and offset" | "findMany - should find many models with sortBy and offset" | "findMany - should find many models with sortBy and limit" | "findMany - should find many models with sortBy and limit and offset" | "findMany - should find many models with sortBy and limit and offset and where" | "update - should update a model" | "update - should return null when where is empty" | "updateMany - should update all models when where is empty" | "updateMany - should update many models with a specific where" | "updateMany - should update many models with a multiple where" | "incrementOne - guarded set transition returns the row on a matching guard and null on a guard miss" | "delete - should delete a model" | "delete - should not throw on record not found" | "delete - should delete by non-unique field" | "deleteMany - should delete many models" | "deleteMany - starts_with should not interpret regex patterns" | "deleteMany - ends_with should not interpret regex patterns" | "deleteMany - contains should not interpret regex patterns" | "deleteMany - should delete many models with numeric values" | "deleteMany - should delete many models with boolean values" | "count - should count many models" | "count - should return 0 with no rows to count" | "count - should count with where clause" | "update - should correctly return record when updating a field used in where clause" | "update - should handle updating multiple fields including where clause field" | "update - should work when updated field is not in where clause" | "findOne - backwards join should only return single record not array" | "findMany - backwards join should only return single record not array" | "findOne - backwards join with modified field name (session base, users-table join)" | "findOne - multiple joins should return result even when some joined tables have no matching rows" | "findOne - should be able to perform a limited join" | "findOne - should be able to perform a complex limited join" | "findMany - should be able to perform a limited join" | "findMany - should be able to perform a complex limited join" | "findOne - should return null for one-to-one join when joined record doesn't exist" | "findMany - should return null for one-to-one join when joined records don't exist" | "findMany - should return empty array for one-to-many join when joined records don't exist" | "findMany - should handle mixed joins correctly when some are missing" | "create - should support arrays" | "create - should support json" | "update - should support multiple where conditions under AND connector with unique field" | "findMany - eq operator with null value (single condition) should use IS NULL" | "findMany - eq and ne operators with null value in AND group should use IS NULL / IS NOT NULL" | "findMany - eq and ne operators with null value in OR group should use IS NULL / IS NOT NULL" | "update - should return updated record when where condition uses null value" | "update - should return null when a multi-predicate where matches no row", boolean>>;
|
|
202
|
+
declare const enableJoinTests: Partial<Record<"create - should create a model" | "create - should always return an id" | "create - should enforce the issuer-scoped account identity key" | "create - should use generateId if provided" | "create - should return null for nullable foreign keys" | "create - should apply default values to fields" | "findOne - should find a model" | "findOne - should not apply defaultValue if value not found" | "findOne - should find a model using a reference field" | "findOne - should not throw on record not found" | "findOne - should find a model without id" | "findOne - should find a model with join" | "findOne - should find a model with modified field name" | "findOne - should find a model with modified model name" | "findOne - should find a model with additional fields" | "findOne - should select fields" | "findOne - should select fields with one-to-many join" | "findOne - should select fields with one-to-one join" | "findOne - should select fields with multiple joins" | "findOne - should find model with date field" | "findOne - should perform backwards joins" | "findOne - should return an object for one-to-one joins" | "findOne - should return an array for one-to-many joins" | "findOne - should work with both one-to-one and one-to-many joins" | "findOne - should return null for failed base model lookup that has joins" | "findOne - should join a model with modified field name" | "findMany - should find many models" | "findMany - should find many models with date fields" | "findMany - should find many models with join" | "findMany - should find many with join and limit" | "findMany - should select fields" | "findMany - should select fields with one-to-many join" | "findMany - should select fields with one-to-one join" | "findMany - should select fields with multiple joins" | "findMany - should find many with join and offset" | "findMany - should find many with join and sortBy" | "findMany - should find many with join and where clause" | "findMany - should find many with join, where, limit, and offset" | "findMany - should find many with one-to-one join" | "findMany - should find many with both one-to-one and one-to-many joins" | "findMany - should return an empty array when no models are found" | "findMany - should return empty array when base records don't exist with joins" | "findMany - should find many models with starts_with operator" | "findMany - starts_with should not interpret regex patterns" | "findMany - ends_with should not interpret regex patterns" | "findMany - contains should not interpret regex patterns" | "findMany - should find many models with ends_with operator" | "findMany - should find many models with contains operator" | "findMany - should handle multiple where conditions with different operators" | "findMany - should find many models with contains operator (using symbol)" | "findMany - should find many models with eq operator" | "findMany - should find many models with ne operator" | "findMany - should find many models with gt operator" | "findMany - should find many models with gte operator" | "findMany - should find many models with lte operator" | "findMany - should find many models with lt operator" | "findMany - should find many models with in operator" | "findMany - should find many models with not_in operator" | "findMany - should find many models with sortBy" | "findMany - should find many models with limit" | "findMany - should find many models with offset" | "findMany - should find many models with limit and offset" | "findMany - should find many models with sortBy and offset" | "findMany - should find many models with sortBy and limit" | "findMany - should find many models with sortBy and limit and offset" | "findMany - should find many models with sortBy and limit and offset and where" | "update - should update a model" | "update - should return null when where is empty" | "updateMany - should update all models when where is empty" | "updateMany - should update many models with a specific where" | "updateMany - should update many models with a multiple where" | "incrementOne - guarded set transition returns the row on a matching guard and null on a guard miss" | "delete - should delete a model" | "delete - should not throw on record not found" | "delete - should delete by non-unique field" | "deleteMany - should delete many models" | "deleteMany - starts_with should not interpret regex patterns" | "deleteMany - ends_with should not interpret regex patterns" | "deleteMany - contains should not interpret regex patterns" | "deleteMany - should delete many models with numeric values" | "deleteMany - should delete many models with boolean values" | "count - should count many models" | "count - should return 0 with no rows to count" | "count - should count with where clause" | "update - should correctly return record when updating a field used in where clause" | "update - should handle updating multiple fields including where clause field" | "update - should work when updated field is not in where clause" | "findOne - backwards join should only return single record not array" | "findMany - backwards join should only return single record not array" | "findOne - backwards join with modified field name (session base, users-table join)" | "findOne - multiple joins should return result even when some joined tables have no matching rows" | "findOne - should be able to perform a limited join" | "findOne - should be able to perform a complex limited join" | "findMany - should be able to perform a limited join" | "findMany - should be able to perform a complex limited join" | "findOne - should return null for one-to-one join when joined record doesn't exist" | "findMany - should return null for one-to-one join when joined records don't exist" | "findMany - should return empty array for one-to-many join when joined records don't exist" | "findMany - should handle mixed joins correctly when some are missing" | "create - should support arrays" | "create - should support json" | "update - should support multiple where conditions under AND connector with unique field" | "findMany - eq operator with null value (single condition) should use IS NULL" | "findMany - eq and ne operators with null value in AND group should use IS NULL / IS NOT NULL" | "findMany - eq and ne operators with null value in OR group should use IS NULL / IS NOT NULL" | "update - should return updated record when where condition uses null value" | "update - should return null when a multi-predicate where matches no row", boolean>>;
|
|
211
203
|
//#endregion
|
|
212
204
|
export { enableJoinTests, getNormalTestSuiteTests, normalTestSuite };
|
|
@@ -6,12 +6,11 @@ import { organization } from "better-auth/plugins/organization";
|
|
|
6
6
|
* This test suite tests the basic CRUD operations of the adapter.
|
|
7
7
|
*/
|
|
8
8
|
const normalTestSuite = createTestSuite("normal", {}, (helpers, debugTools) => {
|
|
9
|
-
const tests = getNormalTestSuiteTests(helpers, debugTools);
|
|
10
9
|
return {
|
|
11
10
|
"init - tests": async () => {
|
|
12
11
|
expect(helpers.getBetterAuthOptions().advanced?.database?.generateId !== "serial").toBeTruthy();
|
|
13
12
|
},
|
|
14
|
-
...
|
|
13
|
+
...getNormalTestSuiteTests(helpers, debugTools)
|
|
15
14
|
};
|
|
16
15
|
});
|
|
17
16
|
const getNormalTestSuiteTests = ({ adapter, generate, insertRandom, modifyBetterAuthOptions, sortModels, customIdGenerator, getBetterAuthOptions, transformGeneratedModel, transformIdOutput }, debugTools) => {
|
|
@@ -38,6 +37,59 @@ const getNormalTestSuiteTests = ({ adapter, generate, insertRandom, modifyBetter
|
|
|
38
37
|
expect(res).toHaveProperty("id");
|
|
39
38
|
expect(typeof res.id).toEqual("string");
|
|
40
39
|
},
|
|
40
|
+
"create - should enforce the issuer-scoped account identity key": async ({ skip }) => {
|
|
41
|
+
if (adapter.options?.adapterConfig.adapterId === "memory") {
|
|
42
|
+
skip("The memory adapter does not implement database indexes");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const firstUser = await adapter.create({
|
|
46
|
+
model: "user",
|
|
47
|
+
data: await generate("user"),
|
|
48
|
+
forceAllowId: true
|
|
49
|
+
});
|
|
50
|
+
const secondUser = await adapter.create({
|
|
51
|
+
model: "user",
|
|
52
|
+
data: await generate("user"),
|
|
53
|
+
forceAllowId: true
|
|
54
|
+
});
|
|
55
|
+
const firstAccount = {
|
|
56
|
+
...await generate("account"),
|
|
57
|
+
userId: firstUser.id,
|
|
58
|
+
providerId: "issuer-key-first-alias",
|
|
59
|
+
issuer: "https://issuer-key.example.com",
|
|
60
|
+
providerAccountId: "shared-subject"
|
|
61
|
+
};
|
|
62
|
+
await adapter.create({
|
|
63
|
+
model: "account",
|
|
64
|
+
data: firstAccount,
|
|
65
|
+
forceAllowId: true
|
|
66
|
+
});
|
|
67
|
+
await expect(adapter.create({
|
|
68
|
+
model: "account",
|
|
69
|
+
data: {
|
|
70
|
+
...await generate("account"),
|
|
71
|
+
userId: secondUser.id,
|
|
72
|
+
providerId: "issuer-key-second-alias",
|
|
73
|
+
issuer: firstAccount.issuer,
|
|
74
|
+
providerAccountId: firstAccount.providerAccountId
|
|
75
|
+
},
|
|
76
|
+
forceAllowId: true
|
|
77
|
+
})).rejects.toThrow();
|
|
78
|
+
await expect(adapter.create({
|
|
79
|
+
model: "account",
|
|
80
|
+
data: {
|
|
81
|
+
...await generate("account"),
|
|
82
|
+
userId: secondUser.id,
|
|
83
|
+
providerId: "issuer-key-other-issuer",
|
|
84
|
+
issuer: "https://other-issuer-key.example.com",
|
|
85
|
+
providerAccountId: firstAccount.providerAccountId
|
|
86
|
+
},
|
|
87
|
+
forceAllowId: true
|
|
88
|
+
})).resolves.toMatchObject({
|
|
89
|
+
issuer: "https://other-issuer-key.example.com",
|
|
90
|
+
providerAccountId: "shared-subject"
|
|
91
|
+
});
|
|
92
|
+
},
|
|
41
93
|
"create - should use generateId if provided": async () => {
|
|
42
94
|
const ID = await customIdGenerator?.() || "MOCK-ID";
|
|
43
95
|
await modifyBetterAuthOptions({ advanced: { database: { generateId: () => ID } } }, false);
|
|
@@ -1843,6 +1895,9 @@ const getNormalTestSuiteTests = ({ adapter, generate, insertRandom, modifyBetter
|
|
|
1843
1895
|
}]
|
|
1844
1896
|
})).resolves.not.toThrow();
|
|
1845
1897
|
},
|
|
1898
|
+
/**
|
|
1899
|
+
* @see https://github.com/better-auth/better-auth/issues/8313
|
|
1900
|
+
*/
|
|
1846
1901
|
"delete - should delete by non-unique field": async () => {
|
|
1847
1902
|
const [verification] = await insertRandom("verification");
|
|
1848
1903
|
await adapter.delete({
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import * as better_auth0 from "better-auth";
|
|
2
|
-
import * as _better_auth_test_utils_adapter0 from "@better-auth/test-utils/adapter";
|
|
3
|
-
|
|
4
1
|
//#region src/adapter/suites/case-insensitive.d.ts
|
|
5
2
|
/**
|
|
6
3
|
* Test suite for case-insensitive string operations across adapters.
|
|
@@ -11,15 +8,15 @@ declare const caseInsensitiveTestSuite: (options?: {
|
|
|
11
8
|
ALL?: boolean;
|
|
12
9
|
}> | undefined;
|
|
13
10
|
} | undefined) => (helpers: {
|
|
14
|
-
adapter: () => Promise<
|
|
15
|
-
log:
|
|
11
|
+
adapter: () => Promise<import("better-auth").DBAdapter<import("better-auth").BetterAuthOptions>>;
|
|
12
|
+
log: import("@better-auth/test-utils/adapter").Logger;
|
|
16
13
|
adapterDisplayName: string;
|
|
17
|
-
getBetterAuthOptions: () =>
|
|
18
|
-
modifyBetterAuthOptions: (options:
|
|
14
|
+
getBetterAuthOptions: () => import("better-auth").BetterAuthOptions;
|
|
15
|
+
modifyBetterAuthOptions: (options: import("better-auth").BetterAuthOptions) => Promise<import("better-auth").BetterAuthOptions>;
|
|
19
16
|
cleanup: () => Promise<void>;
|
|
20
17
|
runMigrations: () => Promise<void>;
|
|
21
18
|
prefixTests?: string | undefined;
|
|
22
|
-
onTestFinish: (stats:
|
|
19
|
+
onTestFinish: (stats: import("@better-auth/test-utils/adapter").TestSuiteStats) => Promise<void>;
|
|
23
20
|
customIdGenerator?: (() => any | Promise<any> | undefined) | undefined;
|
|
24
21
|
transformIdOutput?: ((id: any) => string | undefined) | undefined;
|
|
25
22
|
}) => Promise<void>;
|
|
@@ -4,4 +4,5 @@ import { caseInsensitiveTestSuite } from "./case-insensitive.mjs";
|
|
|
4
4
|
import { joinsTestSuite } from "./joins.mjs";
|
|
5
5
|
import { numberIdTestSuite } from "./number-id.mjs";
|
|
6
6
|
import { transactionsTestSuite } from "./transactions.mjs";
|
|
7
|
-
import { uuidTestSuite } from "./uuid.mjs";
|
|
7
|
+
import { uuidTestSuite } from "./uuid.mjs";
|
|
8
|
+
export { authFlowTestSuite, caseInsensitiveTestSuite, enableJoinTests, getNormalTestSuiteTests, joinsTestSuite, normalTestSuite, numberIdTestSuite, transactionsTestSuite, uuidTestSuite };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Logger } from "../test-adapter.mjs";
|
|
2
|
+
import { TestSuiteStats } from "../create-test-suite.mjs";
|
|
3
|
+
import "../../adapter.mjs";
|
|
4
|
+
//#region src/adapter/suites/joins.d.ts
|
|
5
|
+
declare const joinsTestSuite: (options?: {
|
|
6
|
+
disableTests?: Partial<Record<"init - tests" | "create - should create a model" | "create - should always return an id" | "create - should enforce the issuer-scoped account identity key" | "create - should return null for nullable foreign keys" | "create - should apply default values to fields" | "findOne - should find a model" | "findOne - should not apply defaultValue if value not found" | "findOne - should find a model using a reference field" | "findOne - should not throw on record not found" | "findOne - should find a model without id" | "findOne - should find a model with join" | "findOne - should find a model with modified field name" | "findOne - should find a model with modified model name" | "findOne - should find a model with additional fields" | "findOne - should select fields" | "findOne - should select fields with one-to-many join" | "findOne - should select fields with one-to-one join" | "findOne - should select fields with multiple joins" | "findOne - should find model with date field" | "findOne - should perform backwards joins" | "findOne - should return an object for one-to-one joins" | "findOne - should return an array for one-to-many joins" | "findOne - should work with both one-to-one and one-to-many joins" | "findOne - should return null for failed base model lookup that has joins" | "findOne - should join a model with modified field name" | "findMany - should find many models" | "findMany - should find many models with date fields" | "findMany - should find many models with join" | "findMany - should find many with join and limit" | "findMany - should select fields" | "findMany - should select fields with one-to-many join" | "findMany - should select fields with one-to-one join" | "findMany - should select fields with multiple joins" | "findMany - should find many with join and offset" | "findMany - should find many with join and sortBy" | "findMany - should find many with join and where clause" | "findMany - should find many with join, where, limit, and offset" | "findMany - should find many with one-to-one join" | "findMany - should find many with both one-to-one and one-to-many joins" | "findMany - should return an empty array when no models are found" | "findMany - should return empty array when base records don't exist with joins" | "findMany - should find many models with starts_with operator" | "findMany - starts_with should not interpret regex patterns" | "findMany - ends_with should not interpret regex patterns" | "findMany - contains should not interpret regex patterns" | "findMany - should find many models with ends_with operator" | "findMany - should find many models with contains operator" | "findMany - should handle multiple where conditions with different operators" | "findMany - should find many models with contains operator (using symbol)" | "findMany - should find many models with eq operator" | "findMany - should find many models with ne operator" | "findMany - should find many models with gt operator" | "findMany - should find many models with gte operator" | "findMany - should find many models with lte operator" | "findMany - should find many models with lt operator" | "findMany - should find many models with in operator" | "findMany - should find many models with not_in operator" | "findMany - should find many models with sortBy" | "findMany - should find many models with limit" | "findMany - should find many models with offset" | "findMany - should find many models with limit and offset" | "findMany - should find many models with sortBy and offset" | "findMany - should find many models with sortBy and limit" | "findMany - should find many models with sortBy and limit and offset" | "findMany - should find many models with sortBy and limit and offset and where" | "update - should update a model" | "update - should return null when where is empty" | "updateMany - should update all models when where is empty" | "updateMany - should update many models with a specific where" | "updateMany - should update many models with a multiple where" | "incrementOne - guarded set transition returns the row on a matching guard and null on a guard miss" | "delete - should delete a model" | "delete - should not throw on record not found" | "delete - should delete by non-unique field" | "deleteMany - should delete many models" | "deleteMany - starts_with should not interpret regex patterns" | "deleteMany - ends_with should not interpret regex patterns" | "deleteMany - contains should not interpret regex patterns" | "deleteMany - should delete many models with numeric values" | "deleteMany - should delete many models with boolean values" | "count - should count many models" | "count - should return 0 with no rows to count" | "count - should count with where clause" | "update - should correctly return record when updating a field used in where clause" | "update - should handle updating multiple fields including where clause field" | "update - should work when updated field is not in where clause" | "findOne - backwards join should only return single record not array" | "findMany - backwards join should only return single record not array" | "findOne - backwards join with modified field name (session base, users-table join)" | "findOne - multiple joins should return result even when some joined tables have no matching rows" | "findOne - should be able to perform a limited join" | "findOne - should be able to perform a complex limited join" | "findMany - should be able to perform a limited join" | "findMany - should be able to perform a complex limited join" | "findOne - should return null for one-to-one join when joined record doesn't exist" | "findMany - should return null for one-to-one join when joined records don't exist" | "findMany - should return empty array for one-to-many join when joined records don't exist" | "findMany - should handle mixed joins correctly when some are missing" | "create - should support arrays" | "create - should support json" | "update - should support multiple where conditions under AND connector with unique field" | "findMany - eq operator with null value (single condition) should use IS NULL" | "findMany - eq and ne operators with null value in AND group should use IS NULL / IS NOT NULL" | "findMany - eq and ne operators with null value in OR group should use IS NULL / IS NOT NULL" | "update - should return updated record when where condition uses null value" | "update - should return null when a multi-predicate where matches no row", boolean> & {
|
|
7
|
+
ALL?: boolean;
|
|
8
|
+
}> | undefined;
|
|
9
|
+
} | undefined) => (helpers: {
|
|
10
|
+
adapter: () => Promise<import("better-auth").DBAdapter<import("better-auth").BetterAuthOptions>>;
|
|
11
|
+
log: Logger;
|
|
12
|
+
adapterDisplayName: string;
|
|
13
|
+
getBetterAuthOptions: () => import("better-auth").BetterAuthOptions;
|
|
14
|
+
modifyBetterAuthOptions: (options: import("better-auth").BetterAuthOptions) => Promise<import("better-auth").BetterAuthOptions>;
|
|
15
|
+
cleanup: () => Promise<void>;
|
|
16
|
+
runMigrations: () => Promise<void>;
|
|
17
|
+
prefixTests?: string | undefined;
|
|
18
|
+
onTestFinish: (stats: TestSuiteStats) => Promise<void>;
|
|
19
|
+
customIdGenerator?: (() => any | Promise<any> | undefined) | undefined;
|
|
20
|
+
transformIdOutput?: ((id: any) => string | undefined) | undefined;
|
|
21
|
+
}) => Promise<void>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { joinsTestSuite };
|
|
@@ -3,14 +3,14 @@ import { getNormalTestSuiteTests } from "./basic.mjs";
|
|
|
3
3
|
import { expect } from "vitest";
|
|
4
4
|
//#region src/adapter/suites/joins.ts
|
|
5
5
|
const joinsTestSuite = createTestSuite("joins", {
|
|
6
|
-
defaultBetterAuthOptions: {
|
|
6
|
+
defaultBetterAuthOptions: { advanced: { database: { joins: true } } },
|
|
7
7
|
alwaysMigrate: true,
|
|
8
8
|
prefixTests: "joins"
|
|
9
9
|
}, (helpers) => {
|
|
10
10
|
const { "create - should use generateId if provided": _, ...normalTests } = getNormalTestSuiteTests({ ...helpers });
|
|
11
11
|
return {
|
|
12
12
|
"init - tests": async () => {
|
|
13
|
-
expect(helpers.getBetterAuthOptions().
|
|
13
|
+
expect(helpers.getBetterAuthOptions().advanced?.database?.joins).toBe(true);
|
|
14
14
|
},
|
|
15
15
|
...normalTests
|
|
16
16
|
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Logger } from "../test-adapter.mjs";
|
|
2
|
+
import { TestSuiteStats } from "../create-test-suite.mjs";
|
|
3
|
+
import "../../adapter.mjs";
|
|
4
|
+
//#region src/adapter/suites/number-id.d.ts
|
|
5
|
+
declare const numberIdTestSuite: (options?: {
|
|
6
|
+
disableTests?: Partial<Record<"init - tests" | "create - should create a model" | "create - should always return an id" | "create - should enforce the issuer-scoped account identity key" | "create - should return null for nullable foreign keys" | "create - should apply default values to fields" | "findOne - should find a model" | "findOne - should not apply defaultValue if value not found" | "findOne - should find a model using a reference field" | "findOne - should not throw on record not found" | "findOne - should find a model without id" | "findOne - should find a model with join" | "findOne - should find a model with modified field name" | "findOne - should find a model with modified model name" | "findOne - should find a model with additional fields" | "findOne - should select fields" | "findOne - should select fields with one-to-many join" | "findOne - should select fields with one-to-one join" | "findOne - should select fields with multiple joins" | "findOne - should find model with date field" | "findOne - should perform backwards joins" | "findOne - should return an object for one-to-one joins" | "findOne - should return an array for one-to-many joins" | "findOne - should work with both one-to-one and one-to-many joins" | "findOne - should return null for failed base model lookup that has joins" | "findOne - should join a model with modified field name" | "findMany - should find many models" | "findMany - should find many models with date fields" | "findMany - should find many models with join" | "findMany - should find many with join and limit" | "findMany - should select fields" | "findMany - should select fields with one-to-many join" | "findMany - should select fields with one-to-one join" | "findMany - should select fields with multiple joins" | "findMany - should find many with join and offset" | "findMany - should find many with join and sortBy" | "findMany - should find many with join and where clause" | "findMany - should find many with join, where, limit, and offset" | "findMany - should find many with one-to-one join" | "findMany - should find many with both one-to-one and one-to-many joins" | "findMany - should return an empty array when no models are found" | "findMany - should return empty array when base records don't exist with joins" | "findMany - should find many models with starts_with operator" | "findMany - starts_with should not interpret regex patterns" | "findMany - ends_with should not interpret regex patterns" | "findMany - contains should not interpret regex patterns" | "findMany - should find many models with ends_with operator" | "findMany - should find many models with contains operator" | "findMany - should handle multiple where conditions with different operators" | "findMany - should find many models with contains operator (using symbol)" | "findMany - should find many models with eq operator" | "findMany - should find many models with ne operator" | "findMany - should find many models with gt operator" | "findMany - should find many models with gte operator" | "findMany - should find many models with lte operator" | "findMany - should find many models with lt operator" | "findMany - should find many models with in operator" | "findMany - should find many models with not_in operator" | "findMany - should find many models with sortBy" | "findMany - should find many models with limit" | "findMany - should find many models with offset" | "findMany - should find many models with limit and offset" | "findMany - should find many models with sortBy and offset" | "findMany - should find many models with sortBy and limit" | "findMany - should find many models with sortBy and limit and offset" | "findMany - should find many models with sortBy and limit and offset and where" | "update - should update a model" | "update - should return null when where is empty" | "updateMany - should update all models when where is empty" | "updateMany - should update many models with a specific where" | "updateMany - should update many models with a multiple where" | "incrementOne - guarded set transition returns the row on a matching guard and null on a guard miss" | "delete - should delete a model" | "delete - should not throw on record not found" | "delete - should delete by non-unique field" | "deleteMany - should delete many models" | "deleteMany - starts_with should not interpret regex patterns" | "deleteMany - ends_with should not interpret regex patterns" | "deleteMany - contains should not interpret regex patterns" | "deleteMany - should delete many models with numeric values" | "deleteMany - should delete many models with boolean values" | "count - should count many models" | "count - should return 0 with no rows to count" | "count - should count with where clause" | "update - should correctly return record when updating a field used in where clause" | "update - should handle updating multiple fields including where clause field" | "update - should work when updated field is not in where clause" | "findOne - backwards join should only return single record not array" | "findMany - backwards join should only return single record not array" | "findOne - backwards join with modified field name (session base, users-table join)" | "findOne - multiple joins should return result even when some joined tables have no matching rows" | "findOne - should be able to perform a limited join" | "findOne - should be able to perform a complex limited join" | "findMany - should be able to perform a limited join" | "findMany - should be able to perform a complex limited join" | "findOne - should return null for one-to-one join when joined record doesn't exist" | "findMany - should return null for one-to-one join when joined records don't exist" | "findMany - should return empty array for one-to-many join when joined records don't exist" | "findMany - should handle mixed joins correctly when some are missing" | "create - should support arrays" | "create - should support json" | "update - should support multiple where conditions under AND connector with unique field" | "findMany - eq operator with null value (single condition) should use IS NULL" | "findMany - eq and ne operators with null value in AND group should use IS NULL / IS NOT NULL" | "findMany - eq and ne operators with null value in OR group should use IS NULL / IS NOT NULL" | "update - should return updated record when where condition uses null value" | "update - should return null when a multi-predicate where matches no row" | "create - should return a number id", boolean> & {
|
|
7
|
+
ALL?: boolean;
|
|
8
|
+
}> | undefined;
|
|
9
|
+
} | undefined) => (helpers: {
|
|
10
|
+
adapter: () => Promise<import("better-auth").DBAdapter<import("better-auth").BetterAuthOptions>>;
|
|
11
|
+
log: Logger;
|
|
12
|
+
adapterDisplayName: string;
|
|
13
|
+
getBetterAuthOptions: () => import("better-auth").BetterAuthOptions;
|
|
14
|
+
modifyBetterAuthOptions: (options: import("better-auth").BetterAuthOptions) => Promise<import("better-auth").BetterAuthOptions>;
|
|
15
|
+
cleanup: () => Promise<void>;
|
|
16
|
+
runMigrations: () => Promise<void>;
|
|
17
|
+
prefixTests?: string | undefined;
|
|
18
|
+
onTestFinish: (stats: TestSuiteStats) => Promise<void>;
|
|
19
|
+
customIdGenerator?: (() => any | Promise<any> | undefined) | undefined;
|
|
20
|
+
transformIdOutput?: ((id: any) => string | undefined) | undefined;
|
|
21
|
+
}) => Promise<void>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { numberIdTestSuite };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Logger } from "../test-adapter.mjs";
|
|
2
2
|
import { TestSuiteStats } from "../create-test-suite.mjs";
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import "../../adapter.mjs";
|
|
5
4
|
//#region src/adapter/suites/transactions.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* This test suite tests the transaction functionality of the adapter.
|
|
@@ -11,11 +10,11 @@ declare const transactionsTestSuite: (options?: {
|
|
|
11
10
|
ALL?: boolean;
|
|
12
11
|
}> | undefined;
|
|
13
12
|
} | undefined) => (helpers: {
|
|
14
|
-
adapter: () => Promise<
|
|
13
|
+
adapter: () => Promise<import("better-auth").DBAdapter<import("better-auth").BetterAuthOptions>>;
|
|
15
14
|
log: Logger;
|
|
16
15
|
adapterDisplayName: string;
|
|
17
|
-
getBetterAuthOptions: () =>
|
|
18
|
-
modifyBetterAuthOptions: (options:
|
|
16
|
+
getBetterAuthOptions: () => import("better-auth").BetterAuthOptions;
|
|
17
|
+
modifyBetterAuthOptions: (options: import("better-auth").BetterAuthOptions) => Promise<import("better-auth").BetterAuthOptions>;
|
|
19
18
|
cleanup: () => Promise<void>;
|
|
20
19
|
runMigrations: () => Promise<void>;
|
|
21
20
|
prefixTests?: string | undefined;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Logger } from "../test-adapter.mjs";
|
|
2
|
+
import { TestSuiteStats } from "../create-test-suite.mjs";
|
|
3
|
+
import "../../adapter.mjs";
|
|
4
|
+
//#region src/adapter/suites/uuid.d.ts
|
|
5
|
+
declare const uuidTestSuite: (options?: {
|
|
6
|
+
disableTests?: Partial<Record<"init - tests" | "create - should create a model" | "create - should always return an id" | "create - should enforce the issuer-scoped account identity key" | "create - should return null for nullable foreign keys" | "create - should apply default values to fields" | "findOne - should find a model" | "findOne - should not apply defaultValue if value not found" | "findOne - should find a model using a reference field" | "findOne - should not throw on record not found" | "findOne - should find a model without id" | "findOne - should find a model with join" | "findOne - should find a model with modified field name" | "findOne - should find a model with modified model name" | "findOne - should find a model with additional fields" | "findOne - should select fields" | "findOne - should select fields with one-to-many join" | "findOne - should select fields with one-to-one join" | "findOne - should select fields with multiple joins" | "findOne - should find model with date field" | "findOne - should perform backwards joins" | "findOne - should return an object for one-to-one joins" | "findOne - should return an array for one-to-many joins" | "findOne - should work with both one-to-one and one-to-many joins" | "findOne - should return null for failed base model lookup that has joins" | "findOne - should join a model with modified field name" | "findMany - should find many models" | "findMany - should find many models with date fields" | "findMany - should find many models with join" | "findMany - should find many with join and limit" | "findMany - should select fields" | "findMany - should select fields with one-to-many join" | "findMany - should select fields with one-to-one join" | "findMany - should select fields with multiple joins" | "findMany - should find many with join and offset" | "findMany - should find many with join and sortBy" | "findMany - should find many with join and where clause" | "findMany - should find many with join, where, limit, and offset" | "findMany - should find many with one-to-one join" | "findMany - should find many with both one-to-one and one-to-many joins" | "findMany - should return an empty array when no models are found" | "findMany - should return empty array when base records don't exist with joins" | "findMany - should find many models with starts_with operator" | "findMany - starts_with should not interpret regex patterns" | "findMany - ends_with should not interpret regex patterns" | "findMany - contains should not interpret regex patterns" | "findMany - should find many models with ends_with operator" | "findMany - should find many models with contains operator" | "findMany - should handle multiple where conditions with different operators" | "findMany - should find many models with contains operator (using symbol)" | "findMany - should find many models with eq operator" | "findMany - should find many models with ne operator" | "findMany - should find many models with gt operator" | "findMany - should find many models with gte operator" | "findMany - should find many models with lte operator" | "findMany - should find many models with lt operator" | "findMany - should find many models with in operator" | "findMany - should find many models with not_in operator" | "findMany - should find many models with sortBy" | "findMany - should find many models with limit" | "findMany - should find many models with offset" | "findMany - should find many models with limit and offset" | "findMany - should find many models with sortBy and offset" | "findMany - should find many models with sortBy and limit" | "findMany - should find many models with sortBy and limit and offset" | "findMany - should find many models with sortBy and limit and offset and where" | "update - should update a model" | "update - should return null when where is empty" | "updateMany - should update all models when where is empty" | "updateMany - should update many models with a specific where" | "updateMany - should update many models with a multiple where" | "incrementOne - guarded set transition returns the row on a matching guard and null on a guard miss" | "delete - should delete a model" | "delete - should not throw on record not found" | "delete - should delete by non-unique field" | "deleteMany - should delete many models" | "deleteMany - starts_with should not interpret regex patterns" | "deleteMany - ends_with should not interpret regex patterns" | "deleteMany - contains should not interpret regex patterns" | "deleteMany - should delete many models with numeric values" | "deleteMany - should delete many models with boolean values" | "count - should count many models" | "count - should return 0 with no rows to count" | "count - should count with where clause" | "update - should correctly return record when updating a field used in where clause" | "update - should handle updating multiple fields including where clause field" | "update - should work when updated field is not in where clause" | "findOne - backwards join should only return single record not array" | "findMany - backwards join should only return single record not array" | "findOne - backwards join with modified field name (session base, users-table join)" | "findOne - multiple joins should return result even when some joined tables have no matching rows" | "findOne - should be able to perform a limited join" | "findOne - should be able to perform a complex limited join" | "findMany - should be able to perform a limited join" | "findMany - should be able to perform a complex limited join" | "findOne - should return null for one-to-one join when joined record doesn't exist" | "findMany - should return null for one-to-one join when joined records don't exist" | "findMany - should return empty array for one-to-many join when joined records don't exist" | "findMany - should handle mixed joins correctly when some are missing" | "create - should support arrays" | "create - should support json" | "update - should support multiple where conditions under AND connector with unique field" | "findMany - eq operator with null value (single condition) should use IS NULL" | "findMany - eq and ne operators with null value in AND group should use IS NULL / IS NOT NULL" | "findMany - eq and ne operators with null value in OR group should use IS NULL / IS NOT NULL" | "update - should return updated record when where condition uses null value" | "update - should return null when a multi-predicate where matches no row" | "create - should return a uuid" | "findOne - should find a model using a uuid", boolean> & {
|
|
7
|
+
ALL?: boolean;
|
|
8
|
+
}> | undefined;
|
|
9
|
+
} | undefined) => (helpers: {
|
|
10
|
+
adapter: () => Promise<import("better-auth").DBAdapter<import("better-auth").BetterAuthOptions>>;
|
|
11
|
+
log: Logger;
|
|
12
|
+
adapterDisplayName: string;
|
|
13
|
+
getBetterAuthOptions: () => import("better-auth").BetterAuthOptions;
|
|
14
|
+
modifyBetterAuthOptions: (options: import("better-auth").BetterAuthOptions) => Promise<import("better-auth").BetterAuthOptions>;
|
|
15
|
+
cleanup: () => Promise<void>;
|
|
16
|
+
runMigrations: () => Promise<void>;
|
|
17
|
+
prefixTests?: string | undefined;
|
|
18
|
+
onTestFinish: (stats: TestSuiteStats) => Promise<void>;
|
|
19
|
+
customIdGenerator?: (() => any | Promise<any> | undefined) | undefined;
|
|
20
|
+
transformIdOutput?: ((id: any) => string | undefined) | undefined;
|
|
21
|
+
}) => Promise<void>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { uuidTestSuite };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { createTestSuite } from "./create-test-suite.mjs";
|
|
2
2
|
import { DBAdapter } from "@better-auth/core/db/adapter";
|
|
3
3
|
import { Awaitable, BetterAuthOptions } from "@better-auth/core";
|
|
4
|
-
|
|
5
4
|
//#region src/adapter/test-adapter.d.ts
|
|
6
5
|
type Logger = {
|
|
7
6
|
info: (...args: any[]) => void;
|
|
@@ -10,17 +9,7 @@ type Logger = {
|
|
|
10
9
|
error: (...args: any[]) => void;
|
|
11
10
|
debug: (...args: any[]) => void;
|
|
12
11
|
};
|
|
13
|
-
declare const testAdapter: ({
|
|
14
|
-
adapter: getAdapter,
|
|
15
|
-
runMigrations,
|
|
16
|
-
overrideBetterAuthOptions,
|
|
17
|
-
additionalCleanups,
|
|
18
|
-
tests,
|
|
19
|
-
prefixTests,
|
|
20
|
-
onFinish,
|
|
21
|
-
customIdGenerator,
|
|
22
|
-
transformIdOutput
|
|
23
|
-
}: {
|
|
12
|
+
declare const testAdapter: ({ adapter: getAdapter, runMigrations, overrideBetterAuthOptions, additionalCleanups, tests, prefixTests, onFinish, customIdGenerator, transformIdOutput }: {
|
|
24
13
|
/**
|
|
25
14
|
* A function that will return the adapter instance to test with.
|
|
26
15
|
*
|
|
@@ -5,10 +5,12 @@ import { getAuthTables } from "better-auth/db";
|
|
|
5
5
|
//#region src/adapter/test-adapter.ts
|
|
6
6
|
const testAdapter = async ({ adapter: getAdapter, runMigrations, overrideBetterAuthOptions, additionalCleanups, tests, prefixTests, onFinish, customIdGenerator, transformIdOutput }) => {
|
|
7
7
|
const defaultBAOptions = {};
|
|
8
|
-
let betterAuthOptions = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
let betterAuthOptions = (() => {
|
|
9
|
+
return {
|
|
10
|
+
...defaultBAOptions,
|
|
11
|
+
...overrideBetterAuthOptions?.(defaultBAOptions) || {}
|
|
12
|
+
};
|
|
13
|
+
})();
|
|
12
14
|
let adapter = (await getAdapter(betterAuthOptions))(betterAuthOptions);
|
|
13
15
|
const adapterName = adapter.options?.adapterConfig.adapterName;
|
|
14
16
|
const adapterId = adapter.options?.adapterConfig.adapterId || adapter.id;
|
|
@@ -19,13 +21,15 @@ const testAdapter = async ({ adapter: getAdapter, runMigrations, overrideBetterA
|
|
|
19
21
|
/**
|
|
20
22
|
* A helper function to log to the console.
|
|
21
23
|
*/
|
|
22
|
-
const log = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
const log = (() => {
|
|
25
|
+
return {
|
|
26
|
+
info: (...args) => console.log(`${TTY_COLORS.fg.blue}INFO ${TTY_COLORS.reset} [${adapterDisplayName}]`, ...args),
|
|
27
|
+
success: (...args) => console.log(`${TTY_COLORS.fg.green}SUCCESS${TTY_COLORS.reset} [${adapterDisplayName}]`, ...args),
|
|
28
|
+
warn: (...args) => console.log(`${TTY_COLORS.fg.yellow}WARN ${TTY_COLORS.reset} [${adapterDisplayName}]`, ...args),
|
|
29
|
+
error: (...args) => console.log(`${TTY_COLORS.fg.red}ERROR ${TTY_COLORS.reset} [${adapterDisplayName}]`, ...args),
|
|
30
|
+
debug: (...args) => console.log(`${TTY_COLORS.fg.magenta}DEBUG ${TTY_COLORS.reset} [${adapterDisplayName}]`, ...args)
|
|
31
|
+
};
|
|
32
|
+
})();
|
|
29
33
|
/**
|
|
30
34
|
* Cleanup function to remove all rows from the database.
|
|
31
35
|
*/
|
package/dist/adapter.d.mts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { Logger, testAdapter } from "./test-adapter.mjs";
|
|
2
|
-
import { InsertRandomFn, TestEntry, TestSuiteStats, createTestSuite } from "./create-test-suite.mjs";
|
|
3
|
-
import { authFlowTestSuite } from "./suites/auth-flow.mjs";
|
|
4
|
-
import { enableJoinTests, getNormalTestSuiteTests, normalTestSuite } from "./suites/basic.mjs";
|
|
5
|
-
import { caseInsensitiveTestSuite } from "./suites/case-insensitive.mjs";
|
|
6
|
-
import { joinsTestSuite } from "./suites/joins.mjs";
|
|
7
|
-
import { numberIdTestSuite } from "./suites/number-id.mjs";
|
|
8
|
-
import { transactionsTestSuite } from "./suites/transactions.mjs";
|
|
9
|
-
import { uuidTestSuite } from "./suites/uuid.mjs";
|
|
1
|
+
import { Logger, testAdapter } from "./adapter/test-adapter.mjs";
|
|
2
|
+
import { InsertRandomFn, TestEntry, TestSuiteStats, createTestSuite } from "./adapter/create-test-suite.mjs";
|
|
3
|
+
import { authFlowTestSuite } from "./adapter/suites/auth-flow.mjs";
|
|
4
|
+
import { enableJoinTests, getNormalTestSuiteTests, normalTestSuite } from "./adapter/suites/basic.mjs";
|
|
5
|
+
import { caseInsensitiveTestSuite } from "./adapter/suites/case-insensitive.mjs";
|
|
6
|
+
import { joinsTestSuite } from "./adapter/suites/joins.mjs";
|
|
7
|
+
import { numberIdTestSuite } from "./adapter/suites/number-id.mjs";
|
|
8
|
+
import { transactionsTestSuite } from "./adapter/suites/transactions.mjs";
|
|
9
|
+
import { uuidTestSuite } from "./adapter/suites/uuid.mjs";
|
|
10
|
+
import "./adapter/suites/index.mjs";
|
|
10
11
|
export { type InsertRandomFn, type Logger, type TestEntry, type TestSuiteStats, authFlowTestSuite, caseInsensitiveTestSuite, createTestSuite, enableJoinTests, getNormalTestSuiteTests, joinsTestSuite, normalTestSuite, numberIdTestSuite, testAdapter, transactionsTestSuite, uuidTestSuite };
|
package/dist/adapter.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { createTestSuite } from "./create-test-suite.mjs";
|
|
2
|
-
import { authFlowTestSuite } from "./suites/auth-flow.mjs";
|
|
3
|
-
import { enableJoinTests, getNormalTestSuiteTests, normalTestSuite } from "./suites/basic.mjs";
|
|
4
|
-
import { caseInsensitiveTestSuite } from "./suites/case-insensitive.mjs";
|
|
5
|
-
import { joinsTestSuite } from "./suites/joins.mjs";
|
|
6
|
-
import { numberIdTestSuite } from "./suites/number-id.mjs";
|
|
7
|
-
import { transactionsTestSuite } from "./suites/transactions.mjs";
|
|
8
|
-
import { uuidTestSuite } from "./suites/uuid.mjs";
|
|
9
|
-
import { testAdapter } from "./test-adapter.mjs";
|
|
1
|
+
import { createTestSuite } from "./adapter/create-test-suite.mjs";
|
|
2
|
+
import { authFlowTestSuite } from "./adapter/suites/auth-flow.mjs";
|
|
3
|
+
import { enableJoinTests, getNormalTestSuiteTests, normalTestSuite } from "./adapter/suites/basic.mjs";
|
|
4
|
+
import { caseInsensitiveTestSuite } from "./adapter/suites/case-insensitive.mjs";
|
|
5
|
+
import { joinsTestSuite } from "./adapter/suites/joins.mjs";
|
|
6
|
+
import { numberIdTestSuite } from "./adapter/suites/number-id.mjs";
|
|
7
|
+
import { transactionsTestSuite } from "./adapter/suites/transactions.mjs";
|
|
8
|
+
import { uuidTestSuite } from "./adapter/suites/uuid.mjs";
|
|
9
|
+
import { testAdapter } from "./adapter/test-adapter.mjs";
|
|
10
10
|
export { authFlowTestSuite, caseInsensitiveTestSuite, createTestSuite, enableJoinTests, getNormalTestSuiteTests, joinsTestSuite, normalTestSuite, numberIdTestSuite, testAdapter, transactionsTestSuite, uuidTestSuite };
|
package/dist/scim.d.mts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/scim-lifecycle.d.ts
|
|
2
|
+
/** Observable lifecycle boundaries for database and application-state oracles. */
|
|
3
|
+
type SCIMLifecycleCheckpoint = "group-created" | "failed-add-rolled-back" | "member-added" | "okta-member-removed" | "entra-member-removed" | "member-restored" | "user-deactivated" | "user-reactivated" | "populated-user-deleted" | "user-reprovisioned" | "reprovisioned-member-added" | "populated-group-deleted" | "lifecycle-complete";
|
|
4
|
+
/** Input for the reusable SCIM black-box lifecycle contract. */
|
|
5
|
+
interface SCIMLifecycleOptions {
|
|
6
|
+
/** Better Auth origin exposed by a real HTTP listener. */
|
|
7
|
+
baseURL: string;
|
|
8
|
+
/** Bearer credential for the SCIM connection under test. */
|
|
9
|
+
token: string;
|
|
10
|
+
/** Stable suffix that isolates resources created by this execution. */
|
|
11
|
+
testId: string;
|
|
12
|
+
/** Optional harness control used to prove a failed Group mutation rolls back. */
|
|
13
|
+
projectionFailure?: {
|
|
14
|
+
enable: () => void;
|
|
15
|
+
disable: () => void;
|
|
16
|
+
};
|
|
17
|
+
/** Optional out-of-band oracle invoked after each verified HTTP boundary. */
|
|
18
|
+
onCheckpoint?: (checkpoint: SCIMLifecycleCheckpoint) => void | Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/** Identifiers created and deleted by a completed SCIM lifecycle. */
|
|
21
|
+
interface SCIMLifecycleResult {
|
|
22
|
+
userId: string;
|
|
23
|
+
groupId: string;
|
|
24
|
+
reprovisionedUserId: string;
|
|
25
|
+
userLocation: string;
|
|
26
|
+
groupLocation: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Executes one provider-shaped SCIM User and Group lifecycle exclusively over
|
|
30
|
+
* HTTP. The runner has no access to Better Auth APIs or database internals.
|
|
31
|
+
*/
|
|
32
|
+
declare function runSCIMLifecycle(options: SCIMLifecycleOptions): Promise<SCIMLifecycleResult>;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { SCIMLifecycleCheckpoint, SCIMLifecycleOptions, SCIMLifecycleResult, runSCIMLifecycle };
|
package/dist/scim.mjs
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
import { expect } from "vitest";
|
|
2
|
+
//#region src/scim-lifecycle.ts
|
|
3
|
+
const SCIM_MEDIA_TYPE = "application/scim+json";
|
|
4
|
+
const SCIM_USER_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:User";
|
|
5
|
+
const SCIM_GROUP_SCHEMA = "urn:ietf:params:scim:schemas:core:2.0:Group";
|
|
6
|
+
const SCIM_PATCH_SCHEMA = "urn:ietf:params:scim:api:messages:2.0:PatchOp";
|
|
7
|
+
const SCIM_LIST_SCHEMA = "urn:ietf:params:scim:api:messages:2.0:ListResponse";
|
|
8
|
+
const SCIM_ERROR_SCHEMA = "urn:ietf:params:scim:api:messages:2.0:Error";
|
|
9
|
+
async function readJson(response) {
|
|
10
|
+
return await response.json();
|
|
11
|
+
}
|
|
12
|
+
function expectSCIMResponse(response, status) {
|
|
13
|
+
expect(response.status).toBe(status);
|
|
14
|
+
if (status === 204) return;
|
|
15
|
+
expect(response.headers.get("content-type")?.split(";", 1)[0]).toBe(SCIM_MEDIA_TYPE);
|
|
16
|
+
}
|
|
17
|
+
async function expectSCIMErrorResponse(response, status) {
|
|
18
|
+
expectSCIMResponse(response, status);
|
|
19
|
+
const body = await readJson(response);
|
|
20
|
+
expect(body).toMatchObject({
|
|
21
|
+
schemas: [SCIM_ERROR_SCHEMA],
|
|
22
|
+
status: status.toString()
|
|
23
|
+
});
|
|
24
|
+
return body;
|
|
25
|
+
}
|
|
26
|
+
async function expectSCIMNoContent(response) {
|
|
27
|
+
expectSCIMResponse(response, 204);
|
|
28
|
+
expect(await response.text()).toBe("");
|
|
29
|
+
}
|
|
30
|
+
function createSCIMRequest(baseURL, token) {
|
|
31
|
+
return async (path, init = {}) => {
|
|
32
|
+
const headers = new Headers({
|
|
33
|
+
accept: SCIM_MEDIA_TYPE,
|
|
34
|
+
authorization: `Bearer ${token}`
|
|
35
|
+
});
|
|
36
|
+
if (init.body !== void 0) headers.set("content-type", SCIM_MEDIA_TYPE);
|
|
37
|
+
return fetch(`${baseURL}${path}`, {
|
|
38
|
+
method: init.method ?? "GET",
|
|
39
|
+
headers,
|
|
40
|
+
body: init.body === void 0 ? void 0 : JSON.stringify(init.body)
|
|
41
|
+
});
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function userFilterPath(userName) {
|
|
45
|
+
return `/Users?${new URLSearchParams({ filter: `userName eq "${userName}"` }).toString()}`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Executes one provider-shaped SCIM User and Group lifecycle exclusively over
|
|
49
|
+
* HTTP. The runner has no access to Better Auth APIs or database internals.
|
|
50
|
+
*/
|
|
51
|
+
async function runSCIMLifecycle(options) {
|
|
52
|
+
const scimBaseURL = `${options.baseURL.replace(/\/$/, "")}/api/auth/scim/v2`;
|
|
53
|
+
const request = createSCIMRequest(scimBaseURL, options.token);
|
|
54
|
+
const checkpoint = async (value) => {
|
|
55
|
+
await options.onCheckpoint?.(value);
|
|
56
|
+
};
|
|
57
|
+
const userName = `${options.testId}.user@example.com`;
|
|
58
|
+
const email = `${options.testId}.primary@example.com`;
|
|
59
|
+
const userExternalId = `${options.testId}-directory-user`;
|
|
60
|
+
const groupExternalId = `${options.testId}-finance-admins`;
|
|
61
|
+
const userCreateBody = {
|
|
62
|
+
schemas: [SCIM_USER_SCHEMA],
|
|
63
|
+
externalId: userExternalId,
|
|
64
|
+
userName,
|
|
65
|
+
name: {
|
|
66
|
+
formatted: "Ada Lovelace",
|
|
67
|
+
givenName: "Ada",
|
|
68
|
+
familyName: "Lovelace"
|
|
69
|
+
},
|
|
70
|
+
displayName: "Ada Lovelace",
|
|
71
|
+
active: true,
|
|
72
|
+
emails: [{
|
|
73
|
+
value: email,
|
|
74
|
+
type: "work",
|
|
75
|
+
primary: true
|
|
76
|
+
}]
|
|
77
|
+
};
|
|
78
|
+
const unauthorized = await fetch(`${scimBaseURL}/Users`, { headers: { accept: SCIM_MEDIA_TYPE } });
|
|
79
|
+
await expectSCIMErrorResponse(unauthorized, 401);
|
|
80
|
+
expect(unauthorized.headers.get("www-authenticate")).toBe("Bearer realm=\"SCIM\"");
|
|
81
|
+
const discoveryResponse = await fetch(`${scimBaseURL}/ServiceProviderConfig`, { headers: { accept: SCIM_MEDIA_TYPE } });
|
|
82
|
+
expectSCIMResponse(discoveryResponse, 200);
|
|
83
|
+
expect(await readJson(discoveryResponse)).toMatchObject({
|
|
84
|
+
patch: { supported: true },
|
|
85
|
+
filter: { supported: true },
|
|
86
|
+
meta: {
|
|
87
|
+
resourceType: "ServiceProviderConfig",
|
|
88
|
+
location: `${scimBaseURL}/ServiceProviderConfig`
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const initialListResponse = await request(userFilterPath(userName));
|
|
92
|
+
expectSCIMResponse(initialListResponse, 200);
|
|
93
|
+
expect(await readJson(initialListResponse)).toMatchObject({
|
|
94
|
+
schemas: [SCIM_LIST_SCHEMA],
|
|
95
|
+
totalResults: 0,
|
|
96
|
+
Resources: []
|
|
97
|
+
});
|
|
98
|
+
const createUserResponse = await request("/Users", {
|
|
99
|
+
method: "POST",
|
|
100
|
+
body: userCreateBody
|
|
101
|
+
});
|
|
102
|
+
expectSCIMResponse(createUserResponse, 201);
|
|
103
|
+
const createdUser = await readJson(createUserResponse);
|
|
104
|
+
const userLocation = `${scimBaseURL}/Users/${encodeURIComponent(createdUser.id)}`;
|
|
105
|
+
expect(createdUser).toMatchObject({
|
|
106
|
+
schemas: [SCIM_USER_SCHEMA],
|
|
107
|
+
externalId: userExternalId,
|
|
108
|
+
userName,
|
|
109
|
+
displayName: "Ada Lovelace",
|
|
110
|
+
active: true,
|
|
111
|
+
meta: {
|
|
112
|
+
resourceType: "User",
|
|
113
|
+
location: userLocation
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
expect(createUserResponse.headers.get("location")).toBe(userLocation);
|
|
117
|
+
expect(createUserResponse.headers.get("content-location")).toBe(userLocation);
|
|
118
|
+
const populatedListResponse = await request(userFilterPath(userName));
|
|
119
|
+
expectSCIMResponse(populatedListResponse, 200);
|
|
120
|
+
expect(await readJson(populatedListResponse)).toMatchObject({
|
|
121
|
+
totalResults: 1,
|
|
122
|
+
itemsPerPage: 1,
|
|
123
|
+
Resources: [{ id: createdUser.id }]
|
|
124
|
+
});
|
|
125
|
+
const replaceUserResponse = await request(`/Users/${encodeURIComponent(createdUser.id)}`, {
|
|
126
|
+
method: "PUT",
|
|
127
|
+
body: {
|
|
128
|
+
schemas: [SCIM_USER_SCHEMA],
|
|
129
|
+
externalId: userExternalId,
|
|
130
|
+
userName,
|
|
131
|
+
name: {
|
|
132
|
+
formatted: "Ada Byron",
|
|
133
|
+
givenName: "Ada",
|
|
134
|
+
familyName: "Byron"
|
|
135
|
+
},
|
|
136
|
+
displayName: "Ada Byron",
|
|
137
|
+
active: true,
|
|
138
|
+
emails: [{
|
|
139
|
+
value: email,
|
|
140
|
+
type: "work",
|
|
141
|
+
primary: true
|
|
142
|
+
}]
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
expectSCIMResponse(replaceUserResponse, 200);
|
|
146
|
+
expect(await readJson(replaceUserResponse)).toMatchObject({
|
|
147
|
+
id: createdUser.id,
|
|
148
|
+
externalId: userExternalId,
|
|
149
|
+
displayName: "Ada Byron",
|
|
150
|
+
active: true
|
|
151
|
+
});
|
|
152
|
+
const replacedUserResponse = await request(`/Users/${encodeURIComponent(createdUser.id)}`);
|
|
153
|
+
expectSCIMResponse(replacedUserResponse, 200);
|
|
154
|
+
const replacedUser = await readJson(replacedUserResponse);
|
|
155
|
+
expect(replacedUser).toMatchObject({
|
|
156
|
+
id: createdUser.id,
|
|
157
|
+
externalId: userExternalId,
|
|
158
|
+
displayName: "Ada Byron",
|
|
159
|
+
active: true
|
|
160
|
+
});
|
|
161
|
+
const unchangedUserPatchResponse = await request(`/Users/${encodeURIComponent(createdUser.id)}`, {
|
|
162
|
+
method: "PATCH",
|
|
163
|
+
body: {
|
|
164
|
+
schemas: [SCIM_PATCH_SCHEMA],
|
|
165
|
+
Operations: [{
|
|
166
|
+
op: "Replace",
|
|
167
|
+
path: "displayName",
|
|
168
|
+
value: "Ada Byron"
|
|
169
|
+
}]
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
expectSCIMResponse(unchangedUserPatchResponse, 200);
|
|
173
|
+
expect(await readJson(unchangedUserPatchResponse)).toMatchObject({
|
|
174
|
+
id: createdUser.id,
|
|
175
|
+
displayName: "Ada Byron"
|
|
176
|
+
});
|
|
177
|
+
const unchangedUserResponse = await request(`/Users/${encodeURIComponent(createdUser.id)}`);
|
|
178
|
+
expectSCIMResponse(unchangedUserResponse, 200);
|
|
179
|
+
expect(await readJson(unchangedUserResponse)).toEqual(replacedUser);
|
|
180
|
+
const createGroupResponse = await request("/Groups", {
|
|
181
|
+
method: "POST",
|
|
182
|
+
body: {
|
|
183
|
+
schemas: [SCIM_GROUP_SCHEMA],
|
|
184
|
+
externalId: groupExternalId,
|
|
185
|
+
displayName: "Finance administrators"
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
expectSCIMResponse(createGroupResponse, 201);
|
|
189
|
+
const createdGroup = await readJson(createGroupResponse);
|
|
190
|
+
const groupLocation = `${scimBaseURL}/Groups/${encodeURIComponent(createdGroup.id)}`;
|
|
191
|
+
expect(createdGroup).toMatchObject({
|
|
192
|
+
schemas: [SCIM_GROUP_SCHEMA],
|
|
193
|
+
externalId: groupExternalId,
|
|
194
|
+
displayName: "Finance administrators",
|
|
195
|
+
members: [],
|
|
196
|
+
meta: {
|
|
197
|
+
resourceType: "Group",
|
|
198
|
+
location: groupLocation
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
expect(createGroupResponse.headers.get("location")).toBe(groupLocation);
|
|
202
|
+
expect(createGroupResponse.headers.get("content-location")).toBe(groupLocation);
|
|
203
|
+
await checkpoint("group-created");
|
|
204
|
+
const addMember = () => request(`/Groups/${encodeURIComponent(createdGroup.id)}`, {
|
|
205
|
+
method: "PATCH",
|
|
206
|
+
body: {
|
|
207
|
+
schemas: [SCIM_PATCH_SCHEMA],
|
|
208
|
+
Operations: [{
|
|
209
|
+
op: "Add",
|
|
210
|
+
path: "members",
|
|
211
|
+
value: [{ value: createdUser.id }]
|
|
212
|
+
}]
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
if (options.projectionFailure) {
|
|
216
|
+
options.projectionFailure.enable();
|
|
217
|
+
expect(await expectSCIMErrorResponse(await addMember().finally(() => {
|
|
218
|
+
options.projectionFailure?.disable();
|
|
219
|
+
}), 500)).toEqual({
|
|
220
|
+
schemas: [SCIM_ERROR_SCHEMA],
|
|
221
|
+
status: "500",
|
|
222
|
+
detail: "SCIM projection reconciliation failed"
|
|
223
|
+
});
|
|
224
|
+
const groupAfterFailedAddResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`);
|
|
225
|
+
expectSCIMResponse(groupAfterFailedAddResponse, 200);
|
|
226
|
+
expect((await readJson(groupAfterFailedAddResponse)).members).toEqual([]);
|
|
227
|
+
await checkpoint("failed-add-rolled-back");
|
|
228
|
+
}
|
|
229
|
+
const addMemberResponse = await addMember();
|
|
230
|
+
expectSCIMResponse(addMemberResponse, 200);
|
|
231
|
+
expect((await readJson(addMemberResponse)).members).toEqual([expect.objectContaining({ value: createdUser.id })]);
|
|
232
|
+
const groupWithMemberResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`);
|
|
233
|
+
expectSCIMResponse(groupWithMemberResponse, 200);
|
|
234
|
+
expect((await readJson(groupWithMemberResponse)).members).toEqual([expect.objectContaining({
|
|
235
|
+
value: createdUser.id,
|
|
236
|
+
type: "User",
|
|
237
|
+
$ref: userLocation
|
|
238
|
+
})]);
|
|
239
|
+
await checkpoint("member-added");
|
|
240
|
+
const oktaRemovalResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`, {
|
|
241
|
+
method: "PATCH",
|
|
242
|
+
body: {
|
|
243
|
+
schemas: [SCIM_PATCH_SCHEMA],
|
|
244
|
+
Operations: [{
|
|
245
|
+
op: "Remove",
|
|
246
|
+
path: `members[value eq "${createdUser.id}"]`
|
|
247
|
+
}]
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
expectSCIMResponse(oktaRemovalResponse, 200);
|
|
251
|
+
expect((await readJson(oktaRemovalResponse)).members).toEqual([]);
|
|
252
|
+
const groupAfterOktaRemovalResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`);
|
|
253
|
+
expectSCIMResponse(groupAfterOktaRemovalResponse, 200);
|
|
254
|
+
expect((await readJson(groupAfterOktaRemovalResponse)).members).toEqual([]);
|
|
255
|
+
await checkpoint("okta-member-removed");
|
|
256
|
+
const secondAddResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`, {
|
|
257
|
+
method: "PATCH",
|
|
258
|
+
body: {
|
|
259
|
+
schemas: [SCIM_PATCH_SCHEMA],
|
|
260
|
+
Operations: [{
|
|
261
|
+
op: "Add",
|
|
262
|
+
path: "members",
|
|
263
|
+
value: [{ value: createdUser.id }]
|
|
264
|
+
}]
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
expectSCIMResponse(secondAddResponse, 200);
|
|
268
|
+
expect((await readJson(secondAddResponse)).members).toEqual([expect.objectContaining({ value: createdUser.id })]);
|
|
269
|
+
const entraRemovalResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`, {
|
|
270
|
+
method: "PATCH",
|
|
271
|
+
body: {
|
|
272
|
+
schemas: [SCIM_PATCH_SCHEMA],
|
|
273
|
+
Operations: [{
|
|
274
|
+
op: "Remove",
|
|
275
|
+
path: "members",
|
|
276
|
+
value: [{ value: createdUser.id }]
|
|
277
|
+
}]
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
expectSCIMResponse(entraRemovalResponse, 200);
|
|
281
|
+
expect((await readJson(entraRemovalResponse)).members).toEqual([]);
|
|
282
|
+
const groupAfterEntraRemovalResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`);
|
|
283
|
+
expectSCIMResponse(groupAfterEntraRemovalResponse, 200);
|
|
284
|
+
expect((await readJson(groupAfterEntraRemovalResponse)).members).toEqual([]);
|
|
285
|
+
await checkpoint("entra-member-removed");
|
|
286
|
+
expectSCIMResponse(await addMember(), 200);
|
|
287
|
+
const restoredGroupResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`);
|
|
288
|
+
expectSCIMResponse(restoredGroupResponse, 200);
|
|
289
|
+
expect((await readJson(restoredGroupResponse)).members).toEqual([expect.objectContaining({
|
|
290
|
+
value: createdUser.id,
|
|
291
|
+
$ref: userLocation
|
|
292
|
+
})]);
|
|
293
|
+
await checkpoint("member-restored");
|
|
294
|
+
const deactivateUserResponse = await request(`/Users/${encodeURIComponent(createdUser.id)}`, {
|
|
295
|
+
method: "PATCH",
|
|
296
|
+
body: {
|
|
297
|
+
schemas: [SCIM_PATCH_SCHEMA],
|
|
298
|
+
Operations: [{
|
|
299
|
+
op: "Replace",
|
|
300
|
+
path: "active",
|
|
301
|
+
value: false
|
|
302
|
+
}]
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
expectSCIMResponse(deactivateUserResponse, 200);
|
|
306
|
+
expect(await readJson(deactivateUserResponse)).toMatchObject({
|
|
307
|
+
id: createdUser.id,
|
|
308
|
+
active: false
|
|
309
|
+
});
|
|
310
|
+
const inactiveUserResponse = await request(`/Users/${encodeURIComponent(createdUser.id)}`);
|
|
311
|
+
expectSCIMResponse(inactiveUserResponse, 200);
|
|
312
|
+
expect(await readJson(inactiveUserResponse)).toMatchObject({
|
|
313
|
+
id: createdUser.id,
|
|
314
|
+
active: false
|
|
315
|
+
});
|
|
316
|
+
const groupWithInactiveMemberResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`);
|
|
317
|
+
expectSCIMResponse(groupWithInactiveMemberResponse, 200);
|
|
318
|
+
expect((await readJson(groupWithInactiveMemberResponse)).members).toEqual([expect.objectContaining({ value: createdUser.id })]);
|
|
319
|
+
await checkpoint("user-deactivated");
|
|
320
|
+
const reactivateUserResponse = await request(`/Users/${encodeURIComponent(createdUser.id)}`, {
|
|
321
|
+
method: "PATCH",
|
|
322
|
+
body: {
|
|
323
|
+
schemas: [SCIM_PATCH_SCHEMA],
|
|
324
|
+
Operations: [{
|
|
325
|
+
op: "Replace",
|
|
326
|
+
path: "active",
|
|
327
|
+
value: true
|
|
328
|
+
}]
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
expectSCIMResponse(reactivateUserResponse, 200);
|
|
332
|
+
expect(await readJson(reactivateUserResponse)).toMatchObject({
|
|
333
|
+
id: createdUser.id,
|
|
334
|
+
active: true
|
|
335
|
+
});
|
|
336
|
+
const activeUserResponse = await request(`/Users/${encodeURIComponent(createdUser.id)}`);
|
|
337
|
+
expectSCIMResponse(activeUserResponse, 200);
|
|
338
|
+
expect(await readJson(activeUserResponse)).toMatchObject({
|
|
339
|
+
id: createdUser.id,
|
|
340
|
+
active: true
|
|
341
|
+
});
|
|
342
|
+
await checkpoint("user-reactivated");
|
|
343
|
+
await expectSCIMNoContent(await request(`/Users/${encodeURIComponent(createdUser.id)}`, { method: "DELETE" }));
|
|
344
|
+
await expectSCIMErrorResponse(await request(`/Users/${encodeURIComponent(createdUser.id)}`), 404);
|
|
345
|
+
const groupAfterPopulatedUserDeleteResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`);
|
|
346
|
+
expectSCIMResponse(groupAfterPopulatedUserDeleteResponse, 200);
|
|
347
|
+
expect((await readJson(groupAfterPopulatedUserDeleteResponse)).members).toEqual([]);
|
|
348
|
+
await checkpoint("populated-user-deleted");
|
|
349
|
+
const emptyAfterDeleteResponse = await request(userFilterPath(userName));
|
|
350
|
+
expectSCIMResponse(emptyAfterDeleteResponse, 200);
|
|
351
|
+
expect(await readJson(emptyAfterDeleteResponse)).toMatchObject({
|
|
352
|
+
totalResults: 0,
|
|
353
|
+
Resources: []
|
|
354
|
+
});
|
|
355
|
+
const reprovisionResponse = await request("/Users", {
|
|
356
|
+
method: "POST",
|
|
357
|
+
body: userCreateBody
|
|
358
|
+
});
|
|
359
|
+
expectSCIMResponse(reprovisionResponse, 201);
|
|
360
|
+
const reprovisionedUser = await readJson(reprovisionResponse);
|
|
361
|
+
expect(reprovisionedUser).toMatchObject({
|
|
362
|
+
externalId: userExternalId,
|
|
363
|
+
userName,
|
|
364
|
+
active: true
|
|
365
|
+
});
|
|
366
|
+
expect(reprovisionedUser.id).not.toBe(createdUser.id);
|
|
367
|
+
const reprovisionedUserLocation = `${scimBaseURL}/Users/${encodeURIComponent(reprovisionedUser.id)}`;
|
|
368
|
+
expect(reprovisionedUser.meta.location).toBe(reprovisionedUserLocation);
|
|
369
|
+
expect(reprovisionResponse.headers.get("location")).toBe(reprovisionedUserLocation);
|
|
370
|
+
await checkpoint("user-reprovisioned");
|
|
371
|
+
expectSCIMResponse(await request(`/Groups/${encodeURIComponent(createdGroup.id)}`, {
|
|
372
|
+
method: "PATCH",
|
|
373
|
+
body: {
|
|
374
|
+
schemas: [SCIM_PATCH_SCHEMA],
|
|
375
|
+
Operations: [{
|
|
376
|
+
op: "Add",
|
|
377
|
+
path: "members",
|
|
378
|
+
value: [{ value: reprovisionedUser.id }]
|
|
379
|
+
}]
|
|
380
|
+
}
|
|
381
|
+
}), 200);
|
|
382
|
+
const groupWithReprovisionedMemberResponse = await request(`/Groups/${encodeURIComponent(createdGroup.id)}`);
|
|
383
|
+
expectSCIMResponse(groupWithReprovisionedMemberResponse, 200);
|
|
384
|
+
expect((await readJson(groupWithReprovisionedMemberResponse)).members).toEqual([expect.objectContaining({
|
|
385
|
+
value: reprovisionedUser.id,
|
|
386
|
+
$ref: reprovisionedUserLocation
|
|
387
|
+
})]);
|
|
388
|
+
await checkpoint("reprovisioned-member-added");
|
|
389
|
+
await expectSCIMNoContent(await request(`/Groups/${encodeURIComponent(createdGroup.id)}`, { method: "DELETE" }));
|
|
390
|
+
await expectSCIMErrorResponse(await request(`/Groups/${encodeURIComponent(createdGroup.id)}`), 404);
|
|
391
|
+
const userAfterPopulatedGroupDeleteResponse = await request(`/Users/${encodeURIComponent(reprovisionedUser.id)}`);
|
|
392
|
+
expectSCIMResponse(userAfterPopulatedGroupDeleteResponse, 200);
|
|
393
|
+
expect(await readJson(userAfterPopulatedGroupDeleteResponse)).toMatchObject({
|
|
394
|
+
id: reprovisionedUser.id,
|
|
395
|
+
active: true
|
|
396
|
+
});
|
|
397
|
+
await checkpoint("populated-group-deleted");
|
|
398
|
+
await expectSCIMNoContent(await request(`/Users/${encodeURIComponent(reprovisionedUser.id)}`, { method: "DELETE" }));
|
|
399
|
+
await expectSCIMErrorResponse(await request(`/Users/${encodeURIComponent(reprovisionedUser.id)}`), 404);
|
|
400
|
+
const emptyFinalListResponse = await request(userFilterPath(userName));
|
|
401
|
+
expectSCIMResponse(emptyFinalListResponse, 200);
|
|
402
|
+
expect(await readJson(emptyFinalListResponse)).toMatchObject({
|
|
403
|
+
totalResults: 0,
|
|
404
|
+
Resources: []
|
|
405
|
+
});
|
|
406
|
+
await checkpoint("lifecycle-complete");
|
|
407
|
+
return {
|
|
408
|
+
userId: createdUser.id,
|
|
409
|
+
groupId: createdGroup.id,
|
|
410
|
+
reprovisionedUserId: reprovisionedUser.id,
|
|
411
|
+
userLocation,
|
|
412
|
+
groupLocation
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
//#endregion
|
|
416
|
+
export { runSCIMLifecycle };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/test-utils",
|
|
3
|
-
"version": "1.7.0-rc.
|
|
3
|
+
"version": "1.7.0-rc.3",
|
|
4
4
|
"description": "Testing utilities for Better Auth adapter development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,18 +28,23 @@
|
|
|
28
28
|
"dev-source": "./src/adapter/index.ts",
|
|
29
29
|
"default": "./dist/adapter.mjs",
|
|
30
30
|
"types": "./dist/adapter.d.mts"
|
|
31
|
+
},
|
|
32
|
+
"./scim": {
|
|
33
|
+
"dev-source": "./src/scim-lifecycle.ts",
|
|
34
|
+
"default": "./dist/scim.mjs",
|
|
35
|
+
"types": "./dist/scim.d.mts"
|
|
31
36
|
}
|
|
32
37
|
},
|
|
33
38
|
"devDependencies": {
|
|
34
|
-
"tsdown": "0.
|
|
39
|
+
"tsdown": "0.22.7",
|
|
35
40
|
"vitest": "^4.1.9",
|
|
36
|
-
"@better-auth/core": "1.7.0-rc.
|
|
37
|
-
"better-auth": "1.7.0-rc.
|
|
41
|
+
"@better-auth/core": "1.7.0-rc.3",
|
|
42
|
+
"better-auth": "1.7.0-rc.3"
|
|
38
43
|
},
|
|
39
44
|
"peerDependencies": {
|
|
40
45
|
"vitest": "^4.1.9",
|
|
41
|
-
"@better-auth/core": "^1.7.0-rc.
|
|
42
|
-
"better-auth": "^1.7.0-rc.
|
|
46
|
+
"@better-auth/core": "^1.7.0-rc.3",
|
|
47
|
+
"better-auth": "^1.7.0-rc.3"
|
|
43
48
|
},
|
|
44
49
|
"scripts": {
|
|
45
50
|
"build": "tsdown",
|
package/dist/suites/joins.d.mts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Logger } from "../test-adapter.mjs";
|
|
2
|
-
import { TestSuiteStats } from "../create-test-suite.mjs";
|
|
3
|
-
import * as better_auth0 from "better-auth";
|
|
4
|
-
|
|
5
|
-
//#region src/adapter/suites/joins.d.ts
|
|
6
|
-
declare const joinsTestSuite: (options?: {
|
|
7
|
-
disableTests?: Partial<Record<"init - tests" | "create - should create a model" | "create - should always return an id" | "create - should return null for nullable foreign keys" | "create - should apply default values to fields" | "findOne - should find a model" | "findOne - should not apply defaultValue if value not found" | "findOne - should find a model using a reference field" | "findOne - should not throw on record not found" | "findOne - should find a model without id" | "findOne - should find a model with join" | "findOne - should find a model with modified field name" | "findOne - should find a model with modified model name" | "findOne - should find a model with additional fields" | "findOne - should select fields" | "findOne - should select fields with one-to-many join" | "findOne - should select fields with one-to-one join" | "findOne - should select fields with multiple joins" | "findOne - should find model with date field" | "findOne - should perform backwards joins" | "findOne - should return an object for one-to-one joins" | "findOne - should return an array for one-to-many joins" | "findOne - should work with both one-to-one and one-to-many joins" | "findOne - should return null for failed base model lookup that has joins" | "findOne - should join a model with modified field name" | "findMany - should find many models" | "findMany - should find many models with date fields" | "findMany - should find many models with join" | "findMany - should find many with join and limit" | "findMany - should select fields" | "findMany - should select fields with one-to-many join" | "findMany - should select fields with one-to-one join" | "findMany - should select fields with multiple joins" | "findMany - should find many with join and offset" | "findMany - should find many with join and sortBy" | "findMany - should find many with join and where clause" | "findMany - should find many with join, where, limit, and offset" | "findMany - should find many with one-to-one join" | "findMany - should find many with both one-to-one and one-to-many joins" | "findMany - should return an empty array when no models are found" | "findMany - should return empty array when base records don't exist with joins" | "findMany - should find many models with starts_with operator" | "findMany - starts_with should not interpret regex patterns" | "findMany - ends_with should not interpret regex patterns" | "findMany - contains should not interpret regex patterns" | "findMany - should find many models with ends_with operator" | "findMany - should find many models with contains operator" | "findMany - should handle multiple where conditions with different operators" | "findMany - should find many models with contains operator (using symbol)" | "findMany - should find many models with eq operator" | "findMany - should find many models with ne operator" | "findMany - should find many models with gt operator" | "findMany - should find many models with gte operator" | "findMany - should find many models with lte operator" | "findMany - should find many models with lt operator" | "findMany - should find many models with in operator" | "findMany - should find many models with not_in operator" | "findMany - should find many models with sortBy" | "findMany - should find many models with limit" | "findMany - should find many models with offset" | "findMany - should find many models with limit and offset" | "findMany - should find many models with sortBy and offset" | "findMany - should find many models with sortBy and limit" | "findMany - should find many models with sortBy and limit and offset" | "findMany - should find many models with sortBy and limit and offset and where" | "update - should update a model" | "update - should return null when where is empty" | "updateMany - should update all models when where is empty" | "updateMany - should update many models with a specific where" | "updateMany - should update many models with a multiple where" | "incrementOne - guarded set transition returns the row on a matching guard and null on a guard miss" | "delete - should delete a model" | "delete - should not throw on record not found" | "delete - should delete by non-unique field" | "deleteMany - should delete many models" | "deleteMany - starts_with should not interpret regex patterns" | "deleteMany - ends_with should not interpret regex patterns" | "deleteMany - contains should not interpret regex patterns" | "deleteMany - should delete many models with numeric values" | "deleteMany - should delete many models with boolean values" | "count - should count many models" | "count - should return 0 with no rows to count" | "count - should count with where clause" | "update - should correctly return record when updating a field used in where clause" | "update - should handle updating multiple fields including where clause field" | "update - should work when updated field is not in where clause" | "findOne - backwards join should only return single record not array" | "findMany - backwards join should only return single record not array" | "findOne - backwards join with modified field name (session base, users-table join)" | "findOne - multiple joins should return result even when some joined tables have no matching rows" | "findOne - should be able to perform a limited join" | "findOne - should be able to perform a complex limited join" | "findMany - should be able to perform a limited join" | "findMany - should be able to perform a complex limited join" | "findOne - should return null for one-to-one join when joined record doesn't exist" | "findMany - should return null for one-to-one join when joined records don't exist" | "findMany - should return empty array for one-to-many join when joined records don't exist" | "findMany - should handle mixed joins correctly when some are missing" | "create - should support arrays" | "create - should support json" | "update - should support multiple where conditions under AND connector with unique field" | "findMany - eq operator with null value (single condition) should use IS NULL" | "findMany - eq and ne operators with null value in AND group should use IS NULL / IS NOT NULL" | "findMany - eq and ne operators with null value in OR group should use IS NULL / IS NOT NULL" | "update - should return updated record when where condition uses null value" | "update - should return null when a multi-predicate where matches no row", boolean> & {
|
|
8
|
-
ALL?: boolean;
|
|
9
|
-
}> | undefined;
|
|
10
|
-
} | undefined) => (helpers: {
|
|
11
|
-
adapter: () => Promise<better_auth0.DBAdapter<better_auth0.BetterAuthOptions>>;
|
|
12
|
-
log: Logger;
|
|
13
|
-
adapterDisplayName: string;
|
|
14
|
-
getBetterAuthOptions: () => better_auth0.BetterAuthOptions;
|
|
15
|
-
modifyBetterAuthOptions: (options: better_auth0.BetterAuthOptions) => Promise<better_auth0.BetterAuthOptions>;
|
|
16
|
-
cleanup: () => Promise<void>;
|
|
17
|
-
runMigrations: () => Promise<void>;
|
|
18
|
-
prefixTests?: string | undefined;
|
|
19
|
-
onTestFinish: (stats: TestSuiteStats) => Promise<void>;
|
|
20
|
-
customIdGenerator?: (() => any | Promise<any> | undefined) | undefined;
|
|
21
|
-
transformIdOutput?: ((id: any) => string | undefined) | undefined;
|
|
22
|
-
}) => Promise<void>;
|
|
23
|
-
//#endregion
|
|
24
|
-
export { joinsTestSuite };
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Logger } from "../test-adapter.mjs";
|
|
2
|
-
import { TestSuiteStats } from "../create-test-suite.mjs";
|
|
3
|
-
import * as better_auth0 from "better-auth";
|
|
4
|
-
|
|
5
|
-
//#region src/adapter/suites/number-id.d.ts
|
|
6
|
-
declare const numberIdTestSuite: (options?: {
|
|
7
|
-
disableTests?: Partial<Record<"init - tests" | "create - should create a model" | "create - should always return an id" | "create - should return null for nullable foreign keys" | "create - should apply default values to fields" | "findOne - should find a model" | "findOne - should not apply defaultValue if value not found" | "findOne - should find a model using a reference field" | "findOne - should not throw on record not found" | "findOne - should find a model without id" | "findOne - should find a model with join" | "findOne - should find a model with modified field name" | "findOne - should find a model with modified model name" | "findOne - should find a model with additional fields" | "findOne - should select fields" | "findOne - should select fields with one-to-many join" | "findOne - should select fields with one-to-one join" | "findOne - should select fields with multiple joins" | "findOne - should find model with date field" | "findOne - should perform backwards joins" | "findOne - should return an object for one-to-one joins" | "findOne - should return an array for one-to-many joins" | "findOne - should work with both one-to-one and one-to-many joins" | "findOne - should return null for failed base model lookup that has joins" | "findOne - should join a model with modified field name" | "findMany - should find many models" | "findMany - should find many models with date fields" | "findMany - should find many models with join" | "findMany - should find many with join and limit" | "findMany - should select fields" | "findMany - should select fields with one-to-many join" | "findMany - should select fields with one-to-one join" | "findMany - should select fields with multiple joins" | "findMany - should find many with join and offset" | "findMany - should find many with join and sortBy" | "findMany - should find many with join and where clause" | "findMany - should find many with join, where, limit, and offset" | "findMany - should find many with one-to-one join" | "findMany - should find many with both one-to-one and one-to-many joins" | "findMany - should return an empty array when no models are found" | "findMany - should return empty array when base records don't exist with joins" | "findMany - should find many models with starts_with operator" | "findMany - starts_with should not interpret regex patterns" | "findMany - ends_with should not interpret regex patterns" | "findMany - contains should not interpret regex patterns" | "findMany - should find many models with ends_with operator" | "findMany - should find many models with contains operator" | "findMany - should handle multiple where conditions with different operators" | "findMany - should find many models with contains operator (using symbol)" | "findMany - should find many models with eq operator" | "findMany - should find many models with ne operator" | "findMany - should find many models with gt operator" | "findMany - should find many models with gte operator" | "findMany - should find many models with lte operator" | "findMany - should find many models with lt operator" | "findMany - should find many models with in operator" | "findMany - should find many models with not_in operator" | "findMany - should find many models with sortBy" | "findMany - should find many models with limit" | "findMany - should find many models with offset" | "findMany - should find many models with limit and offset" | "findMany - should find many models with sortBy and offset" | "findMany - should find many models with sortBy and limit" | "findMany - should find many models with sortBy and limit and offset" | "findMany - should find many models with sortBy and limit and offset and where" | "update - should update a model" | "update - should return null when where is empty" | "updateMany - should update all models when where is empty" | "updateMany - should update many models with a specific where" | "updateMany - should update many models with a multiple where" | "incrementOne - guarded set transition returns the row on a matching guard and null on a guard miss" | "delete - should delete a model" | "delete - should not throw on record not found" | "delete - should delete by non-unique field" | "deleteMany - should delete many models" | "deleteMany - starts_with should not interpret regex patterns" | "deleteMany - ends_with should not interpret regex patterns" | "deleteMany - contains should not interpret regex patterns" | "deleteMany - should delete many models with numeric values" | "deleteMany - should delete many models with boolean values" | "count - should count many models" | "count - should return 0 with no rows to count" | "count - should count with where clause" | "update - should correctly return record when updating a field used in where clause" | "update - should handle updating multiple fields including where clause field" | "update - should work when updated field is not in where clause" | "findOne - backwards join should only return single record not array" | "findMany - backwards join should only return single record not array" | "findOne - backwards join with modified field name (session base, users-table join)" | "findOne - multiple joins should return result even when some joined tables have no matching rows" | "findOne - should be able to perform a limited join" | "findOne - should be able to perform a complex limited join" | "findMany - should be able to perform a limited join" | "findMany - should be able to perform a complex limited join" | "findOne - should return null for one-to-one join when joined record doesn't exist" | "findMany - should return null for one-to-one join when joined records don't exist" | "findMany - should return empty array for one-to-many join when joined records don't exist" | "findMany - should handle mixed joins correctly when some are missing" | "create - should support arrays" | "create - should support json" | "update - should support multiple where conditions under AND connector with unique field" | "findMany - eq operator with null value (single condition) should use IS NULL" | "findMany - eq and ne operators with null value in AND group should use IS NULL / IS NOT NULL" | "findMany - eq and ne operators with null value in OR group should use IS NULL / IS NOT NULL" | "update - should return updated record when where condition uses null value" | "update - should return null when a multi-predicate where matches no row" | "create - should return a number id", boolean> & {
|
|
8
|
-
ALL?: boolean;
|
|
9
|
-
}> | undefined;
|
|
10
|
-
} | undefined) => (helpers: {
|
|
11
|
-
adapter: () => Promise<better_auth0.DBAdapter<better_auth0.BetterAuthOptions>>;
|
|
12
|
-
log: Logger;
|
|
13
|
-
adapterDisplayName: string;
|
|
14
|
-
getBetterAuthOptions: () => better_auth0.BetterAuthOptions;
|
|
15
|
-
modifyBetterAuthOptions: (options: better_auth0.BetterAuthOptions) => Promise<better_auth0.BetterAuthOptions>;
|
|
16
|
-
cleanup: () => Promise<void>;
|
|
17
|
-
runMigrations: () => Promise<void>;
|
|
18
|
-
prefixTests?: string | undefined;
|
|
19
|
-
onTestFinish: (stats: TestSuiteStats) => Promise<void>;
|
|
20
|
-
customIdGenerator?: (() => any | Promise<any> | undefined) | undefined;
|
|
21
|
-
transformIdOutput?: ((id: any) => string | undefined) | undefined;
|
|
22
|
-
}) => Promise<void>;
|
|
23
|
-
//#endregion
|
|
24
|
-
export { numberIdTestSuite };
|
package/dist/suites/uuid.d.mts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Logger } from "../test-adapter.mjs";
|
|
2
|
-
import { TestSuiteStats } from "../create-test-suite.mjs";
|
|
3
|
-
import * as better_auth0 from "better-auth";
|
|
4
|
-
|
|
5
|
-
//#region src/adapter/suites/uuid.d.ts
|
|
6
|
-
declare const uuidTestSuite: (options?: {
|
|
7
|
-
disableTests?: Partial<Record<"init - tests" | "create - should create a model" | "create - should always return an id" | "create - should return null for nullable foreign keys" | "create - should apply default values to fields" | "findOne - should find a model" | "findOne - should not apply defaultValue if value not found" | "findOne - should find a model using a reference field" | "findOne - should not throw on record not found" | "findOne - should find a model without id" | "findOne - should find a model with join" | "findOne - should find a model with modified field name" | "findOne - should find a model with modified model name" | "findOne - should find a model with additional fields" | "findOne - should select fields" | "findOne - should select fields with one-to-many join" | "findOne - should select fields with one-to-one join" | "findOne - should select fields with multiple joins" | "findOne - should find model with date field" | "findOne - should perform backwards joins" | "findOne - should return an object for one-to-one joins" | "findOne - should return an array for one-to-many joins" | "findOne - should work with both one-to-one and one-to-many joins" | "findOne - should return null for failed base model lookup that has joins" | "findOne - should join a model with modified field name" | "findMany - should find many models" | "findMany - should find many models with date fields" | "findMany - should find many models with join" | "findMany - should find many with join and limit" | "findMany - should select fields" | "findMany - should select fields with one-to-many join" | "findMany - should select fields with one-to-one join" | "findMany - should select fields with multiple joins" | "findMany - should find many with join and offset" | "findMany - should find many with join and sortBy" | "findMany - should find many with join and where clause" | "findMany - should find many with join, where, limit, and offset" | "findMany - should find many with one-to-one join" | "findMany - should find many with both one-to-one and one-to-many joins" | "findMany - should return an empty array when no models are found" | "findMany - should return empty array when base records don't exist with joins" | "findMany - should find many models with starts_with operator" | "findMany - starts_with should not interpret regex patterns" | "findMany - ends_with should not interpret regex patterns" | "findMany - contains should not interpret regex patterns" | "findMany - should find many models with ends_with operator" | "findMany - should find many models with contains operator" | "findMany - should handle multiple where conditions with different operators" | "findMany - should find many models with contains operator (using symbol)" | "findMany - should find many models with eq operator" | "findMany - should find many models with ne operator" | "findMany - should find many models with gt operator" | "findMany - should find many models with gte operator" | "findMany - should find many models with lte operator" | "findMany - should find many models with lt operator" | "findMany - should find many models with in operator" | "findMany - should find many models with not_in operator" | "findMany - should find many models with sortBy" | "findMany - should find many models with limit" | "findMany - should find many models with offset" | "findMany - should find many models with limit and offset" | "findMany - should find many models with sortBy and offset" | "findMany - should find many models with sortBy and limit" | "findMany - should find many models with sortBy and limit and offset" | "findMany - should find many models with sortBy and limit and offset and where" | "update - should update a model" | "update - should return null when where is empty" | "updateMany - should update all models when where is empty" | "updateMany - should update many models with a specific where" | "updateMany - should update many models with a multiple where" | "incrementOne - guarded set transition returns the row on a matching guard and null on a guard miss" | "delete - should delete a model" | "delete - should not throw on record not found" | "delete - should delete by non-unique field" | "deleteMany - should delete many models" | "deleteMany - starts_with should not interpret regex patterns" | "deleteMany - ends_with should not interpret regex patterns" | "deleteMany - contains should not interpret regex patterns" | "deleteMany - should delete many models with numeric values" | "deleteMany - should delete many models with boolean values" | "count - should count many models" | "count - should return 0 with no rows to count" | "count - should count with where clause" | "update - should correctly return record when updating a field used in where clause" | "update - should handle updating multiple fields including where clause field" | "update - should work when updated field is not in where clause" | "findOne - backwards join should only return single record not array" | "findMany - backwards join should only return single record not array" | "findOne - backwards join with modified field name (session base, users-table join)" | "findOne - multiple joins should return result even when some joined tables have no matching rows" | "findOne - should be able to perform a limited join" | "findOne - should be able to perform a complex limited join" | "findMany - should be able to perform a limited join" | "findMany - should be able to perform a complex limited join" | "findOne - should return null for one-to-one join when joined record doesn't exist" | "findMany - should return null for one-to-one join when joined records don't exist" | "findMany - should return empty array for one-to-many join when joined records don't exist" | "findMany - should handle mixed joins correctly when some are missing" | "create - should support arrays" | "create - should support json" | "update - should support multiple where conditions under AND connector with unique field" | "findMany - eq operator with null value (single condition) should use IS NULL" | "findMany - eq and ne operators with null value in AND group should use IS NULL / IS NOT NULL" | "findMany - eq and ne operators with null value in OR group should use IS NULL / IS NOT NULL" | "update - should return updated record when where condition uses null value" | "update - should return null when a multi-predicate where matches no row" | "create - should return a uuid" | "findOne - should find a model using a uuid", boolean> & {
|
|
8
|
-
ALL?: boolean;
|
|
9
|
-
}> | undefined;
|
|
10
|
-
} | undefined) => (helpers: {
|
|
11
|
-
adapter: () => Promise<better_auth0.DBAdapter<better_auth0.BetterAuthOptions>>;
|
|
12
|
-
log: Logger;
|
|
13
|
-
adapterDisplayName: string;
|
|
14
|
-
getBetterAuthOptions: () => better_auth0.BetterAuthOptions;
|
|
15
|
-
modifyBetterAuthOptions: (options: better_auth0.BetterAuthOptions) => Promise<better_auth0.BetterAuthOptions>;
|
|
16
|
-
cleanup: () => Promise<void>;
|
|
17
|
-
runMigrations: () => Promise<void>;
|
|
18
|
-
prefixTests?: string | undefined;
|
|
19
|
-
onTestFinish: (stats: TestSuiteStats) => Promise<void>;
|
|
20
|
-
customIdGenerator?: (() => any | Promise<any> | undefined) | undefined;
|
|
21
|
-
transformIdOutput?: ((id: any) => string | undefined) | undefined;
|
|
22
|
-
}) => Promise<void>;
|
|
23
|
-
//#endregion
|
|
24
|
-
export { uuidTestSuite };
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|