@hyper-fetch/firebase-admin 7.5.1 → 7.5.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/__tests__/features/firestore/admin/constraints.admin.spec.ts +23 -0
- package/__tests__/features/firestore/admin/methods.admin.spec.ts +20 -0
- package/__tests__/features/firestore/admin/sockets.base.spec.ts +17 -0
- package/__tests__/features/firestore/shared/constraints.shared.tests.ts +72 -0
- package/__tests__/features/firestore/shared/methods/add-doc.test.suite.ts +29 -0
- package/__tests__/features/firestore/shared/methods/delete-doc.test.suite.ts +52 -0
- package/__tests__/features/firestore/shared/methods/get-doc.test.suite.ts +60 -0
- package/__tests__/features/firestore/shared/methods/get-docs.test.suite.ts +45 -0
- package/__tests__/features/firestore/shared/methods/on-snapshot.test.suite.ts +290 -0
- package/__tests__/features/firestore/shared/methods/set-doc.test.suite.ts +70 -0
- package/__tests__/features/firestore/shared/methods/update-doc.test.suite.ts +40 -0
- package/__tests__/features/firestore/shared/methods.shared.tests.ts +24 -0
- package/__tests__/features/realtime/admin/constraints.admin.spec.ts +15 -0
- package/__tests__/features/realtime/admin/methods.admin.spec.ts +24 -0
- package/__tests__/features/realtime/admin/sockets.base.spec.ts +15 -0
- package/__tests__/features/realtime/shared/constraints.shared.tests.ts +59 -0
- package/__tests__/features/realtime/shared/methods/get.test.suite.ts +64 -0
- package/__tests__/features/realtime/shared/methods/on-value.test.suite.ts +190 -0
- package/__tests__/features/realtime/shared/methods/push.test.suite.ts +48 -0
- package/__tests__/features/realtime/shared/methods/remove.test.suite.ts +46 -0
- package/__tests__/features/realtime/shared/methods/set.test.suite.ts +68 -0
- package/__tests__/features/realtime/shared/methods/update.test.suite.ts +42 -0
- package/__tests__/features/realtime/shared/methods.shared.tests.ts +25 -0
- package/__tests__/global.d.ts +1 -0
- package/__tests__/jest.setup.ts +8 -0
- package/__tests__/shared/request-events.shared.ts +32 -0
- package/__tests__/tsconfig.json +8 -0
- package/__tests__/utils/database.rules.json +11 -0
- package/__tests__/utils/index.ts +3 -0
- package/__tests__/utils/initialize.firestore.admin.ts +16 -0
- package/__tests__/utils/initialize.realtime.admin.ts +19 -0
- package/__tests__/utils/seed/seed.data.ts +21 -0
- package/__tests__/utils/seed.admin.ts +23 -0
- package/jest.config.ts +9 -0
- package/package.json +1 -1
- package/project.json +4 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment node
|
|
3
|
+
*/
|
|
4
|
+
import { Client } from "@hyper-fetch/core";
|
|
5
|
+
|
|
6
|
+
import { seedFirestoreDatabaseAdmin } from "../../../utils";
|
|
7
|
+
import { firestoreDbAdmin } from "../../../utils/initialize.firestore.admin";
|
|
8
|
+
import { constraintsSharedTestCases } from "../shared/constraints.shared.tests";
|
|
9
|
+
import { FirebaseAdminAdapter } from "adapter";
|
|
10
|
+
|
|
11
|
+
describe("Firestore Admin [ Constraints ]", () => {
|
|
12
|
+
const client = new Client({ url: "teas/" }).setAdapter(FirebaseAdminAdapter(firestoreDbAdmin));
|
|
13
|
+
|
|
14
|
+
beforeEach(async () => {
|
|
15
|
+
await seedFirestoreDatabaseAdmin(firestoreDbAdmin);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
afterEach(async () => {
|
|
19
|
+
await firestoreDbAdmin.recursiveDelete(firestoreDbAdmin.collection("teas"));
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
constraintsSharedTestCases(client);
|
|
23
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment node
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { seedFirestoreDatabaseAdmin } from "../../../utils";
|
|
6
|
+
import { firestoreDbAdmin } from "../../../utils/initialize.firestore.admin";
|
|
7
|
+
import { methodsSharedTestCases } from "../shared/methods.shared.tests";
|
|
8
|
+
import { FirebaseAdminAdapter } from "adapter";
|
|
9
|
+
|
|
10
|
+
describe("Firestore Admin [ Methods ]", () => {
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
await firestoreDbAdmin.recursiveDelete(firestoreDbAdmin.collection("teas"));
|
|
13
|
+
await seedFirestoreDatabaseAdmin(firestoreDbAdmin);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
afterEach(async () => {
|
|
17
|
+
await firestoreDbAdmin.recursiveDelete(firestoreDbAdmin.collection("teas"));
|
|
18
|
+
});
|
|
19
|
+
methodsSharedTestCases(() => FirebaseAdminAdapter(firestoreDbAdmin));
|
|
20
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jest-environment node
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { seedFirestoreDatabaseAdmin } from "../../../utils";
|
|
6
|
+
import { firestoreDbAdmin } from "../../../utils/initialize.firestore.admin";
|
|
7
|
+
import { socketsMethodsSharedTestCases } from "../shared/methods.shared.tests";
|
|
8
|
+
import { FirebaseSocketsAdminAdapter, FirebaseAdminAdapter } from "adapter";
|
|
9
|
+
|
|
10
|
+
describe("Firestore Admin [ Sockets ]", () => {
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
await firestoreDbAdmin.recursiveDelete(firestoreDbAdmin.collection("teas"));
|
|
13
|
+
await seedFirestoreDatabaseAdmin(firestoreDbAdmin);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
socketsMethodsSharedTestCases(FirebaseSocketsAdminAdapter(firestoreDbAdmin), FirebaseAdminAdapter(firestoreDbAdmin));
|
|
17
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Client } from "@hyper-fetch/core";
|
|
2
|
+
|
|
3
|
+
import { FirestoreAdapterType, FirestoreQueryParams } from "adapter";
|
|
4
|
+
import { $limit, $orderBy, $where } from "constraints";
|
|
5
|
+
import { Tea } from "../../../utils";
|
|
6
|
+
|
|
7
|
+
export const constraintsSharedTestCases = (client: Client<Error, FirestoreAdapterType>) => {
|
|
8
|
+
describe("filtering", () => {
|
|
9
|
+
it("should return filtered data based on single filter", async () => {
|
|
10
|
+
const req = client.createRequest<{ response: Tea[]; queryParams: FirestoreQueryParams }>()({
|
|
11
|
+
endpoint: "",
|
|
12
|
+
method: "getDocs",
|
|
13
|
+
});
|
|
14
|
+
const { data } = await req.send({ queryParams: { constraints: [$where("type", "==", "Green")] } });
|
|
15
|
+
expect(data).toHaveLength(3);
|
|
16
|
+
expect(data?.map((tea) => tea.type)).toStrictEqual(["Green", "Green", "Green"]);
|
|
17
|
+
});
|
|
18
|
+
it("should return filtered data based on compound AND filter", async () => {
|
|
19
|
+
const req = client.createRequest<{ response: Tea[]; queryParams: FirestoreQueryParams }>()({
|
|
20
|
+
endpoint: "",
|
|
21
|
+
method: "getDocs",
|
|
22
|
+
});
|
|
23
|
+
const { data } = await req.send({
|
|
24
|
+
queryParams: { constraints: [$where("type", "==", "Green"), $where("amount", ">=", 50)] },
|
|
25
|
+
});
|
|
26
|
+
expect(data).toHaveLength(2);
|
|
27
|
+
expect(data?.map((tea) => tea.type)).toStrictEqual(["Green", "Green"]);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe("ordering", () => {
|
|
31
|
+
it("should allow for returning ordered data", async () => {
|
|
32
|
+
const req = client.createRequest<{ response: Tea[]; queryParams: FirestoreQueryParams }>()({
|
|
33
|
+
endpoint: "",
|
|
34
|
+
method: "getDocs",
|
|
35
|
+
});
|
|
36
|
+
const { data } = await req.send({ queryParams: { constraints: [$orderBy("year")] } });
|
|
37
|
+
expect(data?.map((tea) => tea.year)).toStrictEqual([1980, 2011, 2017, 2021, 2021, 2021, 2022, 2022, 2023, 2023]);
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("limiting", () => {
|
|
41
|
+
it("should allow for limiting returned data", async () => {
|
|
42
|
+
const req = client.createRequest<{ response: Tea[]; queryParams: FirestoreQueryParams }>()({
|
|
43
|
+
endpoint: "",
|
|
44
|
+
method: "getDocs",
|
|
45
|
+
});
|
|
46
|
+
const { data } = await req.send({ queryParams: { constraints: [$limit(5)] } });
|
|
47
|
+
|
|
48
|
+
expect(data).toHaveLength(5);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe("complex contraint", () => {
|
|
52
|
+
it("should allow for filtering, ordering and limiting in the same query", async () => {
|
|
53
|
+
const req = client.createRequest<{ response: Tea[]; queryParams: FirestoreQueryParams }>()({
|
|
54
|
+
endpoint: "",
|
|
55
|
+
method: "getDocs",
|
|
56
|
+
});
|
|
57
|
+
const { data } = await req.send({
|
|
58
|
+
queryParams: { constraints: [$where("type", "==", "Green"), $orderBy("year"), $limit(1)] },
|
|
59
|
+
});
|
|
60
|
+
expect(data).toHaveLength(1);
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
62
|
+
const { __key, ...rest } = data?.[0] || {};
|
|
63
|
+
expect(rest).toStrictEqual({
|
|
64
|
+
name: "Hon.yama Sencha",
|
|
65
|
+
type: "Green",
|
|
66
|
+
origin: "Japan",
|
|
67
|
+
amount: 25,
|
|
68
|
+
year: 2021,
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Client } from "@hyper-fetch/core";
|
|
2
|
+
|
|
3
|
+
import { FirebaseAdminAdapter } from "adapter";
|
|
4
|
+
import { Tea } from "../../../../utils";
|
|
5
|
+
|
|
6
|
+
export const addDocTestSuite = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
|
|
7
|
+
describe("addDoc", () => {
|
|
8
|
+
it("should allow for adding data to a list", async () => {
|
|
9
|
+
const newData = { origin: "Poland", type: "Green", year: 2023, name: "Pou Ran Do Cha", amount: 100 } as Tea;
|
|
10
|
+
const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
|
|
11
|
+
const getReq = client.createRequest<{ response: Tea[] }>()({
|
|
12
|
+
endpoint: "",
|
|
13
|
+
method: "getDocs",
|
|
14
|
+
});
|
|
15
|
+
const pushReq = client
|
|
16
|
+
.createRequest<{ response: Tea; payload: Tea }>()({
|
|
17
|
+
endpoint: "",
|
|
18
|
+
method: "addDoc",
|
|
19
|
+
options: {},
|
|
20
|
+
})
|
|
21
|
+
.setPayload(newData);
|
|
22
|
+
await pushReq.send();
|
|
23
|
+
const { data } = await getReq.send();
|
|
24
|
+
const arrayedData = Object.values(data);
|
|
25
|
+
|
|
26
|
+
expect(arrayedData).toHaveLength(11);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Client } from "@hyper-fetch/core";
|
|
2
|
+
|
|
3
|
+
import { FirebaseAdminAdapter } from "adapter";
|
|
4
|
+
import { Tea } from "../../../../utils";
|
|
5
|
+
import { testLifecycleEvents } from "../../../../shared/request-events.shared";
|
|
6
|
+
|
|
7
|
+
export const deleteDocTestSuite = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
|
|
8
|
+
describe("deleteDoc", () => {
|
|
9
|
+
it("should allow for removing data", async () => {
|
|
10
|
+
const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
|
|
11
|
+
const getReq = client
|
|
12
|
+
.createRequest<{ response: Tea }>()({
|
|
13
|
+
endpoint: ":teaId",
|
|
14
|
+
method: "getDoc",
|
|
15
|
+
})
|
|
16
|
+
.setParams({ teaId: 1 });
|
|
17
|
+
|
|
18
|
+
const removeReq = client
|
|
19
|
+
.createRequest<{ response: Tea }>()({
|
|
20
|
+
endpoint: ":teaId",
|
|
21
|
+
method: "deleteDoc",
|
|
22
|
+
})
|
|
23
|
+
.setParams({ teaId: 1 });
|
|
24
|
+
|
|
25
|
+
const { data: beforeRemoval } = await getReq.send();
|
|
26
|
+
await removeReq.send();
|
|
27
|
+
const { data } = await getReq.send();
|
|
28
|
+
expect(beforeRemoval).toStrictEqual({
|
|
29
|
+
__key: "1",
|
|
30
|
+
amount: 150,
|
|
31
|
+
year: 2023,
|
|
32
|
+
origin: "China",
|
|
33
|
+
name: "Taiping Hou Kui",
|
|
34
|
+
type: "Green",
|
|
35
|
+
});
|
|
36
|
+
expect(data).toBe(null);
|
|
37
|
+
// expect(extra.snapshot.exists()).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
it("should emit lifecycle events", async () => {
|
|
40
|
+
const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
|
|
41
|
+
|
|
42
|
+
const request = client
|
|
43
|
+
.createRequest<{ response: Tea }>()({
|
|
44
|
+
endpoint: ":teaId",
|
|
45
|
+
method: "deleteDoc",
|
|
46
|
+
})
|
|
47
|
+
.setParams({ teaId: 1 });
|
|
48
|
+
|
|
49
|
+
await testLifecycleEvents(request);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Client } from "@hyper-fetch/core";
|
|
2
|
+
|
|
3
|
+
import { FirebaseAdminAdapter } from "adapter";
|
|
4
|
+
import { Tea } from "../../../../utils";
|
|
5
|
+
import { testLifecycleEvents } from "../../../../shared/request-events.shared";
|
|
6
|
+
|
|
7
|
+
export const getDocTestSuite = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
|
|
8
|
+
describe("getDoc", () => {
|
|
9
|
+
it("should return data available for endpoint", async () => {
|
|
10
|
+
const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
|
|
11
|
+
const req = client
|
|
12
|
+
.createRequest<{ response: Tea[] }>()({
|
|
13
|
+
endpoint: ":teaId",
|
|
14
|
+
method: "getDoc",
|
|
15
|
+
})
|
|
16
|
+
.setParams({ teaId: 1 });
|
|
17
|
+
const { data, extra, status, success, error } = await req.send();
|
|
18
|
+
expect(data).toStrictEqual({
|
|
19
|
+
amount: 150,
|
|
20
|
+
name: "Taiping Hou Kui",
|
|
21
|
+
origin: "China",
|
|
22
|
+
type: "Green",
|
|
23
|
+
year: 2023,
|
|
24
|
+
__key: "1",
|
|
25
|
+
});
|
|
26
|
+
expect(extra).toHaveProperty("snapshot");
|
|
27
|
+
expect(extra).toHaveProperty("ref");
|
|
28
|
+
expect(status).toBe("success");
|
|
29
|
+
expect(success).toBe(true);
|
|
30
|
+
expect(error).toBe(null);
|
|
31
|
+
});
|
|
32
|
+
it("should return emptyResource status for non existing resource", async () => {
|
|
33
|
+
const client = new Client({ url: "bees/" }).setAdapter(adapterFunction());
|
|
34
|
+
const req = client
|
|
35
|
+
.createRequest<{ response: Tea[] }>()({
|
|
36
|
+
endpoint: ":teaId",
|
|
37
|
+
method: "getDoc",
|
|
38
|
+
})
|
|
39
|
+
.setParams({ teaId: 1 });
|
|
40
|
+
const { data, extra, status, success, error } = await req.send();
|
|
41
|
+
expect(data).toStrictEqual(null);
|
|
42
|
+
expect(extra).toHaveProperty("snapshot");
|
|
43
|
+
expect(extra).toHaveProperty("ref");
|
|
44
|
+
expect(status).toBe("emptyResource");
|
|
45
|
+
expect(success).toBe(true);
|
|
46
|
+
expect(error).toBe(null);
|
|
47
|
+
});
|
|
48
|
+
it("should emit lifecycle events", async () => {
|
|
49
|
+
const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
|
|
50
|
+
const request = client
|
|
51
|
+
.createRequest<{ response: Tea }>()({
|
|
52
|
+
endpoint: ":teaId",
|
|
53
|
+
method: "getDoc",
|
|
54
|
+
})
|
|
55
|
+
.setParams({ teaId: 1 });
|
|
56
|
+
|
|
57
|
+
await testLifecycleEvents(request);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Client } from "@hyper-fetch/core";
|
|
2
|
+
|
|
3
|
+
import { FirebaseAdminAdapter } from "adapter";
|
|
4
|
+
import { Tea } from "../../../../utils";
|
|
5
|
+
import { testLifecycleEvents } from "../../../../shared/request-events.shared";
|
|
6
|
+
|
|
7
|
+
export const getDocsTestSuite = (adapterFunction: () => ReturnType<typeof FirebaseAdminAdapter>) => {
|
|
8
|
+
describe("getDocs", () => {
|
|
9
|
+
it("should return data available for endpoint", 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, extra, status, success, error } = await req.send();
|
|
16
|
+
expect(data).toHaveLength(10);
|
|
17
|
+
expect(extra).toHaveProperty("snapshot");
|
|
18
|
+
expect(extra).toHaveProperty("ref");
|
|
19
|
+
expect(status).toBe("success");
|
|
20
|
+
expect(success).toBe(true);
|
|
21
|
+
expect(error).toBe(null);
|
|
22
|
+
});
|
|
23
|
+
it("should return emptyResource status for non existing resource", async () => {
|
|
24
|
+
const client = new Client({ url: "bees/" }).setAdapter(adapterFunction());
|
|
25
|
+
const req = client.createRequest<{ response: Tea[] }>()({
|
|
26
|
+
endpoint: "",
|
|
27
|
+
method: "getDocs",
|
|
28
|
+
});
|
|
29
|
+
const { data, status, success, error } = await req.send();
|
|
30
|
+
expect(data).toStrictEqual(null);
|
|
31
|
+
expect(status).toBe("emptyResource");
|
|
32
|
+
expect(success).toBe(true);
|
|
33
|
+
expect(error).toBe(null);
|
|
34
|
+
});
|
|
35
|
+
it("should emit lifecycle events", async () => {
|
|
36
|
+
const client = new Client({ url: "teas/" }).setAdapter(adapterFunction());
|
|
37
|
+
const request = client.createRequest<{ response: Tea }>()({
|
|
38
|
+
endpoint: "",
|
|
39
|
+
method: "getDocs",
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
await testLifecycleEvents(request);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
};
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { Client } from "@hyper-fetch/core";
|
|
2
|
+
import { Socket } from "@hyper-fetch/sockets";
|
|
3
|
+
import waitForExpect from "wait-for-expect";
|
|
4
|
+
|
|
5
|
+
import { FirebaseAdminAdapterTypes, FirebaseAdminSocketAdapterTypes } from "adapter";
|
|
6
|
+
import { $where } from "constraints";
|
|
7
|
+
import { Tea } from "../../../../utils";
|
|
8
|
+
|
|
9
|
+
export const onSnapshotTestSuite = (
|
|
10
|
+
adapter: FirebaseAdminSocketAdapterTypes<any>,
|
|
11
|
+
coreAdapter: FirebaseAdminAdapterTypes<any>,
|
|
12
|
+
) => {
|
|
13
|
+
const newData = { origin: "Poland", type: "Green", year: 2043, name: "Pou Ran Do Cha", amount: 100 } as Tea;
|
|
14
|
+
let spy = jest.fn();
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
jest.resetAllMocks();
|
|
17
|
+
jest.clearAllMocks();
|
|
18
|
+
spy = jest.fn();
|
|
19
|
+
});
|
|
20
|
+
const initialize = async () => {
|
|
21
|
+
const client = new Client({ url: "teas/" }).setAdapter(coreAdapter);
|
|
22
|
+
const socket = new Socket({ url: "teas/", adapter });
|
|
23
|
+
const pushReq = client
|
|
24
|
+
.createRequest<{ response: Tea; payload: Tea }>()({
|
|
25
|
+
endpoint: "",
|
|
26
|
+
method: "addDoc",
|
|
27
|
+
})
|
|
28
|
+
.setPayload(newData);
|
|
29
|
+
const socketBees = new Socket({ url: "bees/", adapter });
|
|
30
|
+
|
|
31
|
+
return { client, socket, socketBees, pushReq };
|
|
32
|
+
};
|
|
33
|
+
describe("onSnapshot", () => {
|
|
34
|
+
it("should return unmount function", async () => {
|
|
35
|
+
const { socket } = await initialize();
|
|
36
|
+
const onSnapshotReq = socket.createListener<Tea[]>()({
|
|
37
|
+
topic: "",
|
|
38
|
+
});
|
|
39
|
+
const unmount = onSnapshotReq.listen(spy);
|
|
40
|
+
expect(unmount).toBeFunction();
|
|
41
|
+
});
|
|
42
|
+
it("should unmount listeners", async () => {
|
|
43
|
+
const { socket, pushReq } = await initialize();
|
|
44
|
+
const onSnapshotReq = socket.createListener<Tea[]>()({
|
|
45
|
+
topic: "",
|
|
46
|
+
});
|
|
47
|
+
const unmount = onSnapshotReq.listen(spy);
|
|
48
|
+
|
|
49
|
+
await waitForExpect(async () => {
|
|
50
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
unmount();
|
|
54
|
+
await pushReq.send();
|
|
55
|
+
await pushReq.send();
|
|
56
|
+
|
|
57
|
+
await waitForExpect(async () => {
|
|
58
|
+
expect(spy).toHaveBeenCalledTimes(1);
|
|
59
|
+
}, 1000);
|
|
60
|
+
|
|
61
|
+
expect(socket.adapter.listeners.get(onSnapshotReq.topic)?.size).toBe(0);
|
|
62
|
+
});
|
|
63
|
+
it("should return emptyResource status", async () => {
|
|
64
|
+
const { socketBees } = await initialize();
|
|
65
|
+
const onSnapshotReq = socketBees.createListener<Tea[]>()({
|
|
66
|
+
topic: "",
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
let receivedData: any;
|
|
70
|
+
let receivedExtra: any;
|
|
71
|
+
let ref: any;
|
|
72
|
+
|
|
73
|
+
const unmount = onSnapshotReq.listen(({ data, extra }) => {
|
|
74
|
+
spy();
|
|
75
|
+
receivedData = data;
|
|
76
|
+
receivedExtra = extra;
|
|
77
|
+
ref = extra.ref;
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await waitForExpect(async () => {
|
|
81
|
+
expect(spy).toHaveBeenCalled();
|
|
82
|
+
expect(ref).toBeDefined();
|
|
83
|
+
expect(receivedData).toBeNull();
|
|
84
|
+
expect(receivedExtra.status).toBe("emptyResource");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
unmount();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should return data available for collection", async () => {
|
|
91
|
+
const { socket } = await initialize();
|
|
92
|
+
const onSnapshotReq = socket.createListener<Tea[]>()({
|
|
93
|
+
topic: "",
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
let receivedData: any;
|
|
97
|
+
let receivedExtra: any;
|
|
98
|
+
const unmount = onSnapshotReq.listen(({ data, extra }) => {
|
|
99
|
+
spy();
|
|
100
|
+
receivedData = data;
|
|
101
|
+
receivedExtra = extra;
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
await waitForExpect(async () => {
|
|
105
|
+
expect(receivedData).toHaveLength(10);
|
|
106
|
+
expect(receivedExtra).toHaveProperty("snapshot");
|
|
107
|
+
expect(receivedExtra).toHaveProperty("ref");
|
|
108
|
+
expect(receivedExtra.status).toBe("success");
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
unmount();
|
|
112
|
+
});
|
|
113
|
+
it("should inform about changes when groupByChangeType option is added", async () => {
|
|
114
|
+
const newTeaData = {
|
|
115
|
+
origin: "Poland",
|
|
116
|
+
type: "Green",
|
|
117
|
+
year: 2043,
|
|
118
|
+
name: "Pou Ran Do Cha",
|
|
119
|
+
amount: 100,
|
|
120
|
+
} as Tea;
|
|
121
|
+
const { socket, client } = await initialize();
|
|
122
|
+
const onSnapshotReq = socket.createListener<Tea[]>()({
|
|
123
|
+
topic: "",
|
|
124
|
+
options: { groupByChangeType: true },
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const receivedData: any[] = [];
|
|
128
|
+
const receivedExtra: any[] = [];
|
|
129
|
+
const unmount = onSnapshotReq.listen(({ data, extra }) => {
|
|
130
|
+
spy();
|
|
131
|
+
receivedData.push(data);
|
|
132
|
+
receivedExtra.push(extra);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
await waitForExpect(async () => {
|
|
136
|
+
expect(receivedData).toHaveLength(1);
|
|
137
|
+
expect(receivedData[0]).toHaveLength(10);
|
|
138
|
+
}, 1000);
|
|
139
|
+
|
|
140
|
+
const addTeaReq = client
|
|
141
|
+
.createRequest<{ response: Tea; payload: Tea }>()({
|
|
142
|
+
endpoint: "",
|
|
143
|
+
method: "addDoc",
|
|
144
|
+
})
|
|
145
|
+
.setPayload(newTeaData);
|
|
146
|
+
|
|
147
|
+
await addTeaReq.send();
|
|
148
|
+
|
|
149
|
+
const updateTeaReq = client
|
|
150
|
+
.createRequest<{ response: Tea; payload: Tea }>()({
|
|
151
|
+
endpoint: ":teaId",
|
|
152
|
+
method: "updateDoc",
|
|
153
|
+
})
|
|
154
|
+
.setPayload(newTeaData);
|
|
155
|
+
|
|
156
|
+
await updateTeaReq.send({ params: { teaId: 1 } });
|
|
157
|
+
|
|
158
|
+
const removeReq = client
|
|
159
|
+
.createRequest<{ response: Tea }>()({
|
|
160
|
+
endpoint: ":teaId",
|
|
161
|
+
method: "deleteDoc",
|
|
162
|
+
})
|
|
163
|
+
.setParams({ teaId: 1 });
|
|
164
|
+
await removeReq.send();
|
|
165
|
+
|
|
166
|
+
await waitForExpect(async () => {
|
|
167
|
+
expect(receivedData).toHaveLength(4);
|
|
168
|
+
const [, afterAdd, afterModify, afterRemove] = receivedData;
|
|
169
|
+
const [, afterAddExtra, afterModifyExtra, afterRemoveExtra] = receivedExtra;
|
|
170
|
+
expect(afterAdd).toHaveLength(11);
|
|
171
|
+
expect(afterModify).toHaveLength(11);
|
|
172
|
+
expect(afterRemove).toHaveLength(10);
|
|
173
|
+
expect(afterAddExtra.groupedResult.added).toHaveLength(1);
|
|
174
|
+
expect(afterModifyExtra.groupedResult.added).toHaveLength(0);
|
|
175
|
+
expect(afterModifyExtra.groupedResult.modified).toHaveLength(1);
|
|
176
|
+
expect(afterModifyExtra.groupedResult.removed).toHaveLength(0);
|
|
177
|
+
expect(afterRemoveExtra.groupedResult.added).toHaveLength(0);
|
|
178
|
+
expect(afterRemoveExtra.groupedResult.modified).toHaveLength(0);
|
|
179
|
+
expect(afterRemoveExtra.groupedResult.removed).toHaveLength(1);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
unmount();
|
|
183
|
+
});
|
|
184
|
+
it("should return data available for doc", async () => {
|
|
185
|
+
const { socket } = await initialize();
|
|
186
|
+
const onSnapshotReq = socket
|
|
187
|
+
.createListener<Tea[]>()({
|
|
188
|
+
topic: ":teaId",
|
|
189
|
+
})
|
|
190
|
+
.setParams({ teaId: 1 });
|
|
191
|
+
|
|
192
|
+
let receivedData: any;
|
|
193
|
+
const unmount = onSnapshotReq.listen(({ data }) => {
|
|
194
|
+
spy();
|
|
195
|
+
receivedData = data;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
await waitForExpect(async () => {
|
|
199
|
+
expect(receivedData).toStrictEqual({
|
|
200
|
+
__key: "1",
|
|
201
|
+
amount: 150,
|
|
202
|
+
name: "Taiping Hou Kui",
|
|
203
|
+
origin: "China",
|
|
204
|
+
type: "Green",
|
|
205
|
+
year: 2023,
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
unmount();
|
|
210
|
+
});
|
|
211
|
+
it("should allow for listening to multiple documents and change HF cache if data is changed in firebase after onSnapshot listener creation", async () => {
|
|
212
|
+
const { socket, client } = await initialize();
|
|
213
|
+
const initialCache = [
|
|
214
|
+
{
|
|
215
|
+
__key: "0",
|
|
216
|
+
amount: 50,
|
|
217
|
+
year: 2022,
|
|
218
|
+
origin: "China",
|
|
219
|
+
name: "Bi Luo Chun",
|
|
220
|
+
type: "Green",
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
__key: "1",
|
|
224
|
+
amount: 150,
|
|
225
|
+
year: 2023,
|
|
226
|
+
origin: "China",
|
|
227
|
+
name: "Taiping Hou Kui",
|
|
228
|
+
type: "Green",
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
__key: "2",
|
|
232
|
+
amount: 25,
|
|
233
|
+
year: 2021,
|
|
234
|
+
origin: "Japan",
|
|
235
|
+
name: "Hon.yama Sencha",
|
|
236
|
+
type: "Green",
|
|
237
|
+
},
|
|
238
|
+
];
|
|
239
|
+
|
|
240
|
+
// Should listen for changes only for Green teas
|
|
241
|
+
const onSnapshotReq = socket.createListener<Tea[]>()({
|
|
242
|
+
topic: "",
|
|
243
|
+
options: { constraints: [$where("type", "==", "Green")] },
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
const receivedData: any[] = [];
|
|
247
|
+
const unmount = onSnapshotReq.listen(({ data }) => {
|
|
248
|
+
spy();
|
|
249
|
+
receivedData.push(data);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
await waitForExpect(async () => {
|
|
253
|
+
expect(receivedData).toHaveLength(1);
|
|
254
|
+
expect(receivedData[0]).toIncludeSameMembers(initialCache);
|
|
255
|
+
}, 1000);
|
|
256
|
+
|
|
257
|
+
const shouldCacheData = newData as Tea;
|
|
258
|
+
const shouldNotCacheData = {
|
|
259
|
+
...newData,
|
|
260
|
+
type: "Oolong",
|
|
261
|
+
} as Tea;
|
|
262
|
+
|
|
263
|
+
const shouldCacheAddDocRequest = client
|
|
264
|
+
.createRequest<{ response: Tea; payload: Tea }>()({
|
|
265
|
+
endpoint: "",
|
|
266
|
+
method: "addDoc",
|
|
267
|
+
})
|
|
268
|
+
.setPayload(shouldCacheData);
|
|
269
|
+
const shouldNotCacheAddDocRequest = client
|
|
270
|
+
.createRequest<{ response: Tea; payload: Tea }>()({
|
|
271
|
+
endpoint: "",
|
|
272
|
+
method: "addDoc",
|
|
273
|
+
})
|
|
274
|
+
.setPayload(shouldNotCacheData);
|
|
275
|
+
|
|
276
|
+
const { data } = await shouldCacheAddDocRequest.send();
|
|
277
|
+
|
|
278
|
+
await shouldNotCacheAddDocRequest.send();
|
|
279
|
+
|
|
280
|
+
unmount();
|
|
281
|
+
|
|
282
|
+
await shouldCacheAddDocRequest.send();
|
|
283
|
+
|
|
284
|
+
await waitForExpect(async () => {
|
|
285
|
+
expect(receivedData).toHaveLength(2);
|
|
286
|
+
expect(receivedData[1]).toIncludeSameMembers([...initialCache, data]);
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Client } from "@hyper-fetch/core";
|
|
2
|
+
|
|
3
|
+
import { Tea } from "../../../../utils";
|
|
4
|
+
import { 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
|
+
};
|