Skip to content

Commit

Permalink
test: add unit tests for asyncLoadModule funcion
Browse files Browse the repository at this point in the history
  • Loading branch information
webdiscus committed Dec 8, 2024
1 parent eb941a1 commit 1e7e592
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 5 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@
},
"scripts": {
"security": "npm audit --production",
"test": "jest --config ./test/jest.config.js",
"test": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --config ./test/jest.config.js",
"test:coverage": "jest --collectCoverage --config ./test/jest.config.js",
"test:index": "jest --detectOpenHandles --config ./test/jest.config.js --runTestsByPath ./test/index.test.js",
"test:issue": "jest --detectOpenHandles --config ./test/jest.config.js --runTestsByPath ./test/issue.test.js",
"test:messages": "jest --detectOpenHandles --config ./test/jest.config.js --runTestsByPath ./test/messages.test.js",
"test:unit": "jest --detectOpenHandles --collectCoverage --config ./test/jest.config.js --runTestsByPath ./test/unit.test.js",
"test:unit": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" jest --detectOpenHandles --collectCoverage --config ./test/jest.config.js --runTestsByPath ./test/unit.test.js",
"test:unitQueryParser": "jest --detectOpenHandles --collectCoverage --config ./test/jest.config.js --runTestsByPath ./test/unit.queryParser.test.js",
"test:verbose": "jest --detectOpenHandles --config ./test/jest.config.js --runTestsByPath ./test/verbose.test.js",
"test:verbose-update": "jest --detectOpenHandles --updateSnapshot --config ./test/jest.config.js --runTestsByPath ./test/verbose.test.js",
Expand Down
40 changes: 39 additions & 1 deletion src/Common/FileUtils.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// noinspection DuplicatedCode

const path = require('path');
const fs = require('fs');
const { red, redBright, cyan, whiteBright } = require('ansis');
const { isWin, pathToPosix } = require('./Helpers');
const Config = require('../Common/Config');
Expand All @@ -12,6 +13,40 @@ const nodeModuleDirname = path.sep + 'node_modules' + path.sep;
const testDirname = path.sep + path.join(pluginName, 'test') + path.sep;
const srcDirname = path.sep + path.join(pluginName, 'src') + path.sep;

/**
* Dynamically load a CommonJS or ESM module.
*
* @param {string} filePath The path to the module file.
* @returns {Promise<any>} The loaded module.
* @throws
*/
async function asyncLoadModule(filePath) {
const absolutePath = path.resolve(filePath);
const ext = path.extname(absolutePath).toLowerCase();

if (!fs.existsSync(absolutePath)) {
throw new Error(`File not found: ${cyan(absolutePath)}`);
}

if (ext === '.mjs') {
// ESM file
return import(absolutePath);
} else if (ext === '.cjs' || ext === '.js') {
// CommonJS file
try {
return require(absolutePath);
} catch (error) {
if (error.code === 'ERR_REQUIRE_ESM') {
// fallback to ESM
return import(absolutePath);
}
throw error;
}
} else {
throw new Error(`Unsupported file type: ${cyan(`.${ext}`)}`);
}
}

/**
* Load node module.
*
Expand All @@ -29,7 +64,9 @@ const loadModule = (moduleName, callback = null, context = process.cwd()) => {
moduleFile = require.resolve(moduleName, { paths: [context] });
} catch (error) {
if (error.code === 'MODULE_NOT_FOUND') {
const message = whiteBright`Cannot find module '${red(moduleName)}'. Please install the missing module: ${cyan`npm i -D ${moduleName}`}` + "\n";
const message =
whiteBright`Cannot find module '${red(moduleName)}'. Please install the missing module: ${cyan`npm i -D ${moduleName}`}` +
'\n';
throw new Error(message);
}
throw error;
Expand Down Expand Up @@ -280,6 +317,7 @@ const touch = (file, { fs }) => {
};

module.exports = {
asyncLoadModule,
loadModule,
isDir,
readDirRecursiveSync,
Expand Down
1 change: 1 addition & 0 deletions test/fixtures/modules/example-cjs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { message: 'Hello from .js file' }; // Or use ESM syntax depending on `package.json`
1 change: 1 addition & 0 deletions test/fixtures/modules/example-esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const message = 'Hello from .js file';
1 change: 1 addition & 0 deletions test/fixtures/modules/example.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = { message: 'Hello from CommonJS' };
1 change: 1 addition & 0 deletions test/fixtures/modules/example.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const message = 'Hello from ESM';
54 changes: 52 additions & 2 deletions test/unit.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
import path from 'path';
import fs from 'fs';

import { findPlugin, getFileExtension, parseVersion, compareVersions } from '../src/Common/Helpers';
import WeakMapIterable from '../src/Common/WeakMapIterable';
import VMScript from '../src/Common/VMScript';
import { HtmlParser } from '../src/Common/HtmlParser';
import { isDir, loadModule, resolveFile, filterParentPaths, relativePathVerbose } from '../src/Common/FileUtils';
import {
isDir,
asyncLoadModule,
loadModule,
resolveFile,
filterParentPaths,
relativePathVerbose,
} from '../src/Common/FileUtils';
import {
stringifyJSON,
stringifyFn,
Expand Down Expand Up @@ -1544,7 +1552,49 @@ describe('plugin isInlineCss option', () => {
});
});

describe('FileUtils', () => {
describe('asyncLoadModule', () => {
test('example.cjs', async () => {
// usage example
// (async () => {
// // dynamically load CommonJS module
// const commonJSModule = await asyncLoadModule('./fixtures/modules/example.cjs');
// console.log('Loaded CommonJS Module:', commonJSModule);
// })();

const commonJSModule = await asyncLoadModule(path.join(__dirname, './fixtures/modules/example.cjs'));
const received = commonJSModule.message;
const expected = 'Hello from CommonJS';

expect(expected).toEqual(received);
});

test('example-cjs.js', async () => {
const esmModule = await asyncLoadModule(path.join(__dirname, './fixtures/modules/example-cjs.js'));
const received = esmModule.message;
const expected = 'Hello from .js file';

expect(received).toEqual(expected);
});

// Jest doesn't support ESM without --experimental-vm-modules
test('example.mjs', async () => {
const esmModule = await asyncLoadModule(path.join(__dirname, './fixtures/modules/example.mjs'));
const received = esmModule.message;
const expected = 'Hello from ESM';

expect(received).toEqual(expected);
});

test('example-esm.js', async () => {
const esmModule = await asyncLoadModule(path.join(__dirname, './fixtures/modules/example-esm.js'));
const received = esmModule.message;
const expected = 'Hello from .js file';

expect(received).toEqual(expected);
});
});

describe('FileUtils Sync', () => {
test('load module', (done) => {
try {
const ansis = loadModule('ansis');
Expand Down

0 comments on commit 1e7e592

Please sign in to comment.