emberflow 1.0.20 → 1.0.22

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 (39) hide show
  1. package/lib/index-utils.d.ts +6 -6
  2. package/lib/index-utils.js +29 -59
  3. package/lib/index-utils.js.map +1 -1
  4. package/lib/index.d.ts +6 -3
  5. package/lib/index.js +61 -80
  6. package/lib/index.js.map +1 -1
  7. package/lib/sample-custom/business-logics.js +3 -3
  8. package/lib/sample-custom/business-logics.js.map +1 -1
  9. package/lib/sample-custom/db-structure.d.ts +13 -1
  10. package/lib/sample-custom/db-structure.js +13 -0
  11. package/lib/sample-custom/db-structure.js.map +1 -1
  12. package/lib/sample-custom/security.js +2 -2
  13. package/lib/sample-custom/security.js.map +1 -1
  14. package/lib/sample-custom/validators.js +2 -4
  15. package/lib/sample-custom/validators.js.map +1 -1
  16. package/lib/tests/index-utils.test.js +66 -149
  17. package/lib/tests/index-utils.test.js.map +1 -1
  18. package/lib/tests/index.test.js +246 -299
  19. package/lib/tests/index.test.js.map +1 -1
  20. package/lib/tests/utils/bill-protect.test.js +31 -32
  21. package/lib/tests/utils/bill-protect.test.js.map +1 -1
  22. package/lib/tests/utils/paths.test.js +5 -1
  23. package/lib/tests/utils/paths.test.js.map +1 -1
  24. package/lib/types.d.ts +14 -3
  25. package/lib/utils/bill-protect.d.ts +4 -4
  26. package/lib/utils/bill-protect.js +12 -6
  27. package/lib/utils/bill-protect.js.map +1 -1
  28. package/lib/utils/db-structure.d.ts +1 -1
  29. package/lib/utils/db-structure.js +1 -1
  30. package/lib/utils/db-structure.js.map +1 -1
  31. package/lib/utils/paths.d.ts +6 -2
  32. package/lib/utils/paths.js +9 -2
  33. package/lib/utils/paths.js.map +1 -1
  34. package/package.json +2 -2
  35. package/src/sample-custom/business-logics.ts +4 -3
  36. package/src/sample-custom/db-structure.ts +13 -0
  37. package/src/sample-custom/firestore.rules +2 -1
  38. package/src/sample-custom/security.ts +2 -2
  39. package/src/sample-custom/validators.ts +2 -4
@@ -29,11 +29,13 @@ const admin = __importStar(require("firebase-admin"));
29
29
  const firebase_admin_1 = require("firebase-admin");
30
30
  var Timestamp = firebase_admin_1.firestore.Timestamp;
31
31
  const db_structure_1 = require("../sample-custom/db-structure");
32
- admin.initializeApp();
32
+ const paths = __importStar(require("../utils/paths"));
33
33
  // TODO: Create unit test for all new functions and modified functions
