Skip to content

Commit 3eef758

Browse files
No implicit any
1 parent b1f6c75 commit 3eef758

29 files changed

+955
-829
lines changed

dev/conformance/runner.ts

+85-72
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,25 @@
1717
const duplexify = require('duplexify');
1818

1919
import {expect} from 'chai';
20+
import {CallOptions} from 'google-gax';
2021
import * as path from 'path';
2122
import * as protobufjs from 'protobufjs';
2223
import * as through2 from 'through2';
2324
import * as proto from '../protos/firestore_proto_api';
2425

25-
import * as Firestore from '../src';
26-
import {documentFromJson} from '../src/convert';
26+
import {DocumentChange, DocumentSnapshot, FieldPath, FieldValue, Firestore, Query, QueryDocumentSnapshot, QuerySnapshot, Timestamp} from '../src';
27+
import {fieldsFromJson} from '../src/convert';
2728
import {DocumentChangeType} from '../src/document-change';
2829
import {ResourcePath} from '../src/path';
30+
import {DocumentData} from '../src/types';
2931
import {isObject} from '../src/util';
30-
import {createInstance as createInstanceHelper} from '../test/util/helpers';
32+
import {ApiOverride, createInstance as createInstanceHelper} from '../test/util/helpers';
3133

3234
import api = proto.google.firestore.v1;
3335

36+
// TODO(mrschmidt): Create Protobuf .d.ts file for the conformance proto
37+
type ConformanceProto = any; // tslint:disable-line:no-any
38+
3439
const REQUEST_TIME = 'REQUEST_TIME';
3540

3641
/** List of test cases that are ignored. */
@@ -60,14 +65,14 @@ const COMMIT_REQUEST_TYPE =
6065
protoDefinition.lookupType('google.firestore.v1.CommitRequest');
6166

6267
// Firestore instance initialized by the test runner.
63-
let firestore;
68+
let firestore: Firestore;
6469

