diff --git a/.circleci/config.yml b/.circleci/config.yml index c5f91e47..d59095a8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -73,5 +73,3 @@ workflows: branches: only: - main - - "3.99" - - "4.0" diff --git a/lib/loader.js b/lib/loader.js index 8655c32f..28242e14 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -18,7 +18,20 @@ Loader.prototype.load = function(modulePath) { return this.import_(url) .then( mod => mod.default, - e => Promise.reject(fixupImportException(e, modulePath)) + e => { + if (e.code === 'ERR_UNKNOWN_FILE_EXTENSION') { + // Extension isn't supported by import, e.g. .jsx. Fall back to + // require(). This could lead to confusing error messages if someone + // tries to use ES module syntax without transpiling in a file with + // an unsupported extension, but it shouldn't break anything and it + // should work well in the normal case where the file is loadable + // as a CommonJS module, either directly or with the help of a + // loader like `@babel/register`. + return this.require_(modulePath); + } else { + return Promise.reject(fixupImportException(e, modulePath)); + } + } ); } else { return new Promise(resolve => { diff --git a/package.json b/package.json index 2f528dbf..aa08af02 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "bdd" ], "license": "MIT", - "version": "4.0.0", + "version": "4.0.1", "repository": { "type": "git", "url": "https://github.com/jasmine/jasmine-npm" diff --git a/release_notes/4.0.0.md b/release_notes/4.0.0.md index af83329a..49b9e247 100644 --- a/release_notes/4.0.0.md +++ b/release_notes/4.0.0.md @@ -26,6 +26,15 @@ as well. [API reference](https://jasmine.github.io/api/npm/4.0/Jasmine) is considered a private API. +* ES module support is enabled by default, but can still be disabled by + adding `jsLoader: "require"` to the configuration. `jsLoader: "import"` is + now a no-op. + + This change breaks loading of files with extensions that aren't supported by + dynamic `import()`, such as `.jsx`. If you have specs or source files with + such extensions, you can either rename the files to `.js` or add + `jsLoader: "require"` to your Jasmine config file. + * Config files can be ES modules. This is a breaking change because it requires `Jasmine#loadConfigFile` to be async. @@ -57,20 +66,9 @@ as well. ## New features and bugfixes -* Full support for ES modules in the default configuration: - * ES module support is enabled by default, but can still be disabled by - adding `jsLoader: "require"` to the configuration. `jsLoader: "import"` is - now a no-op. - - We think it's highly unlikely that this change will break anything. If it - does (i.e. your code works with `jsLoader: "require"` but not without it), - please [let us know](https://github.com/jasmine/jasmine-npm/issues/new). - This will help us understand whether the `jsLoader` config property is still - needed. - - * Files listed in the `requires` config property can be ES modules +* Files listed in the `requires` config property can be ES modules - * Reporters specified with `--reporter=` can be ES modules. +* Reporters specified with `--reporter=` can be ES modules. * Allow use without creating globals. * See . diff --git a/release_notes/4.0.1.md b/release_notes/4.0.1.md new file mode 100644 index 00000000..9119699a --- /dev/null +++ b/release_notes/4.0.1.md @@ -0,0 +1,13 @@ +# Jasmine NPM 4.0.1 Release Notes + +## Summary + +This release fixes loading of files with nonstandard extensions (e.g. .jsx, +.coffee) in the default configuration by falling back to `require()` when +`import()` fails because of an unsupported file extension. See +[#188](https://github.com/jasmine/jasmine-npm/issues/188). + + +------ + +_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_ diff --git a/spec/fixtures/import-jsx/jasmine.json b/spec/fixtures/import-jsx/jasmine.json new file mode 100644 index 00000000..54b4f2ca --- /dev/null +++ b/spec/fixtures/import-jsx/jasmine.json @@ -0,0 +1,7 @@ +{ + "spec_dir": ".", + "spec_files": [ + "spec.jsx" + ], + "helpers": [] +} diff --git a/spec/fixtures/import-jsx/spec.jsx b/spec/fixtures/import-jsx/spec.jsx new file mode 100644 index 00000000..8e6c54fe --- /dev/null +++ b/spec/fixtures/import-jsx/spec.jsx @@ -0,0 +1,2 @@ +it('is a spec', function() { +}); diff --git a/spec/integration_spec.js b/spec/integration_spec.js index 144ca316..b36d49e7 100644 --- a/spec/integration_spec.js +++ b/spec/integration_spec.js @@ -65,6 +65,11 @@ describe('Integration', function () { expect(await runJasmine('spec/fixtures/js-loader-default')).toBeSuccess(); }); + it('falls back to require when loading extensions that import does not support', async function() { + expect(await runJasmine('spec/fixtures/import-jsx')).toBeSuccess(); + }); + + it('handles load-time exceptions from CommonJS specs properly', async function () { const {exitCode, output} = await runJasmine('spec/fixtures/cjs-load-exception'); expect(exitCode).toEqual(1); diff --git a/spec/loader_spec.js b/spec/loader_spec.js index db54af22..2c5723a2 100644 --- a/spec/loader_spec.js +++ b/spec/loader_spec.js @@ -19,6 +19,26 @@ describe('loader', function() { esModuleSharedExamples('js', true); }); + describe('When the extnesion is not supported by import()', function() { + it('falls back to require()', async function() { + const error = new TypeError(); + error.code = 'ERR_UNKNOWN_FILE_EXTENSION'; + const payload = {}; + const requireShim = jasmine.createSpy('requireShim') + .and.returnValue(Promise.resolve(payload)); + const importShim = jasmine.createSpy('importShim') + .and.returnValue(Promise.reject(error)); + const loader = new Loader({requireShim, importShim}); + loader.alwaysImport = true; + + const result = await loader.load('./spec.jsx'); + + expect(result).toBe(payload); + expect(requireShim).toHaveBeenCalled(); + expect(importShim).toHaveBeenCalled(); + }); + }); + it('uses require to load JSON files', async function() { const requireShim = jasmine.createSpy('requireShim') .and.returnValue(Promise.resolve());