34
34
  const projectConfig = {
35
35
  projectId: "your-project-id",
36
36
  budgetAlertTopicName: "budget-alerts",
37
+ region: "us-central1",
38
+ rtdbName: "rtdb",
37
39
  maxCostLimitPerFunction: 100,
38
40
  specialCostLimitPerFunction: {
39
41
  function1: 50,
@@ -41,179 +43,158 @@ const projectConfig = {
41
43
  function3: 120,
42
44
  },
43
45
  };
44
- const funcName = "testFunction";
46
+ jest.spyOn(admin, "initializeApp").mockImplementation();
47
+ const dataMock = jest.fn().mockReturnValue({});
48
+ const getMock = {
49
+ data: dataMock,
50
+ };
51
+ const docMock = {
52
+ set: jest.fn(),
53
+ get: jest.fn().mockResolvedValue(getMock),
54
+ update: jest.fn(),
55
+ collection: jest.fn(),
56
+ };
57
+ const collectionMock = {
58
+ doc: jest.fn(() => docMock),
59
+ };
60
+ const firestoreMock = jest.spyOn(admin, "firestore")
61
+ .mockImplementation(() => {
62
+ return {
63
+ collection: jest.fn(() => collectionMock),
64
+ doc: jest.fn(() => docMock),
65
+ };
66
+ });
67
+ const refMock = {
68
+ update: jest.fn(),
69
+ };
70
+ const rtdbMock = jest.spyOn(admin, "database")
71
+ .mockImplementation(() => {
72
+ return {
73
+ ref: jest.fn(() => refMock),
74
+ };
75
+ });
76
+ console.log(firestoreMock, rtdbMock);
77
+ const parseEntityMock = jest.fn();
78
+ jest.spyOn(paths, "parseEntity")
79
+ .mockImplementation(parseEntityMock);
80
+ admin.initializeApp();
45
81
  (0, index_1.initializeEmberFlow)(projectConfig, admin, db_structure_1.dbStructure, db_structure_1.Entity, {}, {}, []);
46
- function createDocumentSnapshot(data, refPath, exists = true) {
82
+ function createDocumentSnapshot(form) {
47
83
  return {
48
- exists,
49
- id: "test-id",
84
+ key: "test-id",
50
85
  ref: {
51
- id: "test-id",
52
- path: refPath,
53
- set: jest.fn(),
54
86
  update: jest.fn(),
55
- delete: jest.fn(),
56
- get: jest.fn(),
57
87
  },
58
- data: () => data,
59
- get: jest.fn(),
60
- isEqual: jest.fn(),
61
- create_time: index_1._mockable.createNowTimestamp(),
62
- update_time: index_1._mockable.createNowTimestamp(),
63
- readTime: index_1._mockable.createNowTimestamp(),
88
+ val: () => form,
64
89
  };
65
90
  }
66
- function createChange(beforeData, afterData, refPath) {
91
+ function createEvent(form) {
67
92
  return {
68
- before: createDocumentSnapshot(beforeData, refPath),
69
- after: createDocumentSnapshot(afterData, refPath),
93
+ id: "test-id",
94
+ data: createDocumentSnapshot(form),
95
+ params: {
96
+ formId: "test-fid",
97
+ userId: "test-uid",
98
+ },
70
99
  };
71
100
  }
72
101
  describe("onDocChange", () => {
73
102
  const entity = "user";
74
- const refPath = "/example/test-id";
75
- const contextWithoutAuth = {
76
- auth: undefined,
77
- authType: "ADMIN",
78
- eventId: "test-event-id",
79
- eventType: "test-event-type",
80
- params: {},
81
- resource: {
82
- name: "projects/test-project/databases/(default)/documents/test",
83
- service: "firestore.googleapis.com",
84
- type: "type",
85
- },
86
- timestamp: "2022-03-15T18:52:04.369Z",
87
- };
88
- const contextWithAuth = {
89
- auth: {
90
- uid: "test-uid",
91
- token: {
92
- email: "test-email",
93
- email_verified: true,
94
- name: "test-name",
95
- picture: "test-picture",
96
- sub: "test-sub",
97
- },
98
- },
99
- authType: "ADMIN",
100
- eventId: "test-event-id",
101
- eventType: "test-event-type",
102
- params: {},
103
- resource: {
104
- name: "projects/test-project/databases/(default)/documents/test",
105
- service: "firestore.googleapis.com",
106
- type: "type",
107
- },
108
- timestamp: "2022-03-15T18:52:04.369Z",
103
+ const eventContext = {
104
+ id: "test-id",
105
+ uid: "test-uid",
106
+ formId: "test-fid",
107
+ docId: "test-uid",
108
+ docPath: "users/test-uid",
109
+ entity,
109
110
  };
110
111
  beforeEach(() => {
111
- // ...
112
- jest.spyOn(admin, "initializeApp").mockImplementation();
113
- const docMock = {
114
- set: jest.fn(),
115
- get: jest.fn(),
116
- update: jest.fn(),
117
- delete: jest.fn(),
118
- parent: {},
119
- path: "",
120
- firestore: {},
121
- id: "",
122
- isEqual: jest.fn(),
123
- // Add the missing properties and methods
124
- collection: jest.fn(),
125
- listCollections: jest.fn(),
126
- create: jest.fn(),
127
- onSnapshot: jest.fn(),
128
- withConverter: jest.fn(),
129
- // Add other required properties/methods as needed
130
- };
131
- const collectionMock = {
132
- doc: jest.fn(() => docMock),
133
- // Add other required properties/methods as needed
134
- };
135
- // Mock admin.firestore
136
- const firestoreMock = jest.spyOn(admin, "firestore");
137
- const firestoreInstance = {
138
- collection: jest.fn(() => collectionMock),
139
- settings: jest.fn(),
140
- doc: jest.fn(),
141
- collectionGroup: jest.fn(),
142
- getAll: jest.fn(),
143
- runTransaction: jest.fn(),
144
- batch: jest.fn(),
145
- terminate: jest.fn(),
146
- // Add the missing methods
147
- recursiveDelete: jest.fn(),
148
- listCollections: jest.fn(),
149
- bulkWriter: jest.fn(),
150
- bundle: jest.fn(),
151
- };
152
- firestoreMock.mockImplementation(() => firestoreInstance);
153
112
  // Add the spy for _mockable
154
113
  jest.spyOn(index_1._mockable, "createNowTimestamp").mockReturnValue(Timestamp.now());
155
114
  jest.spyOn(console, "log").mockImplementation();
115
+ jest.spyOn(console, "warn").mockImplementation();
116
+ parseEntityMock.mockReturnValue({
117
+ entity: "user",
118
+ entityId: "test-uid",
119
+ });
120
+ refMock.update.mockReset();
156
121
  });
157
- afterEach(() => {
158
- jest.restoreAllMocks();
159
- });
160
- it("should not execute when auth is null", async () => {
161
- const change = createChange({}, {}, refPath);
162
- await (0, index_1.onDocChange)(funcName, entity, change, contextWithoutAuth, "delete");
163
- expect(console.log).toHaveBeenCalledWith("Auth is null, then this change is initiated by the service account and should be ignored");
164
- expect(console.log).toHaveBeenCalledTimes(1);
165
- });
166
- it("should re-add deleted document", async () => {
167
- const deletedDocumentData = {
168
- field1: "value1",
169
- field2: "value2",
122
+ it("should return when there's no matched entity", async () => {
123
+ const formData = {
124
+ "field1": "newValue",
125
+ "field2": "oldValue",
126
+ "@actionType": "update",
127
+ "@status": "submit",
128
+ "@docPath": "users/test-uid",
170
129
  };
171
- const change = createChange(deletedDocumentData, null, refPath);
172
- await (0, index_1.onDocChange)(funcName, entity, change, contextWithAuth, "delete");
173
- expect(change.after.ref.set).toHaveBeenCalledWith(deletedDocumentData);
174
- expect(change.after.ref.set).toHaveBeenCalledTimes(1);
175
- expect(console.log).toHaveBeenCalledWith("Document re-added with ID test-id");
176
- expect(console.log).toHaveBeenCalledTimes(4);
177
- });
178
- it("should revert modifications outside form", async () => {
179
- const beforeData = {
180
- field1: "oldValue",
181
- field2: "oldValue",
182
- field3: {
130
+ const event = createEvent(formData);
131
+ const document = {
132
+ "field1": "oldValue",
133
+ "field2": "oldValue",
134
+ "field3": {
183
135
  nestedField1: "oldValue",
184
136
  nestedField2: "oldValue",
185
137
  },
186
138
  };
187
- const afterData = {
139
+ dataMock.mockReturnValue(document);
140
+ parseEntityMock.mockReturnValue({
141
+ entityId: "test-id",
142
+ });
143
+ await (0, index_1.onFormSubmit)(event);
144
+ expect(refMock.update).toHaveBeenCalledWith({
145
+ "@status": "error",
146
+ "@message": "docPath does not match any known Entity",
147
+ });
148
+ expect(console.warn).toHaveBeenCalledWith("docPath does not match any known Entity");
149
+ });
150
+ it("should return when target docPath is not allowed for given userId", async () => {
151
+ const formData = {
188
152
  "field1": "newValue",
189
153
  "field2": "oldValue",
154
+ "@actionType": "update",
155
+ "@status": "submit",
156
+ "@docPath": "users/another-user-id",
157
+ };
158
+ const event = createEvent(formData);
159
+ const document = {
160
+ "field1": "oldValue",
161
+ "field2": "oldValue",
190
162
  "field3": {
191
- nestedField1: "newValue",
163
+ nestedField1: "oldValue",
192
164
  nestedField2: "oldValue",
193
165
  },
194
- "@form": {
195
- "@actionType": "update",
196
- "@status": "submit",
197
- },
198
166
  };
199
- const change = createChange(beforeData, afterData, refPath);
200
- // Mock validateForm to return a validation error
201
- jest.spyOn(indexutils, "validateForm").mockResolvedValue([
202
- true,
203
- {
204
- field1: ["error message 1"],
205
- field2: ["error message 2"],
167
+ dataMock.mockReturnValue(document);
168
+ await (0, index_1.onFormSubmit)(event);
169
+ expect(refMock.update).toHaveBeenCalledWith({
170
+ "@status": "error",
171
+ "@message": "User id from path does not match user id from event params",
172
+ });
173
+ expect(console.warn).toHaveBeenCalledWith("User id from path does not match user id from event params");
174
+ });
175
+ it("should return when there's no provided @actionType", async () => {
176
+ const formData = {
177
+ "field1": "newValue",
178
+ "field2": "oldValue",
179
+ "@status": "submit",
180
+ "@docPath": "users/test-uid",
181
+ };
182
+ const event = createEvent(formData);
183
+ const document = {
184
+ "field1": "oldValue",
185
+ "field2": "oldValue",
186
+ "field3": {
187
+ nestedField1: "oldValue",
188
+ nestedField2: "oldValue",
206
189
  },
207
- ]);
208
- const revertModificationsOutsideFormMock = jest.spyOn(indexutils, "revertModificationsOutsideForm").mockResolvedValue();
209
- await (0, index_1.onDocChange)(funcName, "user", change, contextWithAuth, "update");
210
- expect(revertModificationsOutsideFormMock).toHaveBeenCalledWith(afterData, beforeData, change.after);
211
- expect(indexutils.validateForm).toHaveBeenCalledWith("user", afterData, refPath);
212
- expect(change.after.ref.update).toHaveBeenCalledWith({
213
- "@form.@status": "form-validation-failed",
214
- "@form.@message": { "field1": ["error message 1"], "field2": ["error message 2"] },
190
+ };
191
+ dataMock.mockReturnValue(document);
192
+ await (0, index_1.onFormSubmit)(event);
193
+ expect(refMock.update).toHaveBeenCalledWith({
194
+ "@status": "error",
195
+ "@message": "No @actionType found",
215
196
  });
216
- expect(change.after.ref.update).toHaveBeenCalledTimes(1);
197
+ expect(console.warn).toHaveBeenCalledWith("No @actionType found");
217
198
  });
218
199
  it("should return on security check failure", async () => {
219
200
  const getSecurityFnMock = jest.spyOn(indexutils, "getSecurityFn");
@@ -223,135 +204,101 @@ describe("onDocChange", () => {
223
204
  };
224
205
  const securityFnMock = jest.fn().mockResolvedValue(rejectedSecurityResult);
225
206
  getSecurityFnMock.mockReturnValue(securityFnMock);
226
- const beforeData = {
227
- "field1": "oldValue",
207
+ const formData = {
208
+ "field1": "newValue",
228
209
  "field2": "oldValue",
229
- "field3": {
230
- nestedField1: "oldValue",
231
- nestedField2: "oldValue",
232
- },
233
- "@form": {
234
- "field1": "oldValue",
235
- "field2": "oldValue",
236
- "@status": "submit",
237
- },
210
+ "@actionType": "update",
211
+ "@status": "submit",
212
+ "@docPath": "users/test-uid",
238
213
  };
239
- const afterData = {
214
+ const event = createEvent(formData);
215
+ const document = {
240
216
  "field1": "oldValue",
241
217
  "field2": "oldValue",
242
218
  "field3": {
243
219
  nestedField1: "oldValue",
244
220
  nestedField2: "oldValue",
245
221
  },
246
- "@form": {
247
- "field1": "newValue",
248
- "field2": "oldValue",
249
- "@actionType": "update",
250
- "@status": "submit",
251
- },
252
222
  };
253
- const change = createChange(beforeData, afterData, refPath);
223
+ dataMock.mockReturnValue(document);
254
224
  const validateFormMock = jest.spyOn(indexutils, "validateForm");
255
225
  validateFormMock.mockResolvedValue([false, {}]);
256
- await (0, index_1.onDocChange)(funcName, entity, change, contextWithAuth, "update");
226
+ await (0, index_1.onFormSubmit)(event);
257
227
  expect(getSecurityFnMock).toHaveBeenCalledWith(entity);
258
- expect(validateFormMock).toHaveBeenCalledWith(entity, change.after.data(), refPath);
259
- expect(securityFnMock).toHaveBeenCalledWith(entity, change.after.data(), "update", ["field1"]);
260
- expect(change.after.ref.update).toHaveBeenCalledWith({
261
- "@form.@status": "security-error",
262
- "@form.@message": "Unauthorized access",
228
+ expect(validateFormMock).toHaveBeenCalledWith(entity, event.data.val());
229
+ expect(securityFnMock).toHaveBeenCalledWith(entity, event.data.val(), document, "update", ["field1"]);
230
+ expect(refMock.update).toHaveBeenCalledWith({
231
+ "@status": "security-error",
232
+ "@message": "Unauthorized access",
263
233
  });
264
234
  expect(console.log).toHaveBeenCalledWith(`Security check failed: ${rejectedSecurityResult.message}`);
235
+ getSecurityFnMock.mockReset();
265
236
  });
266
237
  it("should call delayFormSubmissionAndCheckIfCancelled with correct parameters", async () => {
267
- jest.spyOn(indexutils, "revertModificationsOutsideForm").mockResolvedValue();
268
- jest.spyOn(indexutils, "validateForm").mockResolvedValue([false, {}]);
269
- jest.spyOn(indexutils, "getFormModifiedFields").mockReturnValue(["field1", "field2"]);
270
- jest.spyOn(indexutils, "getSecurityFn").mockReturnValue(() => Promise.resolve({ status: "allowed" }));
238
+ const validateFormMock = jest.spyOn(indexutils, "validateForm").mockResolvedValue([false, {}]);
239
+ const getFormModifiedFieldsMock = jest.spyOn(indexutils, "getFormModifiedFields").mockReturnValue(["field1", "field2"]);
240
+ const getSecurityFnMock = jest.spyOn(indexutils, "getSecurityFn").mockReturnValue(() => Promise.resolve({ status: "allowed" }));
271
241
  const delayFormSubmissionAndCheckIfCancelledSpy = jest.spyOn(indexutils, "delayFormSubmissionAndCheckIfCancelled").mockResolvedValue(true);
272
- const doc = {
273
- "@form": {
274
- "@delay": 1000,
275
- "@status": "submit",
276
- "@actionType": "create",
277
- },
242
+ const formData = {
243
+ "@delay": 1000,
244
+ "@status": "submit",
245
+ "@actionType": "create",
278
246
  "someField": "exampleValue",
247
+ "@docPath": "users/test-uid",
279
248
  };
280
- const change = createChange(null, doc, "/example/test-id");
281
- const event = "create";
282
- await (0, index_1.onDocChange)(funcName, "user", change, contextWithAuth, event);
249
+ const event = createEvent(formData);
250
+ await (0, index_1.onFormSubmit)(event);
283
251
  // Test that the delayFormSubmissionAndCheckIfCancelled function is called with the correct parameters
284
- expect(delayFormSubmissionAndCheckIfCancelledSpy).toHaveBeenCalledWith(1000, change.after);
285
- // Test that snapshot.ref.update is called with the correct parameters
286
- expect(change.after.ref.update).toHaveBeenCalledWith({ "@form.@status": "cancelled" });
287
- });
288
- it("should not process the form if @form.@status is not 'submit'", async () => {
289
- jest.spyOn(indexutils, "revertModificationsOutsideForm").mockResolvedValue();
290
- jest.spyOn(indexutils, "validateForm").mockResolvedValue([false, {}]);
291
- jest.spyOn(indexutils, "getFormModifiedFields").mockReturnValue(["field1", "field2"]);
292
- jest.spyOn(indexutils, "getSecurityFn").mockReturnValue(() => Promise.resolve({ status: "allowed" }));
293
- const delayFormSubmissionAndCheckIfCancelledSpy = jest.spyOn(indexutils, "delayFormSubmissionAndCheckIfCancelled").mockResolvedValue(true);
294
- const doc = {
295
- "@form": {
296
- "@actionType": "create",
297
- "@status": "not-submit",
298
- "@delay": 1000,
299
- },
300
- "someField": "exampleValue",
301
- };
302
- const change = createChange(null, doc, "/example/test-id");
303
- const event = "create";
304
- await (0, index_1.onDocChange)(funcName, "user", change, contextWithAuth, event);
305
- // Test that the delayFormSubmissionAndCheckIfCancelled function is NOT called
306
- expect(indexutils.revertModificationsOutsideForm).toHaveBeenCalled();
307
- expect(indexutils.getFormModifiedFields).not.toHaveBeenCalled();
308
- expect(indexutils.getSecurityFn).not.toHaveBeenCalled();
309
- expect(delayFormSubmissionAndCheckIfCancelledSpy).not.toHaveBeenCalled();
310
- // Test that snapshot.ref.update is NOT called
311
- expect(change.after.ref.update).not.toHaveBeenCalled();
252
+ expect(delayFormSubmissionAndCheckIfCancelledSpy).toHaveBeenCalledWith(1000, refMock);
253
+ expect(refMock.update).toHaveBeenCalledWith({ "@status": "cancelled" });
254
+ validateFormMock.mockReset();
255
+ getFormModifiedFieldsMock.mockReset();
256
+ getSecurityFnMock.mockReset();
257
+ delayFormSubmissionAndCheckIfCancelledSpy.mockReset();
312
258
  });
313
- it("should set @form.@status to 'submitted' after passing all checks", async () => {
314
- jest.spyOn(indexutils, "revertModificationsOutsideForm").mockResolvedValue();
315
- jest.spyOn(indexutils, "validateForm").mockResolvedValue([false, {}]);
316
- jest.spyOn(indexutils, "getFormModifiedFields").mockReturnValue(["field1", "field2"]);
317
- jest.spyOn(indexutils, "getSecurityFn").mockReturnValue(() => Promise.resolve({ status: "allowed" }));
318
- jest.spyOn(indexutils, "delayFormSubmissionAndCheckIfCancelled").mockResolvedValue(false);
319
- const setActionSpy = jest.fn().mockResolvedValue({
259
+ it("should set form @status to 'submitted' after passing all checks", async () => {
260
+ const validateFormMock = jest.spyOn(indexutils, "validateForm").mockResolvedValue([false, {}]);
261
+ const getFormModifiedFieldsMock = jest.spyOn(indexutils, "getFormModifiedFields").mockReturnValue(["field1", "field2"]);
262
+ const getSecurityFnMock = jest.spyOn(indexutils, "getSecurityFn").mockReturnValue(() => Promise.resolve({ status: "allowed" }));
263
+ const delayFormSubmissionAndCheckIfCancelledMock = jest.spyOn(indexutils, "delayFormSubmissionAndCheckIfCancelled").mockResolvedValue(false);
264
+ const setActionMock = jest.fn().mockResolvedValue({
320
265
  update: jest.fn(),
321
266
  });
322
- const updateActionSpy = jest.fn().mockResolvedValue({
267
+ const updateActionMock = jest.fn().mockResolvedValue({
323
268
  update: jest.fn(),
324
269
  });
325
- jest.spyOn(index_1._mockable, "initActionRef").mockResolvedValue({
326
- set: setActionSpy,
327
- update: updateActionSpy,
270
+ const initActionRefMock = jest.spyOn(index_1._mockable, "initActionRef").mockResolvedValue({
271
+ set: setActionMock,
272
+ update: updateActionMock,
328
273
  });
329
- const doc = {
330
- "@form": {
331
- "@actionType": "create",
332
- "name": "test",
333
- "@status": "submit",
334
- },
335
- "someField": "exampleValue",
274
+ const formData = {
275
+ "@actionType": "create",
276
+ "name": "test",
277
+ "@status": "submit",
278
+ "@docPath": "users/test-uid",
336
279
  };
337
- const change = createChange(null, doc, "/example/test-id");
338
- const event = "create";
339
- await (0, index_1.onDocChange)(funcName, "user", change, contextWithAuth, event);
340
- // Test that the snapshot.ref.update is called with the correct parameters
341
- expect(change.after.ref.update).toHaveBeenCalledWith({ "@form.@status": "processing" });
342
- expect(change.after.ref.update).toHaveBeenCalledWith({ "@form.@status": "submitted" });
280
+ const event = createEvent(formData);
281
+ await (0, index_1.onFormSubmit)(event);
282
+ expect(refMock.update).toHaveBeenCalledWith({ "@status": "processing" });
283
+ expect(refMock.update).toHaveBeenCalledWith({ "@status": "submitted" });
343
284
  // Test that addActionSpy is called with the correct parameters
344
- expect(setActionSpy).toHaveBeenCalled();
345
- expect(updateActionSpy).toHaveBeenCalled();
285
+ expect(setActionMock).toHaveBeenCalled();
286
+ expect(updateActionMock).toHaveBeenCalled();
287
+ validateFormMock.mockReset();
288
+ getFormModifiedFieldsMock.mockReset();
289
+ getSecurityFnMock.mockReset();
290
+ delayFormSubmissionAndCheckIfCancelledMock.mockReset();
291
+ setActionMock.mockReset();
292
+ updateActionMock.mockReset();
293
+ initActionRefMock.mockReset();
346
294
  });
347
- it("should set @form.@status to 'logic-error' if there are logic error results", async () => {
348
- jest.spyOn(indexutils, "revertModificationsOutsideForm").mockResolvedValue();
349
- jest.spyOn(indexutils, "validateForm").mockResolvedValue([false, {}]);
350
- jest.spyOn(indexutils, "getFormModifiedFields").mockReturnValue(["field1", "field2"]);
351
- jest.spyOn(indexutils, "getSecurityFn").mockReturnValue(() => Promise.resolve({ status: "allowed" }));
352
- jest.spyOn(indexutils, "delayFormSubmissionAndCheckIfCancelled").mockResolvedValue(false);
295
+ it("should set @status to 'logic-error' if there are logic error results", async () => {
296
+ const validateFormMock = jest.spyOn(indexutils, "validateForm").mockResolvedValue([false, {}]);
297
+ const getFormModifiedFieldsMock = jest.spyOn(indexutils, "getFormModifiedFields").mockReturnValue(["field1", "field2"]);
298
+ const getSecurityFnMock = jest.spyOn(indexutils, "getSecurityFn").mockReturnValue(() => Promise.resolve({ status: "allowed" }));
299
+ const delayFormSubmissionAndCheckIfCancelledMock = jest.spyOn(indexutils, "delayFormSubmissionAndCheckIfCancelled").mockResolvedValue(false);
353
300
  const errorMessage = "logic error message";
354
- const runBusinessLogicsSpy = jest.spyOn(indexutils, "runBusinessLogics").mockResolvedValue([
301
+ const runBusinessLogicsMock = jest.spyOn(indexutils, "runBusinessLogics").mockResolvedValue([
355
302
  {
356
303
  name: "testLogic",
357
304
  status: "error",
@@ -360,77 +307,81 @@ describe("onDocChange", () => {
360
307
  documents: [],
361
308
  },
362
309
  ]);
363
- const setActionSpy = jest.fn().mockResolvedValue({
310
+ const setActionMock = jest.fn().mockResolvedValue({
364
311
  update: jest.fn(),
365
312
  });
366
- const updateActionSpy = jest.fn().mockResolvedValue({
313
+ const updateActionMock = jest.fn().mockResolvedValue({
367
314
  update: jest.fn(),
368
315
  });
369
- jest.spyOn(index_1._mockable, "initActionRef").mockResolvedValue({
370
- set: setActionSpy,
371
- update: updateActionSpy,
316
+ const initActionRefMock = jest.spyOn(index_1._mockable, "initActionRef").mockResolvedValue({
317
+ set: setActionMock,
318
+ update: updateActionMock,
372
319
  collection: jest.fn().mockReturnValue({
373
320
  doc: jest.fn().mockReturnValue({
374
- set: setActionSpy,
375
- update: updateActionSpy,
321
+ set: setActionMock,
322
+ update: updateActionMock,
376
323
  }),
377
324
  }),
378
325
  });
326
+ const formData = {
327
+ "@actionType": "create",
328
+ "name": "test",
329
+ "@status": "submit",
330
+ "@docPath": "users/test-uid",
331
+ };
379
332
  const doc = {
380
- "@form": {
381
- "@actionType": "create",
382
- "name": "test",
383
- "@status": "submit",
384
- },
385
- "someField": "exampleValue",
333
+ name: "test",
334
+ description: "test description",
386
335
  };
387
- const change = createChange(null, doc, "/example/test-id");
388
- const event = "create";
389
- await (0, index_1.onDocChange)(funcName, "user", change, contextWithAuth, event);
336
+ dataMock.mockReturnValue(doc);
337
+ const event = createEvent(formData);
338
+ await (0, index_1.onFormSubmit)(event);
390
339
  // Test that the runBusinessLogics function was called with the correct parameters
391
- expect(runBusinessLogicsSpy).toHaveBeenCalledWith("create", ["field1", "field2"], "user", expect.objectContaining({
340
+ expect(runBusinessLogicsMock).toHaveBeenCalledWith("create", ["field1", "field2"], "user", expect.objectContaining({
341
+ eventContext,
392
342
  actionType: "create",
393
- document: {
394
- "@form": {
395
- "@actionType": "create",
396
- "@status": "submit",
397
- "name": "test",
398
- },
399
- "someField": "exampleValue",
343
+ document: doc,
344
+ form: {
345
+ "@actionType": "create",
346
+ "@status": "submit",
347
+ "name": "test",
348
+ "@docPath": "users/test-uid",
400
349
  },
401
350
  modifiedFields: ["field1", "field2"],
402
- path: "/example/test-id",
403
351
  status: "processing",
404
352
  // TimeCreated is not specified because it's dynamic
405
353
  }));
406
- // Test that the snapshot.ref.update is called with the correct parameters
407
- expect(change.after.ref.update).toHaveBeenCalledTimes(3);
408
- const updateMock = change.after.ref.update;
409
- expect(updateMock.mock.calls[0][0]).toEqual({ "@form.@status": "processing" });
410
- expect(updateMock.mock.calls[1][0]).toEqual({ "@form.@status": "submitted" });
411
- expect(updateMock.mock.calls[2][0]).toEqual({ "@form.@status": "finished" });
354
+ expect(refMock.update).toHaveBeenCalledTimes(3);
355
+ expect(refMock.update.mock.calls[0][0]).toEqual({ "@status": "processing" });
356
+ expect(refMock.update.mock.calls[1][0]).toEqual({ "@status": "submitted" });
357
+ expect(refMock.update.mock.calls[2][0]).toEqual({ "@status": "finished" });
412
358
  // Test that collectionAddSpy is not called if there are logic errors
413
- expect(setActionSpy).toHaveBeenCalledWith(expect.objectContaining({
359
+ expect(setActionMock).toHaveBeenCalledWith(expect.objectContaining({
360
+ eventContext,
414
361
  actionType: "create",
415
- document: {
416
- "@form": {
417
- "@actionType": "create",
418
- "@status": "submit",
419
- "name": "test",
420
- },
421
- "someField": "exampleValue",
362
+ document: doc,
363
+ form: {
364
+ "@actionType": "create",
365
+ "@status": "submit",
366
+ "name": "test",
367
+ "@docPath": "users/test-uid",
422
368
  },
423
369
  modifiedFields: ["field1", "field2"],
424
- path: "/example/test-id",
425
370
  status: "processing",
426
371
  // TimeCreated is not specified because it's dynamic
427
372
  }));
428
- expect(updateActionSpy).toHaveBeenCalledTimes(2);
429
- expect(updateActionSpy.mock.calls[0][0]).toEqual({ status: "finished-with-error", message: errorMessage });
373
+ expect(updateActionMock).toHaveBeenCalledTimes(2);
374
+ expect(updateActionMock.mock.calls[0][0]).toEqual({ status: "finished-with-error", message: errorMessage });
375
+ validateFormMock.mockReset();
376
+ getFormModifiedFieldsMock.mockReset();
377
+ getSecurityFnMock.mockReset();
378
+ delayFormSubmissionAndCheckIfCancelledMock.mockReset();
379
+ runBusinessLogicsMock.mockReset();
380
+ setActionMock.mockReset();
381
+ updateActionMock.mockReset();
382
+ initActionRefMock.mockReset();
430
383
  });
431
- // ... existing test code ...
432
384
  it("should execute the sequence of operations correctly", async () => {
433
- jest.spyOn(indexutils, "revertModificationsOutsideForm").mockResolvedValue();
434
385
  jest.spyOn(indexutils, "validateForm").mockResolvedValue([false, {}]);
435
386
  jest.spyOn(indexutils, "getFormModifiedFields").mockReturnValue(["field1", "field2"]);
436
387
  jest.spyOn(indexutils, "getSecurityFn").mockReturnValue(() => Promise.resolve({ status: "allowed" }));
@@ -460,16 +411,13 @@ describe("onDocChange", () => {
460
411
  }),
461
412
  }),
462
413
  });
463
- const doc = {
464
- "@form": {
465
- "@actionType": "create",
466
- "name": "test",
467
- "@status": "submit",
468
- },
469
- "someField": "exampleValue",
414
+ const formData = {
415
+ "@actionType": "create",
416
+ "name": "test",
417
+ "@status": "submit",
418
+ "@docPath": "users/test-uid",
470
419
  };
471
- const change = createChange(null, doc, "/example/test-id");
472
- const event = "create";
420
+ const event = createEvent(formData);
473
421
  const consolidatedLogicResults = new Map();
474
422
  const consolidatedViewLogicResults = new Map();
475
423
  const consolidatedPeerSyncViewLogicResults = new Map();
@@ -500,11 +448,10 @@ describe("onDocChange", () => {
500
448
  jest.spyOn(indexutils, "runViewLogics").mockResolvedValue(viewLogicResults);
501
449
  jest.spyOn(indexutils, "runPeerSyncViews").mockResolvedValue(peerSyncViewLogicResults);
502
450
  jest.spyOn(indexutils, "distribute");
503
- await (0, index_1.onDocChange)(funcName, "user", change, contextWithAuth, event);
451
+ await (0, index_1.onFormSubmit)(event);
504
452
  // Test that the runBusinessLogics function was called with the correct parameters
505
453
  expect(runBusinessLogicsSpy).toHaveBeenCalled();
506
- // Test that the snapshot.ref.update is called with the correct parameters
507
- expect(change.after.ref.update).toHaveBeenCalledTimes(3);
454
+ expect(refMock.update).toHaveBeenCalledTimes(3);
508
455
  expect(setActionSpy).toHaveBeenCalledTimes(2);
509
456
  // Test that the functions are called in the correct sequence
510
457
  expect(indexutils.consolidateAndGroupByDstPath).toHaveBeenNthCalledWith(1, businessLogicResults);
@@ -514,7 +461,7 @@ describe("onDocChange", () => {
514
461
  expect(indexutils.groupDocsByUserAndDstPath).toHaveBeenNthCalledWith(2, consolidatedViewLogicResults, "test-uid");
515
462
  expect(indexutils.distribute).toHaveBeenNthCalledWith(1, userDocsByDstPath);
516
463
  expect(indexutils.distribute).toHaveBeenNthCalledWith(2, userViewDocsByDstPath);
517
- expect(change.after.ref.update).toHaveBeenCalledWith({ "@form.@status": "finished" });
464
+ expect(refMock.update).toHaveBeenCalledWith({ "@status": "finished" });
518
465
  expect(indexutils.runPeerSyncViews).toHaveBeenCalledWith(userDocsByDstPath);
519
466
  expect(indexutils.consolidateAndGroupByDstPath).toHaveBeenNthCalledWith(3, peerSyncViewLogicResults);
520
467
  expect(indexutils.groupDocsByUserAndDstPath).toHaveBeenNthCalledWith(3, consolidatedPeerSyncViewLogicResults, "test-uid");