65-
const docRef = path => {
70+
const docRef = (path: string) => {
6671
const relativePath = ResourcePath.fromSlashSeparatedString(path).relativeName;
6772
return firestore.doc(relativePath);
6873
};
6974

70-
const collRef = path => {
75+
const collRef = (path: string) => {
7176
const relativePath = ResourcePath.fromSlashSeparatedString(path).relativeName;
7277
return firestore.collection(relativePath);
7378
};
@@ -76,7 +81,7 @@ const watchQuery = () => {
7681
return firestore.collection('C').orderBy('a');
7782
};
7883

79-
const createInstance = overrides => {
84+
const createInstance = (overrides: ApiOverride) => {
8085
return createInstanceHelper(
8186
overrides, {projectId: CONFORMANCE_TEST_PROJECT_ID})
8287
.then(firestoreClient => {
@@ -87,36 +92,38 @@ const createInstance = overrides => {
8792

8893
/** Converts JSON test data into JavaScript types suitable for the Node API. */
8994
const convertInput = {
90-
argument: json => {
95+
argument: (json: ConformanceProto) => {
9196
const obj = JSON.parse(json);
92-
function convertValue(value) {
97+
function convertValue(value: unknown) {
9398
if (isObject(value)) {
9499
return convertObject(value);
95100
} else if (Array.isArray(value)) {
96101
return convertArray(value);
97102
} else if (value === 'NaN') {
98103
return NaN;
99104
} else if (value === 'Delete') {
100-
return Firestore.FieldValue.delete();
105+
return FieldValue.delete();
101106
} else if (value === 'ServerTimestamp') {
102-
return Firestore.FieldValue.serverTimestamp();
107+
return FieldValue.serverTimestamp();
103108
}
104109

105110
return value;
106111
}
107-
function convertArray(arr) {
112+
function convertArray(arr: Array<unknown>): Array<unknown>|FieldValue {
108113
if (arr.length > 0 && arr[0] === 'ArrayUnion') {
109-
return Firestore.FieldValue.arrayUnion(...convertArray(arr.slice(1)));
114+
return FieldValue.arrayUnion(
115+
...(convertArray(arr.slice(1)) as Array<unknown>));
110116
} else if (arr.length > 0 && arr[0] === 'ArrayRemove') {
111-
return Firestore.FieldValue.arrayRemove(...convertArray(arr.slice(1)));
117+
return FieldValue.arrayRemove(
118+
...(convertArray(arr.slice(1)) as Array<unknown>));
112119
} else {
113120
for (let i = 0; i < arr.length; ++i) {
114121
arr[i] = convertValue(arr[i]);
115122
}
116123
return arr;
117124
}
118125
}
119-
function convertObject(obj) {
126+
function convertObject(obj: {[k: string]: unknown}) {
120127
for (const key in obj) {
121128
if (obj.hasOwnProperty(key)) {
122129
obj[key] = convertValue(obj[key]);
@@ -126,94 +133,98 @@ const convertInput = {
126133
}
127134
return convertValue(obj);
128135
},
129-
precondition: precondition => {
136+
precondition: (precondition: string) => {
130137
const deepCopy = JSON.parse(JSON.stringify(precondition));
131138
if (deepCopy.updateTime) {
132-
deepCopy.lastUpdateTime =
133-
Firestore.Timestamp.fromProto(deepCopy.updateTime);
139+
deepCopy.lastUpdateTime = Timestamp.fromProto(deepCopy.updateTime);
134140
delete deepCopy.updateTime;
135141
}
136142
return deepCopy;
137143
},
138-
path: path => {
144+
path: (path: ConformanceProto) => {
139145
if (path.field.length === 1 && path.field[0] === '__name__') {
140-
return Firestore.FieldPath.documentId();
146+
return FieldPath.documentId();
141147
}
142-
return new Firestore.FieldPath(path.field);
148+
return new FieldPath(path.field);
143149
},
144-
paths: fields => {
145-
const convertedPaths: Array<{}> = [];
150+
paths: (fields: ConformanceProto): FieldPath[] => {
151+
const convertedPaths: FieldPath[] = [];
146152
if (fields) {
147153
for (const field of fields) {
148154
convertedPaths.push(convertInput.path(field));
149155
}
150156
} else {
151-
convertedPaths.push(Firestore.FieldPath.documentId());
157+
convertedPaths.push(FieldPath.documentId());
152158
}
153159
return convertedPaths;
154160
},
155-
cursor: cursor => {
156-
const args: Array<{}> = [];
161+
cursor: (cursor: ConformanceProto) => {
162+
const args: Array<unknown> = [];
157163
if (cursor.docSnapshot) {
158-
args.push(Firestore.DocumentSnapshot.fromObject(
164+
args.push(DocumentSnapshot.fromObject(
159165
docRef(cursor.docSnapshot.path),
160-
convertInput.argument(cursor.docSnapshot.jsonData)));
166+
convertInput.argument(cursor.docSnapshot.jsonData) as DocumentData));
161167
} else {
162168
for (const jsonValue of cursor.jsonValues) {
163169
args.push(convertInput.argument(jsonValue));
164170
}
165171
}
166172
return args;
167173
},
168-
snapshot: snapshot => {
169-
const docs: Firestore.QueryDocumentSnapshot[] = [];
170-
const changes: Firestore.DocumentChange[] = [];
171-
const readTime = Firestore.Timestamp.fromProto(snapshot.readTime);
174+
snapshot: (snapshot: ConformanceProto) => {
175+
const docs: QueryDocumentSnapshot[] = [];
176+
const changes: DocumentChange[] = [];
177+
const readTime = Timestamp.fromProto(snapshot.readTime);
172178

173179
for (const doc of snapshot.docs) {
174180
const deepCopy = JSON.parse(JSON.stringify(doc));
175-
deepCopy.fields = documentFromJson(deepCopy.fields);
181+
deepCopy.fields = fieldsFromJson(deepCopy.fields);
176182
docs.push(
177-
firestore.snapshot_(deepCopy, readTime, 'json') as
178-
Firestore.QueryDocumentSnapshot);
183+
firestore.snapshot_(
184+
deepCopy, readTime.toDate().toISOString(), 'json') as
185+
QueryDocumentSnapshot);
179186
}
180187

181188
for (const change of snapshot.changes) {
182189
const deepCopy = JSON.parse(JSON.stringify(change.doc));
183-
deepCopy.fields = documentFromJson(deepCopy.fields);
184-
const doc = firestore.snapshot_(deepCopy, readTime, 'json');
190+
deepCopy.fields = fieldsFromJson(deepCopy.fields);
191+
const doc = firestore.snapshot_(
192+
deepCopy, readTime.toDate().toISOString(), 'json') as
193+
QueryDocumentSnapshot;
185194
const type =
186195
(['unspecified', 'added', 'removed', 'modified'][change.kind] as
187196
DocumentChangeType);
188-
changes.push(new Firestore.DocumentChange(
189-
type, doc, change.oldIndex, change.newIndex));
197+
changes.push(
198+
new DocumentChange(type, doc, change.oldIndex, change.newIndex));
190199
}
191200

192-
return new Firestore.QuerySnapshot(
201+
return new QuerySnapshot(
193202
watchQuery(), readTime, docs.length, () => docs, () => changes);
194203
},
195204
};
196205

197206
/** Converts Firestore Protobuf types in Proto3 JSON format to Protobuf JS. */
198207
const convertProto = {
199-
targetChange: type => type || 'NO_CHANGE',
200-
listenResponse: listenRequest => {
208+
targetChange: (type?: string) => type || 'NO_CHANGE',
209+
listenResponse: (listenRequest: ConformanceProto) => {
201210
const deepCopy = JSON.parse(JSON.stringify(listenRequest));
202211
if (deepCopy.targetChange) {
203212
deepCopy.targetChange.targetChangeType =
204213
convertProto.targetChange(deepCopy.targetChange.targetChangeType);
205214
}
206215
if (deepCopy.documentChange) {
207216
deepCopy.documentChange.document.fields =
208-
documentFromJson(deepCopy.documentChange.document.fields);
217+
fieldsFromJson(deepCopy.documentChange.document.fields);
209218
}
210219
return deepCopy;
211220
},
212221
};
213222

214223
/** Request handler for _commit. */
215-
function commitHandler(spec) {
216-
return (request, options, callback) => {
224+
function commitHandler(spec: ConformanceProto) {
225+
return (request: api.ICommitRequest, options: CallOptions,
226+
callback: (err: Error|null|undefined, resp?: api.ICommitResponse) =>
227+
void) => {
217228
try {
218229
const actualCommit = COMMIT_REQUEST_TYPE.fromObject(request);
219230
const expectedCommit = COMMIT_REQUEST_TYPE.fromObject(spec.request);
@@ -222,7 +233,7 @@ function commitHandler(spec) {
222233
commitTime: {},
223234
writeResults: [],
224235
};
225-
for (let i = 1; i <= request.writes.length; ++i) {
236+
for (let i = 1; i <= request.writes!.length; ++i) {
226237
res.writeResults!.push({
227238
updateTime: {},
228239
});
@@ -235,10 +246,10 @@ function commitHandler(spec) {
235246
}
236247

237248
/** Request handler for _runQuery. */
238-
function queryHandler(spec) {
239-
return request => {
249+
function queryHandler(spec: ConformanceProto) {
250+
return (request: api.IRunQueryRequest) => {
240251
const actualQuery =
241-
STRUCTURED_QUERY_TYPE.fromObject(request.structuredQuery);
252+
STRUCTURED_QUERY_TYPE.fromObject(request.structuredQuery!);
242253
const expectedQuery = STRUCTURED_QUERY_TYPE.fromObject(spec.query);
243254
expect(actualQuery).to.deep.equal(expectedQuery);
244255
const stream = through2.obj();
@@ -248,10 +259,10 @@ function queryHandler(spec) {
248259
}
249260

250261
/** Request handler for _batchGetDocuments. */
251-
function getHandler(spec) {
252-
return request => {
262+
function getHandler(spec: ConformanceProto) {
263+
return (request: api.IBatchGetDocumentsRequest) => {
253264
const getDocument = spec.request;
254-
expect(request.documents[0]).to.equal(getDocument.name);
265+
expect(request.documents![0]).to.equal(getDocument.name);
255266
const stream = through2.obj();
256267
setImmediate(() => {
257268
stream.push({
@@ -264,19 +275,19 @@ function getHandler(spec) {
264275
};
265276
}
266277

267-
function runTest(spec) {
278+
function runTest(spec: ConformanceProto) {
268279
console.log(`Running Spec:\n${JSON.stringify(spec, null, 2)}\n`);
269280

270-
const updateTest = spec => {
281+
const updateTest = (spec: ConformanceProto) => {
271282
const overrides = {commit: commitHandler(spec)};
272283
return createInstance(overrides).then(() => {
273-
const varargs: Array<{}> = [];
284+
const varargs: Array<unknown> = [];
274285

275286
if (spec.jsonData) {
276287
varargs[0] = convertInput.argument(spec.jsonData);
277288
} else {
278289
for (let i = 0; i < spec.fieldPaths.length; ++i) {
279-
varargs[2 * i] = new Firestore.FieldPath(spec.fieldPaths[i].field);
290+
varargs[2 * i] = new FieldPath(spec.fieldPaths[i].field);
280291
}
281292
for (let i = 0; i < spec.jsonValues.length; ++i) {
282293
varargs[2 * i + 1] = convertInput.argument(spec.jsonValues[i]);
@@ -288,13 +299,16 @@ function runTest(spec) {
288299
}
289300

290301
const document = docRef(spec.docRefPath);
291-
return document.update.apply(document, varargs);
302+
// TODO(mrschmidt): Remove 'any' and invoke by calling update() directly
303+
// for each individual case.
304+
// tslint:disable-next-line:no-any
305+
return document.update.apply(document, varargs as any);
292306
});
293307
};
294308

295-
const queryTest = spec => {
309+
const queryTest = (spec: ConformanceProto) => {
296310
const overrides = {runQuery: queryHandler(spec)};
297-
const applyClause = (query, clause) => {
311+
const applyClause = (query: Query, clause: ConformanceProto) => {
298312
if (clause.select) {
299313
query =
300314
query.select.apply(query, convertInput.paths(clause.select.fields));
@@ -325,15 +339,15 @@ function runTest(spec) {
325339
};
326340

327341
return createInstance(overrides).then(() => {
328-
let query = collRef(spec.collPath);
342+
let query: Query = collRef(spec.collPath);
329343
for (const clause of spec.clauses) {
330344
query = applyClause(query, clause);
331345
}
332346
return query.get();
333347
});
334348
};
335349

336-
const deleteTest = spec => {
350+
const deleteTest = (spec: ConformanceProto) => {
337351
const overrides = {commit: commitHandler(spec)};
338352
return createInstance(overrides).then(() => {
339353
if (spec.precondition) {
@@ -345,43 +359,42 @@ function runTest(spec) {
345359
});
346360
};
347361

348-
const setTest = spec => {
362+
const setTest = (spec: ConformanceProto) => {
349363
const overrides = {commit: commitHandler(spec)};
350364
return createInstance(overrides).then(() => {
351-
const setOption: {merge?: boolean,
352-
mergeFields?: Firestore.FieldPath[]} = {};
365+
const setOption: {merge?: boolean, mergeFields?: FieldPath[]} = {};
353366
if (spec.option && spec.option.all) {
354367
setOption.merge = true;
355368
} else if (spec.option && spec.option.fields) {
356369
setOption.mergeFields = [];
357370
for (const fieldPath of spec.option.fields) {
358-
setOption.mergeFields.push(new Firestore.FieldPath(fieldPath.field));
371+
setOption.mergeFields.push(new FieldPath(fieldPath.field));
359372
}
360373
}
361374
return docRef(setSpec.docRefPath)
362-
.set(convertInput.argument(spec.jsonData), setOption);
375+
.set(convertInput.argument(spec.jsonData) as DocumentData, setOption);
363376
});
364377
};
365378

366-
const createTest = spec => {
379+
const createTest = (spec: ConformanceProto) => {
367380
const overrides = {commit: commitHandler(spec)};
368381
return createInstance(overrides).then(() => {
369382
return docRef(spec.docRefPath)
370-
.create(convertInput.argument(spec.jsonData));
383+
.create(convertInput.argument(spec.jsonData) as DocumentData);
371384
});
372385
};
373386

374-
const getTest = spec => {
387+
const getTest = (spec: ConformanceProto) => {
375388
const overrides = {batchGetDocuments: getHandler(spec)};
376389
return createInstance(overrides).then(() => {
377390
return docRef(spec.docRefPath).get();
378391
});
379392
};
380393

381-
const watchTest = spec => {
394+
const watchTest = (spec: ConformanceProto) => {
382395
const expectedSnapshots = spec.snapshots;
383396
const writeStream = through2.obj();
384-
const overrides = {
397+
const overrides: ApiOverride = {
385398
listen: () => duplexify.obj(through2.obj(), writeStream)
386399
};
387400

@@ -418,7 +431,7 @@ function runTest(spec) {
418431
});
419432
};
420433

421-
let testSpec;
434+
let testSpec: ConformanceProto;
422435
let testPromise;
423436

424437
const getSpec = spec.get;

0 commit comments

Comments
 (0)