-
-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TypeError: Invalid host defined options - Cannot Use TypeScript, JavaScript, ESM, and TS-Node #4594
Comments
I can't really help with that, but there are two details (?) which are/could be wrong. |
@juergba Thanks for the advice! I changed the {
"extension": ["js", "ts"],
"require": ["./register.ts", "ts-node/register"]
} Then when I run it I get
I know that this is the issue with When I add {
"extension": ["js", "ts"],
"require": ["./register.ts", "esm", "ts-node/register"]
}
Do you have any guidance on these configurations? |
I strongly advise against using the see ts-node/esm, maybe @cspotcode can give you a hint.
|
On node, you have 2x options:
You should commit to one or the other, and then I can give you a configuration that will work. The first option -- using node's CommonJS support -- is by far the recommended option. If you absolutely must use the second option -- native ESM support -- then do the following: Remove the |
I've shared a complete, working example here, with logs to prove that it works. |
@cspotcode I am committing to working with node's new native ESM support I will look at the example and report back! |
@cspotcode thanks for your support. |
Hrm... I really appreciate the repo to compare against. I have updated my
I have changed my
And now when I run I get the dreaded ✘ lknecht ~/Repositories/palantir-api do_not_use/prototyping_mocha_typescript-dev ± ⬡ v12.17.0 env TS_NODE_PROJECT=test/tsconfig.json \
yarn run mocha --config ./.mocharc.json --test unit
yarn run v1.22.10
$ /Users/lknecht/Repositories/palantir-api/node_modules/.bin/mocha --config ./.mocharc.json --test unit
(node:60415) ExperimentalWarning: The ESM module loader is experimental.
(node:60415) ExperimentalWarning: --experimental-loader is an experimental feature. This feature could change at any time
{"message":"Something caused the test to crash.","level":"error"}
{"code":"ERR_REQUIRE_ESM","level":"error"}
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/lknecht/Repositories/palantir-api/test/unit/helper_controller.test.js
require() of ES modules is not supported.
require() of /Users/lknecht/Repositories/palantir-api/test/unit/helper_controller.test.js from /Users/lknecht/Repositories/palantir-api/node_modules/ts-node/dist/index.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead change the requiring code to use import(), or remove "type": "module" from /Users/lknecht/Repositories/palantir-api/package.json.
at createErrRequireEsm (/Users/lknecht/Repositories/palantir-api/node_modules/ts-node/dist-raw/node-cjs-loader-utils.js:86:15)
at assertScriptCanLoadAsCJSImpl (/Users/lknecht/Repositories/palantir-api/node_modules/ts-node/dist-raw/node-cjs-loader-utils.js:19:11)
at assertScriptCanLoadAsCJS (/Users/lknecht/Repositories/palantir-api/node_modules/ts-node/src/index.ts:31:3)
at Object.require.extensions.<computed> [as .js] (/Users/lknecht/Repositories/palantir-api/node_modules/ts-node/src/index.ts:1048:7)
at Module.load (internal/modules/cjs/loader.js:986:32)
at Function.Module._load (internal/modules/cjs/loader.js:879:14)
at Module.require (internal/modules/cjs/loader.js:1026:19)
at require (internal/modules/cjs/helpers.js:72:18)
at /Users/lknecht/Repositories/palantir-api/node_modules/mocha/lib/mocha.js:394:36
at Array.forEach (<anonymous>)
at Mocha.loadFiles (/Users/lknecht/Repositories/palantir-api/node_modules/mocha/lib/mocha.js:391:14)
at Mocha.run (/Users/lknecht/Repositories/palantir-api/node_modules/mocha/lib/mocha.js:970:10)
at main (file:///Users/lknecht/Repositories/palantir-api/test/runner.js:246:15)
at file:///Users/lknecht/Repositories/palantir-api/test/runner.js:283:1
at ModuleJob.run (internal/modules/esm/module_job.js:110:37)
at Loader.import (internal/modules/esm/loader.js:179:24)
at Object.exports.loadFilesAsync (/Users/lknecht/Repositories/palantir-api/node_modules/mocha/lib/esm-utils.js:33:20)
at singleRun (/Users/lknecht/Repositories/palantir-api/node_modules/mocha/lib/cli/run-helpers.js:125:3)
at Object.exports.handler (/Users/lknecht/Repositories/palantir-api/node_modules/mocha/lib/cli/run.js:362:5) {
code: 'ERR_REQUIRE_ESM',
level: 'error',
[Symbol(level)]: 'error',
[Symbol(message)]: '{"code":"ERR_REQUIRE_ESM","level":"error"}'
} I will continue you to try and figure out where this is coming from @cspotcode and @juergba I really appreciate all the input. And lol at the |
What is in |
Eh, nevermind, that error is happening because mocha is trying to mocha requires files and detects certain errors to know if it should subsequently |
This is the contents of import chai from 'chai';
import sinon from 'sinon';
import { v4 as uuid } from 'uuid';
import { NewStubs } from './mock.js';
import ControllerHelper from '../../src/utilities/controller_helper.js';
import { dbTable } from '../../src/utilities/data_helper.js';
describe('Controller Helper', () => {
let controller, dbConnectorStub, resStub;
const testProject = { name: 'test.quick.fox', projectid: uuid() };
const projectIdParam = { name: 'projectid', value: testProject.projectid };
const suiteid = uuid();
const suiteIdParam = { name: 'suiteid', value: suiteid };
const testrunid = uuid();
const testrunIdParam = { name: 'testrunid', value: testrunid };
beforeEach(() => {
let stubs = NewStubs();
// Assign the stubs
dbConnectorStub = stubs.dbConnector;
resStub = stubs.res;
// instantiate the controller we are testing with the connector stub and joi schema validator
controller = new ControllerHelper(dbConnectorStub);
});
describe('getall', () => {
const testData = [
{ title: 'when empty', rows: [] },
{ title: 'when 1 project is available', rows: [testProject] },
];
testData.forEach((test) => {
it('retrieve all projects ' + test.title, async () => {
// Arrange
dbConnectorStub.getAll.returns({ rows: test.rows });
// Act
const projectRows = await controller.listProjects();
// Assert the call on dbConnector.getAll
sinon.assert.calledOnce(dbConnectorStub.getAll);
sinon.assert.calledWith(dbConnectorStub.getAll, 'project');
// Assert payload returned
chai.assert.equal(projectRows, test.rows);
});
});
});
describe('deleteProject', () => {
it('Delete Project with no suites', async () => {
// Arrange
dbConnectorStub.getAll.returns({ rows: [testProject] });
dbConnectorStub.getWithParams.withArgs(dbTable.suite, projectIdParam).returns({ rows: [] });
dbConnectorStub.delete.returns({});
// Act
await controller.deleteProject(testProject.projectid);
// Assert delete project
sinon.assert.calledOnceWithExactly(dbConnectorStub.delete, dbTable.project, projectIdParam);
// Assert suite delete was not invoked
// not sure about this one
sinon.assert.neverCalledWith(dbConnectorStub.delete, dbTable.suite, suiteIdParam);
});
it('Delete Project with one suite', async () => {
// Arrange getAll projects
dbConnectorStub.getAll.returns({ rows: [testProject] });
// Arrange get suites for project
dbConnectorStub.getWithParams
.withArgs(dbTable.suite, projectIdParam)
.returns({ rows: [{ suiteid: suiteid }] });
// Arrange get testrunID for suite
dbConnectorStub.getWithParams.withArgs(dbTable.testrun, suiteIdParam).returns({ rows: [] });
dbConnectorStub.delete.returns({});
// Act
await controller.deleteProject(testProject.projectid);
// Assert
sinon.assert.calledWithMatch(dbConnectorStub.getWithParams, dbTable.suite, projectIdParam);
sinon.assert.calledWithMatch(dbConnectorStub.delete, dbTable.project, projectIdParam);
sinon.assert.neverCalledWithMatch(dbConnectorStub.delete, dbTable.testresult, testrunIdParam);
sinon.assert.calledWithMatch(dbConnectorStub.delete, dbTable.test, suiteIdParam);
sinon.assert.calledWithMatch(dbConnectorStub.delete, dbTable.testrun, suiteIdParam);
sinon.assert.calledWithMatch(dbConnectorStub.delete, dbTable.suite, suiteIdParam);
sinon.assert.callCount(dbConnectorStub.delete, 4);
});
it('Delete Project with one suite and testrunID', async () => {
// Arrange getAll projects
dbConnectorStub.getAll.returns({ rows: [testProject] });
// Arrange get suites for project
dbConnectorStub.getWithParams
.withArgs(dbTable.suite, projectIdParam)
.returns({ rows: [{ suiteid: suiteid }] });
// Arrange get testrunID for suite
dbConnectorStub.getWithParams
.withArgs(dbTable.testrun, suiteIdParam)
.returns({ rows: [{ testrunid: testrunid }] });
dbConnectorStub.delete.returns({});
// Act
await controller.deleteProject(testProject.projectid);
// Assert
sinon.assert.calledWithMatch(dbConnectorStub.getWithParams, dbTable.suite, projectIdParam);
sinon.assert.calledWithMatch(dbConnectorStub.delete, dbTable.project, projectIdParam);
sinon.assert.calledWithMatch(dbConnectorStub.delete, dbTable.testresult, testrunIdParam);
sinon.assert.calledWithMatch(dbConnectorStub.delete, dbTable.test, suiteIdParam);
sinon.assert.calledWithMatch(dbConnectorStub.delete, dbTable.testrun, suiteIdParam);
sinon.assert.calledWithMatch(dbConnectorStub.delete, dbTable.suite, suiteIdParam);
sinon.assert.callCount(dbConnectorStub.delete, 5);
});
});
}); I don't think that's the issue though. It appears as though my team has created a runner for mocha in This is what's it's import chai from 'chai';
import chaiHttp from 'chai-http';
import dotenv from 'dotenv';
import fs from 'fs';
import Mocha from 'mocha';
import path from 'path';
import yargs from 'yargs';
import { logger } from '../src/winston/config.ts';
dotenv.config();
chai.use(chaiHttp);
const argv = yargs
.usage('To run locally : runner.sh [options]')
.usage('To push results: runner.sh [options] [push options]')
.option('test', {
description: 'type of test',
alias: 't',
type: 'string',
choices: ['unit', 'system'],
})
.option('reporterURL', {
description: 'the URL to submit reports to',
alias: 'u',
type: 'string',
requiresArg: true,
group: 'push',
})
.option('suiteID', {
description: 'the SuiteID in palantir mapped to the run',
alias: 's',
type: 'string',
requiresArg: true,
group: 'push',
})
.option('suitesTitle', {
description: 'the testSuitesTitle for mocha-junit-reporter',
alias: 'x',
type: 'string',
requiresArg: true,
})
.option('commitSHA', {
description: 'the commit sha associated to this run',
alias: 'c',
type: 'string',
requiresArg: true,
default: null,
group: 'push',
})
.option('reporterType', {
description: 'the mocha reporter preset type',
alias: 'r',
type: 'string',
default: 'multi-junit',
})
.option('reportPath', {
hidden: true,
default: 'test-result.xml',
})
.wrap(120)
.demandOption(['t'])
.check((argv, options) => {
if (
argv.commitSHA === null &&
process.env.CI_COMMIT_SHORT_SHA !== null &&
process.env.CI_COMMIT_SHORT_SHA !== undefined
) {
argv.commitSHA = process.env.CI_COMMIT_SHORT_SHA;
}
if (!argv.reporterURL && !argv.suiteID) {
return true;
} else if (argv.reporterURL && argv.suiteID) {
return true;
}
throw new Error('Missing or extra values');
})
.help()
.alias('help', 'h').argv;
async function WaitForAPI() {
let server = process.env.API_HOST + ':' + process.env.API_PORT;
// In pipeline and when talking to deployments, the API_PORT is left blank
// hence it is modified
if (process.env.API_PORT === undefined || process.env.API_PORT === '') {
server = process.env.API_HOST;
}
logger.info('Targeting: ' + server);
let result = false;
for (let i = 0; i < 15; i++) {
result = await chai
.request(server)
.get('/api/info')
.then((res) => {
logger.info('/api/info ' + res.status);
if (res.status !== 200) {
return false;
}
return true;
})
.catch((err) => {
logger.error(err);
return false;
});
if (result) {
break;
}
await new Promise((resolve) => setTimeout(resolve, 1000));
}
if (!result) {
logger.error('Could not reach the service in time');
return null;
}
result = false;
for (let i = 0; i < 15; i++) {
result = await chai
.request(server)
.get('/api/init')
.then((res) => {
logger.info('/api/init ' + res.status);
if (res.status !== 200) {
return false;
}
return true;
})
.catch((err) => {
logger.error(err);
return false;
});
if (result) {
break;
}
await new Promise((resolve) => setTimeout(resolve, 1000));
}
if (!result) {
logger.error('DB was not initialized properly in time');
return null;
}
return server;
}
function NewMocha(mochaType) {
let mocha;
switch (mochaType) {
case 'xunit':
mocha = new Mocha({
fullTrace: true,
reporter: 'xunit',
reporterOptions: {
suiteName: argv.suitesTitle,
output: process.env.REPORT_PATH,
properties: {
COMMIT_SHA: argv.commitSHA,
},
},
});
argv.reportPath = process.env.REPORT_PATH;
break;
case 'multi-xunit':
mocha = new Mocha({
fullTrace: true,
reporter: 'mocha-multi-reporters',
reporterOptions: {
reporterEnabled: 'xunit,spec',
xunitReporterOptions: {
output: process.env.REPORT_PATH,
suiteName: argv.suitesTitle,
},
},
});
argv.reportPath = process.env.REPORT_PATH;
break;
case 'multi-junit':
mocha = new Mocha({
fullTrace: true,
reporter: 'mocha-multi-reporters',
reporterOptions: {
reporterEnabled: 'mocha-junit-reporter,spec',
mochaJunitReporterReporterOptions: {
mochaFile: process.env.REPORT_PATH,
rootSuiteTitle: 'The root!',
testsuitesTitle: argv.suitesTitle,
properties: {
COMMIT_SHA: argv.commitSHA,
},
},
},
});
argv.reportPath = process.env.REPORT_PATH;
break;
default:
throw new Error('Not a mocha configuration supported');
}
return mocha;
}
async function main() {
if (!argv.suitesTitle) {
argv.suitesTitle = process.env.SUITES_TITLE_UNIT;
if (argv.t === 'system') {
argv.suitesTitle = process.env.SUITES_TITLE_SYSTEM;
}
}
if (argv.t === 'system') {
let serv = await WaitForAPI();
if (serv === null) {
process.exit(1);
}
logger.info(serv);
}
// Instantiate a Mocha instance.
var mocha = NewMocha(argv.reporterType);
var testDir = 'test/' + argv.test;
// Add each .js file to the mocha instance
fs.readdirSync(testDir)
.filter(function (file) {
// Only keep the .js files
return path.extname(file) === '.js';
})
.forEach(function (file) {
mocha.addFile(path.join(testDir, file));
});
try {
// Run the tests.
mocha.run(function (failures) {
process.exitCode = failures ? 1 : 0; // exit with non-zero status if there were failures
if (argv.reporterURL) {
const content = fs.readFileSync(argv.reportPath, { encoding: 'utf8' });
let req = chai
.request(argv.reporterURL)
.post('/api/suites/' + argv.suiteID + '/test-runs')
.send(content)
.set('Content-Type', 'application/xml;charset=utf-8');
if (argv.commitSHA !== null) {
req = req.set('commitsha', argv.commitSHA);
}
req.then((res) => {
if (res.status === 200) {
logger.info('successfully posted result to palantir');
logger.info(res.text);
} else {
logger.warn('Issues posting the results. Status Code: ' + res.status);
logger.warn(res.text);
}
}).catch((err) => {
logger.error('failed to submit result to palantir');
logger.error(err);
});
}
});
} catch (error) {
logger.error('Something caused the test to crash.');
logger.error(error);
console.log(error);
process.exit(1);
}
}
main(); Do you know if there needs to be anything done when programmatically using |
I can confirm that if I remove the Just not sure why the |
In general,
Unfortunately, there is a bug in node that makes node&mocha incompatible with this approach. IIRC, the mocha team can choose to implement a workaround if they want. |
You have to explicitely load the test files asynchronously with loadFilesAsync, before calling |
FWIW, I have nearly the same exact setup as @loganknecht and it's been working fine for months. Today after updating node modules I started getting the same error. In node_modules only the "esm" and "escalade" libraries had been touched, despite neither of them having had a version upgrade. I've been racking my brain trying to figure out what went wrong and then found this issue which was opened only 2 days ago. Could be a coincidence. It's one of those, "but I didn't change anything and now I have to learn node internals" problems... Thanks for all the advice above about switching to modern node esm support. Edit: after spending a few hours down the rabbit hole of converting my project to native esm support (changing all the imports, fixing typescript errors, dealing with modules that could only be required, etc) I got stuck, backed everything out and then the problem mysteriously disappeared. My mocha tests are now back to running normal though I didn't change a thing. |
@juergba and @cspotcode There we go! 👏 👏 👏 👏 👏 The final trick was the requirement of calling Prior to this change. The previous version called Thank you so much for your time, your patience, the example project, and everything in between! |
Hello!
I tried reaching out on
Gitter
, but wasn't able to elicit any help.I am in the process of trying to migrate my team's code base to
TypeScript
in small chunks. Which means I need to haveJavaScript
andTypeScript
supported while this is performed. Additionally I am trying to align the standards for that move.Is there anyone who can provide insight on how to get
mocha
to run for atypescript
project that hasJavascript
in it usingESM module support
?Also quick disclaimer: This is not the
palantir
related to Peter Thiel :/, My team mates just really like Lord of the Rings and chose a poor name for our project.I have a directory structure like so
All my test files have a
.js
extension on themI have a
package.json
file with these contentsI have a default
tsconfig.json
file with these contentsWhich is inherited by the
test/tsconfig.json
and looks like thisAnd then I have a
.mocharc.json
configured with these optionsAnd finally I have a
register.ts
file with these configurationsAdditionally there is a webpack file here:
When I run this command
I am provided this output
I have been testing different configurations non-stop trying to get
to all play nicely.
By default I CAN get the api to stand itself up, but the second
mocha
gets involved this blows up! :(Can anyone provide any guidance?
The text was updated successfully, but these errors were encountered: