@hyper-fetch/firebase-admin 7.5.2 → 8.0.0

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.
Files changed (119) hide show
  1. package/.eslintrc.cjs +12 -0
  2. package/__tests__/features/firestore/admin/constraints.admin.spec.ts +23 -0
  3. package/__tests__/features/firestore/admin/methods.admin.spec.ts +20 -0
  4. package/__tests__/features/firestore/admin/sockets.base.spec.ts +17 -0
  5. package/__tests__/features/firestore/shared/constraints.shared.tests.ts +72 -0
  6. package/__tests__/features/firestore/shared/methods/add-doc.test.suite.ts +29 -0
  7. package/__tests__/features/firestore/shared/methods/delete-doc.test.suite.ts +52 -0
  8. package/__tests__/features/firestore/shared/methods/get-doc.test.suite.ts +60 -0
  9. package/__tests__/features/firestore/shared/methods/get-docs.test.suite.ts +45 -0
  10. package/__tests__/features/firestore/shared/methods/on-snapshot.test.suite.ts +290 -0
  11. package/__tests__/features/firestore/shared/methods/set-doc.test.suite.ts +70 -0
  12. package/__tests__/features/firestore/shared/methods/update-doc.test.suite.ts +40 -0
  13. package/__tests__/features/firestore/shared/methods.shared.tests.ts +24 -0
  14. package/__tests__/features/realtime/admin/constraints.admin.spec.ts +15 -0
  15. package/__tests__/features/realtime/admin/methods.admin.spec.ts +24 -0
  16. package/__tests__/features/realtime/admin/sockets.base.spec.ts +15 -0
  17. package/__tests__/features/realtime/shared/constraints.shared.tests.ts +57 -0
  18. package/__tests__/features/realtime/shared/methods/get.test.suite.ts +64 -0
  19. package/__tests__/features/realtime/shared/methods/on-value.test.suite.ts +190 -0
  20. package/__tests__/features/realtime/shared/methods/push.test.suite.ts +48 -0
  21. package/__tests__/features/realtime/shared/methods/remove.test.suite.ts +46 -0
  22. package/__tests__/features/realtime/shared/methods/set.test.suite.ts +70 -0
  23. package/__tests__/features/realtime/shared/methods/update.test.suite.ts +42 -0
  24. package/__tests__/features/realtime/shared/methods.shared.tests.ts +25 -0
  25. package/__tests__/shared/request-events.shared.ts +32 -0
  26. package/__tests__/tsconfig.json +21 -0
  27. package/__tests__/utils/database.rules.json +11 -0
  28. package/__tests__/utils/index.ts +3 -0
  29. package/__tests__/utils/initialize.firestore.admin.ts +16 -0
  30. package/__tests__/utils/initialize.realtime.admin.ts +19 -0
  31. package/__tests__/utils/seed/seed.data.ts +21 -0
  32. package/__tests__/utils/seed.admin.ts +23 -0
  33. package/__tests__/vitest.setup.ts +9 -0
  34. package/dist/adapter/adapter.d.ts +3 -0
  35. package/dist/adapter/adapter.d.ts.map +1 -0
  36. package/dist/adapter/adapter.sockets.d.ts +3 -0
  37. package/dist/adapter/adapter.sockets.d.ts.map +1 -0
  38. package/dist/adapter/index.d.ts +4 -0
  39. package/dist/adapter/index.d.ts.map +1 -0
  40. package/dist/adapter/types/adapter.base.types.d.ts +11 -0
  41. package/dist/adapter/types/adapter.base.types.d.ts.map +1 -0
  42. package/dist/adapter/types/adapter.firestore.types.d.ts +45 -0
  43. package/dist/adapter/types/adapter.firestore.types.d.ts.map +1 -0
  44. package/dist/adapter/types/adapter.realtime.types.d.ts +39 -0
  45. package/dist/adapter/types/adapter.realtime.types.d.ts.map +1 -0
  46. package/dist/adapter/types/firestore.socket.types.d.ts +17 -0
  47. package/dist/adapter/types/firestore.socket.types.d.ts.map +1 -0
  48. package/dist/adapter/types/index.d.ts +6 -0
  49. package/dist/adapter/types/index.d.ts.map +1 -0
  50. package/dist/adapter/types/realtime.socket.types.d.ts +12 -0
  51. package/dist/adapter/types/realtime.socket.types.d.ts.map +1 -0
  52. package/dist/constraints/constraints.types.d.ts +13 -0
  53. package/dist/constraints/constraints.types.d.ts.map +1 -0
  54. package/dist/constraints/firebase.constraints.d.ts +86 -0
  55. package/dist/constraints/firebase.constraints.d.ts.map +1 -0
  56. package/dist/constraints/index.d.ts +3 -0
  57. package/dist/constraints/index.d.ts.map +1 -0
  58. package/dist/firestore/firestore.methods.d.ts +21 -0
  59. package/dist/firestore/firestore.methods.d.ts.map +1 -0
  60. package/dist/firestore/firestore.sockets.d.ts +4 -0
  61. package/dist/firestore/firestore.sockets.d.ts.map +1 -0
  62. package/dist/firestore/index.d.ts +4 -0
  63. package/dist/firestore/index.d.ts.map +1 -0
  64. package/dist/firestore/utils/constraints.utils.d.ts +5 -0
  65. package/dist/firestore/utils/constraints.utils.d.ts.map +1 -0
  66. package/dist/firestore/utils/index.d.ts +4 -0
  67. package/dist/firestore/utils/index.d.ts.map +1 -0
  68. package/dist/firestore/utils/ref.utils.d.ts +3 -0
  69. package/dist/firestore/utils/ref.utils.d.ts.map +1 -0
  70. package/dist/firestore/utils/result.utils.d.ts +10 -0
  71. package/dist/firestore/utils/result.utils.d.ts.map +1 -0
  72. package/dist/index.d.ts +5 -271
  73. package/dist/index.d.ts.map +1 -0
  74. package/dist/index.mjs +670 -0
  75. package/dist/index.mjs.map +1 -0
  76. package/dist/realtime/index.d.ts +4 -0
  77. package/dist/realtime/index.d.ts.map +1 -0
  78. package/dist/realtime/realtime.methods.d.ts +19 -0
  79. package/dist/realtime/realtime.methods.d.ts.map +1 -0
  80. package/dist/realtime/realtime.sockets.d.ts +4 -0
  81. package/dist/realtime/realtime.sockets.d.ts.map +1 -0
  82. package/dist/realtime/utils/constraints.utils.d.ts +5 -0
  83. package/dist/realtime/utils/constraints.utils.d.ts.map +1 -0
  84. package/dist/realtime/utils/index.d.ts +3 -0
  85. package/dist/realtime/utils/index.d.ts.map +1 -0
  86. package/dist/realtime/utils/result.utils.d.ts +3 -0
  87. package/dist/realtime/utils/result.utils.d.ts.map +1 -0
  88. package/dist/utils/cache.utils.d.ts +11 -0
  89. package/dist/utils/cache.utils.d.ts.map +1 -0
  90. package/dist/utils/index.d.ts +3 -0
  91. package/dist/utils/index.d.ts.map +1 -0
  92. package/dist/utils/misc.d.ts +3 -0
  93. package/dist/utils/misc.d.ts.map +1 -0
  94. package/package.json +8 -11
  95. package/project.json +4 -0
  96. package/src/adapter/adapter.sockets.ts +1 -1
  97. package/src/adapter/adapter.ts +13 -14
  98. package/src/adapter/types/adapter.base.types.ts +4 -4
  99. package/src/adapter/types/adapter.firestore.types.ts +4 -4
  100. package/src/adapter/types/adapter.realtime.types.ts +4 -4
  101. package/src/adapter/types/firestore.socket.types.ts +3 -3
  102. package/src/adapter/types/realtime.socket.types.ts +3 -3
  103. package/src/constraints/constraints.types.ts +1 -1
  104. package/src/constraints/firebase.constraints.ts +1 -1
  105. package/src/firestore/firestore.methods.ts +4 -4
  106. package/src/firestore/firestore.sockets.ts +3 -9
  107. package/src/firestore/utils/constraints.utils.ts +4 -3
  108. package/src/firestore/utils/ref.utils.ts +1 -1
  109. package/src/firestore/utils/result.utils.ts +1 -1
  110. package/src/realtime/realtime.methods.ts +4 -4
  111. package/src/realtime/realtime.sockets.ts +2 -2
  112. package/src/realtime/utils/constraints.utils.ts +3 -2
  113. package/src/realtime/utils/result.utils.ts +1 -1
  114. package/src/utils/cache.utils.ts +4 -2
  115. package/tsconfig.json +1 -1
  116. package/vite.config.ts +45 -0
  117. package/.eslintrc.json +0 -11
  118. package/dist/index.js +0 -686
  119. package/dist/index.js.map +0 -7
