120 lines
4.0 KiB
JavaScript
120 lines
4.0 KiB
JavaScript
|
'use strict';
|
||
|
|
||
|
const common = require('../common');
|
||
|
const assert = require('node:assert');
|
||
|
const { describe, test } = require('node:test');
|
||
|
|
||
|
const ArrayStream = require('../common/arraystream');
|
||
|
|
||
|
const repl = require('node:repl');
|
||
|
|
||
|
function runCompletionTests(replInit, tests) {
|
||
|
const stream = new ArrayStream();
|
||
|
const testRepl = repl.start({ stream });
|
||
|
|
||
|
// Some errors are passed to the domain
|
||
|
testRepl._domain.on('error', assert.ifError);
|
||
|
|
||
|
testRepl.write(replInit);
|
||
|
testRepl.write('\n');
|
||
|
|
||
|
tests.forEach(([query, expectedCompletions]) => {
|
||
|
testRepl.complete(query, common.mustCall((error, data) => {
|
||
|
const actualCompletions = data[0];
|
||
|
if (expectedCompletions.length === 0) {
|
||
|
assert.deepStrictEqual(actualCompletions, []);
|
||
|
} else {
|
||
|
expectedCompletions.forEach((expectedCompletion) =>
|
||
|
assert(actualCompletions.includes(expectedCompletion), `completion '${expectedCompletion}' not found`)
|
||
|
);
|
||
|
}
|
||
|
}));
|
||
|
});
|
||
|
}
|
||
|
|
||
|
describe('REPL completion in relation of getters', () => {
|
||
|
describe('standard behavior without proxies/getters', () => {
|
||
|
test('completion of nested properties of an undeclared objects', () => {
|
||
|
runCompletionTests('', [
|
||
|
['nonExisting.', []],
|
||
|
['nonExisting.f', []],
|
||
|
['nonExisting.foo', []],
|
||
|
['nonExisting.foo.', []],
|
||
|
['nonExisting.foo.bar.b', []],
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
test('completion of nested properties on plain objects', () => {
|
||
|
runCompletionTests('const plainObj = { foo: { bar: { baz: {} } } };', [
|
||
|
['plainObj.', ['plainObj.foo']],
|
||
|
['plainObj.f', ['plainObj.foo']],
|
||
|
['plainObj.foo', ['plainObj.foo']],
|
||
|
['plainObj.foo.', ['plainObj.foo.bar']],
|
||
|
['plainObj.foo.bar.b', ['plainObj.foo.bar.baz']],
|
||
|
['plainObj.fooBar.', []],
|
||
|
['plainObj.fooBar.baz', []],
|
||
|
]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('completions on an object with getters', () => {
|
||
|
test(`completions are generated for properties that don't trigger getters`, () => {
|
||
|
runCompletionTests(
|
||
|
`
|
||
|
const objWithGetters = {
|
||
|
foo: { bar: { baz: {} }, get gBar() { return { baz: {} } } },
|
||
|
get gFoo() { return { bar: { baz: {} } }; }
|
||
|
};
|
||
|
`, [
|
||
|
['objWithGetters.', ['objWithGetters.foo']],
|
||
|
['objWithGetters.f', ['objWithGetters.foo']],
|
||
|
['objWithGetters.foo', ['objWithGetters.foo']],
|
||
|
['objWithGetters.foo.', ['objWithGetters.foo.bar']],
|
||
|
['objWithGetters.foo.bar.b', ['objWithGetters.foo.bar.baz']],
|
||
|
['objWithGetters.gFo', ['objWithGetters.gFoo']],
|
||
|
['objWithGetters.foo.gB', ['objWithGetters.foo.gBar']],
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
test('no completions are generated for properties that trigger getters', () => {
|
||
|
runCompletionTests(
|
||
|
`
|
||
|
const objWithGetters = {
|
||
|
foo: { bar: { baz: {} }, get gBar() { return { baz: {} } } },
|
||
|
get gFoo() { return { bar: { baz: {} } }; }
|
||
|
};
|
||
|
`,
|
||
|
[
|
||
|
['objWithGetters.gFoo.', []],
|
||
|
['objWithGetters.gFoo.b', []],
|
||
|
['objWithGetters.gFoo.bar.b', []],
|
||
|
['objWithGetters.foo.gBar.', []],
|
||
|
['objWithGetters.foo.gBar.b', []],
|
||
|
]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('completions on proxies', () => {
|
||
|
test('no completions are generated for a proxy object', () => {
|
||
|
runCompletionTests('const proxyObj = new Proxy({ foo: { bar: { baz: {} } } }, {});', [
|
||
|
['proxyObj.', []],
|
||
|
['proxyObj.f', []],
|
||
|
['proxyObj.foo', []],
|
||
|
['proxyObj.foo.', []],
|
||
|
['proxyObj.foo.bar.b', []],
|
||
|
]);
|
||
|
});
|
||
|
|
||
|
test('no completions are generated for a proxy present in a standard object', () => {
|
||
|
runCompletionTests(
|
||
|
'const objWithProxy = { foo: { bar: new Proxy({ baz: {} }, {}) } };', [
|
||
|
['objWithProxy.', ['objWithProxy.foo']],
|
||
|
['objWithProxy.foo', ['objWithProxy.foo']],
|
||
|
['objWithProxy.foo.', ['objWithProxy.foo.bar']],
|
||
|
['objWithProxy.foo.b', ['objWithProxy.foo.bar']],
|
||
|
['objWithProxy.foo.bar.', []],
|
||
|
]);
|
||
|
});
|
||
|
});
|
||
|
});
|