Skip to content

Commit 4328471

Browse files
authored
chore: test that autocomplete works without the fallback, re-order the tests (#559)
* test that autocomplete works without the fallback, re-order the tests * comment * add events.js
1 parent 1382cfb commit 4328471

File tree

3 files changed

+70
-43
lines changed

3 files changed

+70
-43
lines changed

packages/mongodb-ts-autocomplete/scripts/extract-types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,10 @@ const deps: Record<string, string[]> = {
141141
'assert.js', // exists only
142142
],
143143
buffer: ['package.json', 'index.d.ts'],
144-
events: ['package.json'],
144+
events: [
145+
'package.json',
146+
'events.js', // exists only (also only on windows)
147+
],
145148
punycode: [
146149
'package.json',
147150
'punycode.js', // exists only

packages/mongodb-ts-autocomplete/src/autocompleter.spec.ts

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { MongoDBAutocompleter } from './index';
33
import type { AutocompletionContext } from './autocompletion-context';
44
import { analyzeDocuments } from 'mongodb-schema';
55
import { expect } from 'chai';
6+
import { relativeNodePath } from '@mongodb-js/ts-autocomplete';
67

78
/*
89
This is intended as deliberately diabolical database and collection names to
@@ -25,6 +26,7 @@ describe('MongoDBAutocompleter', function () {
2526
let fallbackServiceHost: ts.LanguageServiceHost;
2627
let autocompleterContext: AutocompletionContext;
2728
let autocompleter: MongoDBAutocompleter;
29+
let autocompleterWithFallback: MongoDBAutocompleter;
2830
let encounteredPaths: EncounteredPaths;
2931

3032
beforeEach(function () {
@@ -51,19 +53,19 @@ describe('MongoDBAutocompleter', function () {
5153
ts.sys.readFile(fileName) || '',
5254
);
5355

54-
encounteredPaths.getScriptSnapshot.push(fileName);
56+
encounteredPaths.getScriptSnapshot.push(relativeNodePath(fileName));
5557
return result;
5658
},
5759
fileExists: (fileName: string) => {
5860
const result = ts.sys.fileExists(fileName);
5961
if (result) {
60-
encounteredPaths.fileExists.push(fileName);
62+
encounteredPaths.fileExists.push(relativeNodePath(fileName));
6163
}
6264
return result;
6365
},
6466
readFile: (fileName: string) => {
6567
const result = ts.sys.readFile(fileName);
66-
encounteredPaths.readFile.push(fileName);
68+
encounteredPaths.readFile.push(relativeNodePath(fileName));
6769
return result;
6870
},
6971
readDirectory: (...args) => {
@@ -126,11 +128,32 @@ describe('MongoDBAutocompleter', function () {
126128

127129
autocompleter = new MongoDBAutocompleter({
128130
context: autocompleterContext,
131+
});
132+
133+
autocompleterWithFallback = new MongoDBAutocompleter({
134+
context: autocompleterContext,
129135
fallbackServiceHost,
130136
});
131137
});
132138

133-
afterEach(function () {
139+
/*
140+
This test can be used to recreate the list of deps in extract-types.ts.
141+
142+
ie. if you comment out the deps structure so it is an empty object, run
143+
extract-types (so it is just everything except the node types and Javascript
144+
lib) and then run this test, then it will essentially print what that structure
145+
needs to be.
146+
147+
The other tests would fail at the same time because they don't use the fallback
148+
service host, so typescript wouldn't load all the dependencies.
149+
*/
150+
it('autocompletes', async function () {
151+
await autocompleterWithFallback.autocomplete('db.foo.find({ fo');
152+
153+
encounteredPaths.fileExists.sort();
154+
encounteredPaths.getScriptSnapshot.sort();
155+
encounteredPaths.readFile.sort();
156+
134157
// this is what tells us what we're missing in extract-types.ts
135158
expect(encounteredPaths).to.deep.equal({
136159
fileExists: [],
@@ -139,33 +162,6 @@ describe('MongoDBAutocompleter', function () {
139162
});
140163
});
141164

142-
it('deals with no connection', async function () {
143-
// The body of tests are all wrapped in loops so that we exercise the
144-
// caching logic in the autocompleter.
145-
for (let i = 0; i < 2; i++) {
146-
autocompleterContext.currentDatabaseAndConnection = () => {
147-
return undefined;
148-
};
149-
150-
const completions = await autocompleter.autocomplete('db.');
151-
expect(completions).to.deep.equal([]);
152-
}
153-
});
154-
155-
it('does not leak the bson package', async function () {
156-
for (let i = 0; i < 2; i++) {
157-
const completions = await autocompleter.autocomplete('bson.');
158-
expect(completions).to.deep.equal([]);
159-
}
160-
});
161-
162-
it('does not leak the ShellAPI package', async function () {
163-
for (let i = 0; i < 2; i++) {
164-
const completions = await autocompleter.autocomplete('ShellAPI.');
165-
expect(completions).to.deep.equal([]);
166-
}
167-
});
168-
169165
it('completes a bson expression', async function () {
170166
for (let i = 0; i < 2; i++) {
171167
const completions = await autocompleter.autocomplete('Ob');
@@ -285,6 +281,33 @@ describe('MongoDBAutocompleter', function () {
285281
]);
286282
});
287283

284+
it('deals with no connection', async function () {
285+
// The body of tests are all wrapped in loops so that we exercise the
286+
// caching logic in the autocompleter.
287+
for (let i = 0; i < 2; i++) {
288+
autocompleterContext.currentDatabaseAndConnection = () => {
289+
return undefined;
290+
};
291+
292+
const completions = await autocompleter.autocomplete('db.');
293+
expect(completions).to.deep.equal([]);
294+
}
295+
});
296+
297+
it('does not leak the bson package', async function () {
298+
for (let i = 0; i < 2; i++) {
299+
const completions = await autocompleter.autocomplete('bson.');
300+
expect(completions).to.deep.equal([]);
301+
}
302+
});
303+
304+
it('does not leak the ShellAPI package', async function () {
305+
for (let i = 0; i < 2; i++) {
306+
const completions = await autocompleter.autocomplete('ShellAPI.');
307+
expect(completions).to.deep.equal([]);
308+
}
309+
});
310+
288311
describe('getConnectionSchemaCode', function () {
289312
it('generates code for a connection', async function () {
290313
const docs = [

packages/ts-autocomplete/src/index.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ type UpdateDefinitionFunction = (
1313
newDef: Record<TypeFilename, string | boolean>,
1414
) => void;
1515

16-
function relativeNodePath(fileName: string): string {
16+
export function relativeNodePath(fileName: string): string {
1717
const parts = fileName.split(/\/node_modules\//g);
1818
if (parts.length === 1 && fileName.endsWith('package.json')) {
1919
// special case: when it looks up this package itself it isn't going to find
@@ -65,13 +65,14 @@ function getVirtualLanguageService(
6565
return (versions[fileName] ?? 1).toString();
6666
},
6767
getScriptSnapshot: (fileName) => {
68-
fileName = relativeNodePath(fileName);
69-
if (fileName in codeHolder) {
68+
const relativeFileName = relativeNodePath(fileName);
69+
70+
if (relativeFileName in codeHolder) {
7071
// if its a boolean rather than code, just return a blank string if for
7172
// some reason we ever get here.
7273
const code =
73-
typeof codeHolder[fileName] === 'string'
74-
? (codeHolder[fileName] as string)
74+
typeof codeHolder[relativeFileName] === 'string'
75+
? (codeHolder[relativeFileName] as string)
7576
: '';
7677
return ts.ScriptSnapshot.fromString(code);
7778
}
@@ -86,8 +87,8 @@ function getVirtualLanguageService(
8687
return ts.getDefaultLibFilePath(options);
8788
},
8889
fileExists: (fileName) => {
89-
fileName = relativeNodePath(fileName);
90-
if (fileName in codeHolder) {
90+
const relativeFileName = relativeNodePath(fileName);
91+
if (relativeFileName in codeHolder) {
9192
return true;
9293
}
9394

@@ -98,13 +99,13 @@ function getVirtualLanguageService(
9899
return false;
99100
},
100101
readFile: (fileName) => {
101-
fileName = relativeNodePath(fileName);
102-
if (fileName in codeHolder) {
102+
const relativeFileName = relativeNodePath(fileName);
103+
if (relativeFileName in codeHolder) {
103104
// if its a boolean rather than code, just return a blank string if for
104105
// some reason we ever get here.
105106
const code =
106-
typeof codeHolder[fileName] === 'string'
107-
? (codeHolder[fileName] as string)
107+
typeof codeHolder[relativeFileName] === 'string'
108+
? (codeHolder[relativeFileName] as string)
108109
: undefined;
109110
return code;
110111
}

0 commit comments

Comments
 (0)