@@ -0,0 +1,70 @@
1
+ import { Client } from "@hyper-fetch/core";
2
+
3
+ import type { Tea } from "../../../../utils";
4
+ import type { FirebaseAdminAdapter } from "adapter";
5
+ import { testLifecycleEvents } from "../../../../shared/request-events.shared";
6
+
7
+ export const setDocTestSuite = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
8
+ describe("setDoc", () => {
9
+ it("should set data", async () => {
10
+ const newData = { origin: "Poland", type: "Green", year: 2023, name: "Pou Ran Do Cha", amount: 10 } as Tea;
11
+ const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
12
+ const getReq = client
13
+ .createRequest<{ response: Tea }>()({
14
+ endpoint: ":teaId",
15
+ method: "getDoc",
16
+ })
17
+ .setParams({ teaId: 1 });
18
+ const setReq = client
19
+ .createRequest<{ response: Tea; payload: Tea }>()({
20
+ endpoint: ":teaId",
21
+ method: "setDoc",
22
+ })
23
+ .setParams({ teaId: 1 })
24
+ .setPayload(newData);
25
+
26
+ await setReq.send();
27
+ const { data } = await getReq.send();
28
+
29
+ expect(data).toStrictEqual({ ...newData, __key: "1" });
30
+ });
31
+ it("should merge data if merge options is passed", async () => {
32
+ const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
33
+ const getReq = client
34
+ .createRequest<{ response: Tea }>()({
35
+ endpoint: ":teaId",
36
+ method: "getDoc",
37
+ })
38
+ .setParams({ teaId: 1 });
39
+ const { data: existingData } = await getReq.send();
40
+ const setReq = client
41
+ .createRequest<{ response: Tea; payload: Tea }>()({
42
+ endpoint: ":teaId",
43
+ method: "setDoc",
44
+ options: { merge: true },
45
+ })
46
+ .setParams({ teaId: 1 })
47
+ .setPayload({ name: "Pou Ran Do Cha" } as Tea);
48
+
49
+ await setReq.send();
50
+ const { data } = await getReq.send();
51
+
52
+ expect(data).toStrictEqual({ ...existingData, name: "Pou Ran Do Cha" });
53
+ // expect(extra.snapshot.exists()).toBe(true);
54
+ });
55
+ it("should emit lifecycle events", async () => {
56
+ const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
57
+
58
+ const request = client
59
+ .createRequest<{ response: Tea; payload: Tea }>()({
60
+ endpoint: ":teaId",
61
+ method: "setDoc",
62
+ options: { merge: true },
63
+ })
64
+ .setParams({ teaId: 1 })
65
+ .setPayload({ name: "Pou Ran Do Cha" } as Tea);
66
+
67
+ await testLifecycleEvents(request);
68
+ });
69
+ });
70
+ };
@@ -0,0 +1,40 @@
1
+ import { Client } from "@hyper-fetch/core";
2
+
3
+ import type { FirebaseAdminAdapter } from "adapter";
4
+ import type { Tea } from "../../../../utils";
5
+ import { testLifecycleEvents } from "../../../../shared/request-events.shared";
6
+
7
+ export const updateDocTestSuite = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
8
+ describe("updateDoc", () => {
9
+ it("should allow for updating data", async () => {
10
+ const newData = { name: "Pou Ran Do Cha", amount: 100, year: 966 } as Tea;
11
+ const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
12
+ const updateReq = client
13
+ .createRequest<{ response: Tea; payload: Tea }>()({
14
+ endpoint: ":teaId",
15
+ method: "updateDoc",
16
+ })
17
+ .setPayload(newData);
18
+ const getReq = client.createRequest<{ response: Tea }>()({
19
+ endpoint: ":teaId",
20
+ method: "getDoc",
21
+ });
22
+ await updateReq.send({ params: { teaId: 1 } });
23
+ const { data } = await getReq.send({ params: { teaId: 1 } });
24
+ expect(data).toStrictEqual({ ...newData, origin: "China", type: "Green", __key: "1" });
25
+ });
26
+ it("should emit lifecycle events", async () => {
27
+ const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
28
+ const newData = { name: "Pou Ran Do Cha", amount: 100, year: 966 } as Tea;
29
+
30
+ const request = client
31
+ .createRequest<{ response: Tea; payload: Tea }>()({
32
+ endpoint: ":teaId",
33
+ method: "updateDoc",
34
+ })
35
+ .setPayload(newData);
36
+
37
+ await testLifecycleEvents(request);
38
+ });
39
+ });
40
+ };
@@ -0,0 +1,24 @@
1
+ import type { FirebaseAdminAdapter, FirebaseAdminAdapterTypes, FirebaseAdminSocketAdapterTypes } from "adapter";
2
+ import { addDocTestSuite } from "./methods/add-doc.test.suite";
3
+ import { deleteDocTestSuite } from "./methods/delete-doc.test.suite";
4
+ import { getDocTestSuite } from "./methods/get-doc.test.suite";
5
+ import { getDocsTestSuite } from "./methods/get-docs.test.suite";
6
+ import { setDocTestSuite } from "./methods/set-doc.test.suite";
7
+ import { updateDocTestSuite } from "./methods/update-doc.test.suite";
8
+ import { onSnapshotTestSuite } from "./methods/on-snapshot.test.suite";
9
+
10
+ export const methodsSharedTestCases = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
11
+ addDocTestSuite(adapterFunction);
12
+ deleteDocTestSuite(adapterFunction);
13
+ getDocTestSuite(adapterFunction);
14
+ getDocsTestSuite(adapterFunction);
15
+ setDocTestSuite(adapterFunction);
16
+ updateDocTestSuite(adapterFunction);
17
+ };
18
+
19
+ export const socketsMethodsSharedTestCases = (
20
+ adapter: FirebaseAdminSocketAdapterTypes<any>,
21
+ coreAdapter: FirebaseAdminAdapterTypes<any>,
22
+ ) => {
23
+ onSnapshotTestSuite(adapter, coreAdapter);
24
+ };
@@ -0,0 +1,15 @@
1
+ import { FirebaseAdminAdapter } from "adapter";
2
+ import { seedRealtimeDatabaseAdmin } from "../../../utils/seed.admin";
3
+ import { realtimeDbAdmin } from "../../../utils";
4
+ import { constraintsSharedTestCases } from "../shared/constraints.shared.tests";
5
+
6
+ describe("Realtime Database Admin [Constraints]", () => {
7
+ let db: any;
8
+ beforeEach(async () => {
9
+ db = await realtimeDbAdmin;
10
+ await db.ref("teas").set(null);
11
+ await seedRealtimeDatabaseAdmin(db);
12
+ });
13
+
14
+ constraintsSharedTestCases(() => FirebaseAdminAdapter(db));
15
+ });
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @vitest-environment node
3
+ */
4
+ import { realtimeDbAdmin, seedRealtimeDatabaseAdmin } from "../../../utils";
5
+ import { FirebaseAdminAdapter } from "adapter";
6
+ import { methodsSharedTestCases } from "../shared/methods.shared.tests";
7
+
8
+ describe("Realtime Database Admin [ Methods ]", () => {
9
+ let db: any;
10
+
11
+ beforeAll(async () => {
12
+ db = await realtimeDbAdmin;
13
+ });
14
+ beforeEach(async () => {
15
+ await db.ref("teas").set(null);
16
+ await seedRealtimeDatabaseAdmin(db);
17
+ });
18
+
19
+ afterEach(async () => {
20
+ await db.ref("teas").set(null);
21
+ });
22
+
23
+ methodsSharedTestCases(() => FirebaseAdminAdapter(db));
24
+ });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @vitest-environment node
3
+ */
4
+ import { realtimeDbAdmin, seedRealtimeDatabaseAdmin } from "../../../utils";
5
+ import { socketsMethodsSharedTestCases } from "../shared/methods.shared.tests";
6
+ import { FirebaseSocketsAdminAdapter, FirebaseAdminAdapter } from "adapter";
7
+
8
+ describe("Realtime Database Admin [Sockets]", () => {
9
+ socketsMethodsSharedTestCases(
10
+ realtimeDbAdmin,
11
+ seedRealtimeDatabaseAdmin,
12
+ FirebaseSocketsAdminAdapter,
13
+ FirebaseAdminAdapter,
14
+ );
15
+ });
@@ -0,0 +1,57 @@
1
+ import { Client } from "@hyper-fetch/core";
2
+
3
+ import type { FirebaseAdminAdapter } from "../../../../src";
4
+ import { $endAt, $limitToFirst, $orderByChild, $startAt } from "../../../../src";
5
+ import type { Tea } from "../../../utils";
6
+
7
+ export const constraintsSharedTestCases = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
8
+ describe("Ordering", () => {
9
+ it("Should allow ordering by child", async () => {
10
+ const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
11
+ const req = client.createRequest<{ response: Tea[] }>()({
12
+ endpoint: "",
13
+ method: "getDocs",
14
+ });
15
+ const { data } = await req.send({
16
+ queryParams: { constraints: [$orderByChild("origin")] },
17
+ });
18
+ expect(data?.map((el) => el.origin)).toStrictEqual([
19
+ "China",
20
+ "China",
21
+ "China",
22
+ "China",
23
+ "China",
24
+ "China",
25
+ "China",
26
+ "Japan",
27
+ "Taiwan",
28
+ "Taiwan",
29
+ ]);
30
+ });
31
+ });
32
+ describe("Filtering and ordering", () => {
33
+ it("Should allow to limit the result and order it", async () => {
34
+ const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
35
+ const req = client.createRequest<{ response: Tea[] }>()({
36
+ endpoint: "",
37
+ method: "getDocs",
38
+ });
39
+ const { data } = await req.send({
40
+ queryParams: { constraints: [$orderByChild("origin"), $limitToFirst(5)] },
41
+ });
42
+ expect(data?.map((tea) => tea.origin)).toStrictEqual(["China", "China", "China", "China", "China"]);
43
+ });
44
+ it("Should allow to combine multiple filters", async () => {
45
+ const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
46
+ const req = client.createRequest<{ response: Tea[] }>()({
47
+ endpoint: "",
48
+ method: "getDocs",
49
+ });
50
+ const { data } = await req.send({
51
+ queryParams: { constraints: [$orderByChild("year"), $startAt(2021), $endAt(2022)] },
52
+ });
53
+ expect(data).toHaveLength(5);
54
+ expect(data?.map((tea) => tea.year)).toStrictEqual([2021, 2021, 2021, 2022, 2022]);
55
+ });
56
+ });
57
+ };
@@ -0,0 +1,64 @@
1
+ import { Client } from "@hyper-fetch/core";
2
+
3
+ import type { FirebaseAdminAdapter } from "adapter";
4
+ import { testLifecycleEvents } from "../../../../shared/request-events.shared";
5
+ import type { Tea } from "../../../../utils";
6
+
7
+ export const getTestSuite = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
8
+ describe("get", () => {
9
+ let client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
10
+ let clientBees = new Client({ url: "bees/" }).setAdapter(adapterFunction());
11
+ beforeEach(() => {
12
+ clientBees = new Client({ url: "bees/" }).setAdapter(adapterFunction());
13
+ client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
14
+ });
15
+
16
+ it("should return data available for endpoint", async () => {
17
+ const req = client.createRequest<{ response: Tea[] }>()({
18
+ endpoint: "",
19
+ method: "get",
20
+ });
21
+ const { data, extra, status, success, error } = await req.send();
22
+ expect(data).toHaveLength(10);
23
+ expect(data![0]).toHaveProperty("__key");
24
+ expect(extra).toHaveProperty("snapshot");
25
+ expect(extra).toHaveProperty("ref");
26
+ expect(status).toBe("success");
27
+ expect(success).toBe(true);
28
+ expect(error).toBe(null);
29
+ });
30
+ it("should return data for dynamic endpoint", async () => {
31
+ const req = client
32
+ .createRequest<{ response: Tea }>()({
33
+ endpoint: ":teaId",
34
+ method: "get",
35
+ })
36
+ .setParams({ teaId: 1 });
37
+
38
+ const { data } = await req.send();
39
+ expect(data).toStrictEqual({ amount: 150, name: "Taiping Hou Kui", origin: "China", type: "Green", year: 2023 });
40
+ });
41
+ it("should return emptyResource status for non existing resource", async () => {
42
+ const req = clientBees
43
+ .createRequest<{ response: Tea }>()({
44
+ endpoint: ":teaId",
45
+ method: "get",
46
+ })
47
+ .setParams({ teaId: 1 });
48
+
49
+ const { data, status } = await req.send();
50
+ expect(data).toStrictEqual(null);
51
+ expect(status).toStrictEqual("emptyResource");
52
+ });
53
+ it("should emit lifecycle events", async () => {
54
+ const req = clientBees
55
+ .createRequest<{ response: Tea }>()({
56
+ endpoint: ":teaId",
57
+ method: "get",
58
+ })
59
+ .setParams({ teaId: 1 });
60
+
61
+ await testLifecycleEvents(req);
62
+ });
63
+ });
64
+ };
@@ -0,0 +1,190 @@
1
+ /* eslint-disable max-params */
2
+ import { Socket } from "@hyper-fetch/sockets";
3
+ import { Client } from "@hyper-fetch/core";
4
+ import waitForExpect from "wait-for-expect";
5
+
6
+ import type { FirebaseAdminAdapterTypes, FirebaseAdminSocketAdapterTypes } from "adapter";
7
+ import type { Tea } from "../../../../utils";
8
+
9
+ export const onValueTestSuite = (
10
+ db: Promise<any>,
11
+ seedDb: (initializedDb: any) => Promise<void>,
12
+ socketsAdapter: (database: any) => FirebaseAdminSocketAdapterTypes<any>,
13
+ coreAdapter: (database: any) => FirebaseAdminAdapterTypes<any>,
14
+ ) => {
15
+ describe("when using onValue method", () => {
16
+ let initializedSocketsAdapter: any;
17
+ let initializedCoreAdapter: any;
18
+ let initializedDb: any;
19
+ let spy = vi.fn();
20
+ const newData = { origin: "Poland", type: "Green", year: 2043, name: "Pou Ran Do Cha", amount: 100 } as Tea;
21
+
22
+ beforeAll(async () => {
23
+ initializedDb = await db;
24
+ initializedSocketsAdapter = socketsAdapter(initializedDb);
25
+ initializedCoreAdapter = coreAdapter(initializedDb);
26
+ });
27
+
28
+ beforeEach(async () => {
29
+ await seedDb(initializedDb);
30
+ });
31
+
32
+ const initialize = async () => {
33
+ const client = new Client({ url: "teas/" }).setAdapter(initializedCoreAdapter);
34
+ const socket = new Socket({ url: "teas/", adapter: initializedSocketsAdapter });
35
+ const pushReq = client
36
+ .createRequest<{ response: Tea; payload: Tea }>()({
37
+ endpoint: "",
38
+ method: "push",
39
+ })
40
+ .setPayload(newData);
41
+ const socketBees = new Socket({ url: "bees/", adapter: initializedSocketsAdapter });
42
+
43
+ return { client, socket, pushReq, socketBees };
44
+ };
45
+
46
+ beforeEach(() => {
47
+ vi.resetAllMocks();
48
+ vi.clearAllMocks();
49
+ spy = vi.fn();
50
+ });
51
+
52
+ it("should return unmount function", async () => {
53
+ const { socket } = await initialize();
54
+ const onValueReq = socket.createListener<Tea[]>()({
55
+ topic: "",
56
+ });
57
+ const unmount = onValueReq.listen(spy);
58
+ expect(typeof unmount).toBe("function");
59
+ });
60
+
61
+ it("should unmount listeners", async () => {
62
+ const { socket, pushReq } = await initialize();
63
+ const onValueReq = socket.createListener<Tea[]>()({
64
+ topic: "",
65
+ });
66
+ const unmount = onValueReq.listen(spy);
67
+
68
+ await waitForExpect(async () => {
69
+ expect(spy).toHaveBeenCalledTimes(1);
70
+ });
71
+
72
+ unmount();
73
+
74
+ await pushReq.send();
75
+ await pushReq.send();
76
+
77
+ await waitForExpect(async () => {
78
+ expect(spy).toHaveBeenCalledTimes(1);
79
+ }, 1000);
80
+
81
+ expect(socket.adapter.listeners.get(onValueReq.topic)?.size).toBe(0);
82
+ });
83
+
84
+ it("should return emptyResource status", async () => {
85
+ const { socketBees } = await initialize();
86
+ const onValueReq = socketBees.createListener<Tea[]>()({
87
+ topic: "",
88
+ options: { onlyOnce: false },
89
+ });
90
+
91
+ let receivedData: any;
92
+ let receivedExtra: any;
93
+
94
+ const unmount = onValueReq.listen(({ data, extra }) => {
95
+ spy();
96
+ receivedData = data;
97
+ receivedExtra = extra;
98
+ });
99
+
100
+ await waitForExpect(async () => {
101
+ expect(spy).toHaveBeenCalled();
102
+ expect(receivedData).toBeNull();
103
+ expect(receivedExtra.status).toBe("emptyResource");
104
+ });
105
+
106
+ unmount();
107
+ });
108
+
109
+ it("should be called once with onlyOnce option", async () => {
110
+ const { socket, pushReq } = await initialize();
111
+ const onValueReq = socket.createListener<Tea[]>()({
112
+ topic: "",
113
+ options: { onlyOnce: true },
114
+ });
115
+
116
+ const unmount = onValueReq.listen(spy);
117
+
118
+ await pushReq.send();
119
+
120
+ await waitForExpect(async () => {
121
+ expect(spy).toHaveBeenCalledTimes(1);
122
+ });
123
+
124
+ unmount();
125
+ });
126
+
127
+ it("should receive updates", async () => {
128
+ const { socket, pushReq } = await initialize();
129
+
130
+ const onValueReq = socket.createListener<Tea[]>()({
131
+ topic: "",
132
+ options: { onlyOnce: false },
133
+ });
134
+
135
+ let receivedData: Tea[] | null;
136
+ let receivedExtra: any;
137
+
138
+ const unmount = onValueReq.listen(({ data, extra }) => {
139
+ spy();
140
+ receivedData = data;
141
+ receivedExtra = extra;
142
+ });
143
+
144
+ const { data } = await pushReq.send();
145
+
146
+ await waitForExpect(async () => {
147
+ expect(receivedData).toEqual(expect.arrayContaining([{ ...newData, __key: data?.__key }]));
148
+ expect(receivedExtra).toHaveProperty("snapshot");
149
+ expect(receivedExtra).toHaveProperty("status");
150
+ expect(receivedExtra).toHaveProperty("ref");
151
+ expect(receivedExtra.status).toBe("success");
152
+ });
153
+
154
+ unmount();
155
+ });
156
+
157
+ it("should return data available for doc", async () => {
158
+ const { socket } = await initialize();
159
+ const onValueReq = socket
160
+ .createListener<Tea[]>()({
161
+ topic: ":teaId",
162
+ })
163
+ .setParams({ teaId: 1 });
164
+
165
+ let receivedData: any;
166
+ let receivedExtra: any;
167
+ const unmount = onValueReq.listen(({ data, extra }) => {
168
+ spy();
169
+ receivedData = data;
170
+ receivedExtra = extra;
171
+ });
172
+
173
+ await waitForExpect(async () => {
174
+ expect(receivedData).toStrictEqual({
175
+ __key: "1",
176
+ amount: 150,
177
+ name: "Taiping Hou Kui",
178
+ origin: "China",
179
+ type: "Green",
180
+ year: 2023,
181
+ });
182
+ expect(receivedExtra).toHaveProperty("snapshot");
183
+ expect(receivedExtra).toHaveProperty("ref");
184
+ expect(receivedExtra.status).toBe("success");
185
+ });
186
+
187
+ unmount();
188
+ });
189
+ });
190
+ };
@@ -0,0 +1,48 @@
1
+ import { Client } from "@hyper-fetch/core";
2
+
3
+ import type { FirebaseAdminAdapter } from "adapter";
4
+ import { testLifecycleEvents } from "../../../../shared/request-events.shared";
5
+ import type { Tea } from "../../../../utils";
6
+
7
+ export const pushTestSuite = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
8
+ describe("push", () => {
9
+ let client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
10
+ beforeEach(() => {
11
+ client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
12
+ });
13
+
14
+ it("should allow for adding data to a list", async () => {
15
+ const newData = { origin: "Poland", type: "Green", year: 2023, name: "Pou Ran Do Cha", amount: 100 } as Tea;
16
+ const getReq = client.createRequest<{ response: Tea[] }>()({
17
+ endpoint: "",
18
+ method: "getDoc",
19
+ });
20
+ const pushReq = client
21
+ .createRequest<{ response: Tea; payload: Tea }>()({
22
+ endpoint: "",
23
+ method: "setDoc",
24
+ options: {},
25
+ })
26
+ .setPayload(newData);
27
+ const { data: pushedData, extra } = await pushReq.send();
28
+ const { data } = await getReq.send();
29
+
30
+ expect(data).toHaveLength(11);
31
+ expect(data).toContainEqual({ ...newData, __key: pushedData?.__key });
32
+ expect(extra).toHaveProperty("key");
33
+ });
34
+ it("should emit lifecycle events", async () => {
35
+ const newData = { origin: "Poland", type: "Green", year: 2043, name: "Pou Ran Do Cha", amount: 100 } as Tea;
36
+
37
+ const pushReq = client
38
+ .createRequest<{ response: Tea; payload: Tea }>()({
39
+ endpoint: "teas/",
40
+ method: "setDoc",
41
+ options: {},
42
+ })
43
+ .setPayload(newData);
44
+
45
+ await testLifecycleEvents(pushReq);
46
+ });
47
+ });
48
+ };
@@ -0,0 +1,46 @@
1
+ import { Client } from "@hyper-fetch/core";
2
+
3
+ import type { FirebaseAdminAdapter } from "adapter";
4
+ import { testLifecycleEvents } from "../../../../shared/request-events.shared";
5
+ import type { Tea } from "../../../../utils";
6
+
7
+ export const removeTestSuite = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
8
+ let client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
9
+ beforeEach(() => {
10
+ client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
11
+ });
12
+ describe("remove", () => {
13
+ it("should allow for removing data", async () => {
14
+ const getReq = client
15
+ .createRequest<{ response: Tea }>()({
16
+ endpoint: ":teaId",
17
+ method: "getDoc",
18
+ })
19
+ .setParams({ teaId: 1 });
20
+
21
+ const removeReq = client
22
+ .createRequest<{ response: Tea }>()({
23
+ endpoint: ":teaId",
24
+ method: "deleteDoc",
25
+ })
26
+ .setParams({ teaId: 1 });
27
+
28
+ await removeReq.send();
29
+ const { data, extra } = await getReq.send();
30
+ expect(data).toBe(null);
31
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
32
+ // @ts-ignore
33
+ expect(extra?.snapshot?.exists()).toBe(false);
34
+ });
35
+ it("should emit lifecycle events", async () => {
36
+ const removeReq = client
37
+ .createRequest<{ response: Tea }>()({
38
+ endpoint: ":teaId",
39
+ method: "deleteDoc",
40
+ })
41
+ .setParams({ teaId: 1 });
42
+
43
+ await testLifecycleEvents(removeReq);
44
+ });
45
+ });
46
+ };
@@ -0,0 +1,70 @@
1
+ import { Client } from "@hyper-fetch/core";
2
+
3
+ import type { FirebaseAdminAdapter, RealtimeDbGetMethodExtra } from "adapter";
4
+ import { testLifecycleEvents } from "../../../../shared/request-events.shared";
5
+ import type { Tea } from "../../../../utils";
6
+
7
+ export const setTestSuite = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
8
+ describe("set", () => {
9
+ let client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
10
+ beforeEach(() => {
11
+ client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
12
+ });
13
+ it("should set data", async () => {
14
+ const newData = { origin: "Poland", type: "Green", year: 2023, name: "Pou Ran Do Cha", amount: 10 } as Tea;
15
+
16
+ const getReq = client
17
+ .createRequest<{ response: Tea }>()({
18
+ endpoint: ":teaId",
19
+ method: "get",
20
+ })
21
+ .setParams({ teaId: 1 });
22
+ const setReq = client
23
+ .createRequest<{ response: Tea; payload: Tea }>()({
24
+ endpoint: ":teaId",
25
+ method: "set",
26
+ })
27
+ .setParams({ teaId: 1 })
28
+ .setPayload(newData);
29
+
30
+ await setReq.send();
31
+ const { data, extra } = await getReq.send();
32
+ expect(data).toStrictEqual(newData);
33
+ expect(extra).not.toBeNull();
34
+ expect((extra as RealtimeDbGetMethodExtra).snapshot.exists()).toBe(true);
35
+ });
36
+ it("should allow for removing data via set", async () => {
37
+ const getReq = client
38
+ .createRequest<{ response: Tea | null }>()({
39
+ endpoint: ":teaId",
40
+ method: "get",
41
+ })
42
+ .setParams({ teaId: 1 });
43
+
44
+ const setReq = client
45
+ .createRequest<{ response: Tea | null; payload: { data: null } }>()({
46
+ endpoint: ":teaId",
47
+ method: "set",
48
+ })
49
+ .setParams({ teaId: 1 })
50
+ .setPayload({ data: null });
51
+
52
+ await setReq.send();
53
+ const { data, extra } = await getReq.send();
54
+ expect(data).toBe(null);
55
+ expect(extra).not.toBeNull();
56
+ expect((extra as RealtimeDbGetMethodExtra).snapshot.exists()).toBe(false);
57
+ });
58
+ it("should emit lifecycle events", async () => {
59
+ const setReq = client
60
+ .createRequest<{ response: Tea | null; payload: { data: null } }>()({
61
+ endpoint: ":teaId",
62
+ method: "set",
63
+ })
64
+ .setParams({ teaId: 1 })
65
+ .setPayload({ data: null });
66
+
67
+ await testLifecycleEvents(setReq);
68
+ });
69
+ });
70
+ };