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