node/test/parallel/test-repl-tab-complete-import.js
Dario Piotrowicz 9ac571d0d5
test: add new startNewREPLSever testing utility
PR-URL: https://github.com/nodejs/node/pull/59964
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
2025-09-30 15:20:02 +02:00

145 lines
4.7 KiB
JavaScript

'use strict';
const common = require('../common');
const fixtures = require('../common/fixtures');
const assert = require('assert');
const { builtinModules } = require('module');
const publicUnprefixedModules = builtinModules.filter((lib) => !lib.startsWith('_') && !lib.startsWith('node:'));
const { isMainThread } = require('worker_threads');
if (!isMainThread) {
common.skip('process.chdir is not available in Workers');
}
// We have to change the directory to ../fixtures before requiring repl
// in order to make the tests for completion of node_modules work properly
// since repl modifies module.paths.
process.chdir(fixtures.fixturesDir);
const repl = require('repl');
const { startNewREPLServer } = require('../common/repl');
const { replServer, input } = startNewREPLServer();
// Tab complete provides built in libs for import()
replServer.complete('import(\'', common.mustSucceed((data) => {
publicUnprefixedModules.forEach((lib) => {
assert(
data[0].includes(lib) && data[0].includes(`node:${lib}`),
`${lib} not found`,
);
});
const newModule = 'foobar';
assert(!builtinModules.includes(newModule));
repl.builtinModules.push(newModule);
replServer.complete('import(\'', common.mustSucceed(([modules]) => {
assert.strictEqual(data[0].length + 1, modules.length);
assert(modules.includes(newModule) &&
!modules.includes(`node:${newModule}`));
}));
}));
replServer.complete("import\t( 'n", common.mustSucceed((data) => {
assert.strictEqual(data.length, 2);
assert.strictEqual(data[1], 'n');
const completions = data[0];
// import(...) completions include `node:` URL modules:
let lastIndex = -1;
publicUnprefixedModules.forEach((lib, index) => {
lastIndex = completions.indexOf(`node:${lib}`);
assert.notStrictEqual(lastIndex, -1);
});
assert.strictEqual(completions[lastIndex + 1], '');
// There is only one Node.js module that starts with n:
assert.strictEqual(completions[lastIndex + 2], 'net');
assert.strictEqual(completions[lastIndex + 3], '');
// It's possible to pick up non-core modules too
completions.slice(lastIndex + 4).forEach((completion) => {
assert.match(completion, /^n/);
});
}));
{
const expected = ['@nodejsscope', '@nodejsscope/'];
// Import calls should handle all types of quotation marks.
for (const quotationMark of ["'", '"', '`']) {
input.run(['.clear']);
replServer.complete('import(`@nodejs', common.mustSucceed((data) => {
assert.deepStrictEqual(data, [expected, '@nodejs']);
}));
input.run(['.clear']);
// Completions should not be greedy in case the quotation ends.
replServer.complete(`import(${quotationMark}@nodejsscope${quotationMark}`, common.mustSucceed((data) => {
assert.deepStrictEqual(data, [[], undefined]);
}));
}
}
{
input.run(['.clear']);
// Completions should find modules and handle whitespace after the opening
// bracket.
replServer.complete('import \t("no_ind', common.mustSucceed((data) => {
assert.deepStrictEqual(data, [['no_index', 'no_index/'], 'no_ind']);
}));
}
// Test tab completion for import() relative to the current directory
{
input.run(['.clear']);
const cwd = process.cwd();
process.chdir(__dirname);
['import(\'.', 'import(".'].forEach((input) => {
replServer.complete(input, common.mustSucceed((data) => {
assert.strictEqual(data.length, 2);
assert.strictEqual(data[1], '.');
assert.strictEqual(data[0].length, 2);
assert.ok(data[0].includes('./'));
assert.ok(data[0].includes('../'));
}));
});
['import(\'..', 'import("..'].forEach((input) => {
replServer.complete(input, common.mustSucceed((data) => {
assert.deepStrictEqual(data, [['../'], '..']);
}));
});
['./', './test-'].forEach((path) => {
[`import('${path}`, `import("${path}`].forEach((input) => {
replServer.complete(input, common.mustSucceed((data) => {
assert.strictEqual(data.length, 2);
assert.strictEqual(data[1], path);
assert.ok(data[0].includes('./test-repl-tab-complete.js'));
}));
});
});
['../parallel/', '../parallel/test-'].forEach((path) => {
[`import('${path}`, `import("${path}`].forEach((input) => {
replServer.complete(input, common.mustSucceed((data) => {
assert.strictEqual(data.length, 2);
assert.strictEqual(data[1], path);
assert.ok(data[0].includes('../parallel/test-repl-tab-complete.js'));
}));
});
});
{
const path = '../fixtures/repl-folder-extensions/f';
replServer.complete(`import('${path}`, common.mustSucceed((data) => {
assert.strictEqual(data.length, 2);
assert.strictEqual(data[1], path);
assert.ok(data[0].includes(
'../fixtures/repl-folder-extensions/foo.js/'));
}));
}
process.chdir(cwd);
}