UNPKG

als-require

Version:

A utility for using CommonJS require in the browser and creating bundles.

235 lines (200 loc) 9.67 kB
const { describe, it, afterEach } = require('node:test'); const assert = require('node:assert'); const Require = require('../index'); const fs = require('fs') const { join } = require('path') function levenshtein(a, b) { const an = a ? a.length : 0; const bn = b ? b.length : 0; if (an === 0) return bn; if (bn === 0) return an; const matrix = new Array(bn + 1); for (let i = 0; i <= bn; ++i) { matrix[i] = new Array(an + 1); matrix[i][0] = i; } for (let j = 0; j <= an; ++j) { matrix[0][j] = j; } for (let i = 1; i <= bn; ++i) { for (let j = 1; j <= an; ++j) { const cost = (b[i - 1] === a[j - 1]) ? 0 : 1; matrix[i][j] = Math.min( matrix[i - 1][j] + 1, // Deletion matrix[i][j - 1] + 1, // Insertion matrix[i - 1][j - 1] + cost // Substitution ); } } return matrix[bn][an]; } function areStringsApproximatelyEqual(a, b) { const distance = levenshtein(a, b); const length = Math.max(a.length, b.length); return (distance / length) <= 0.5; } const mockModulePath = './modules/testModule'; describe('Require class tests', () => { it('should have static properties initialized', () => { assert.ok(Require.contents, 'Contents static property should be defined'); assert.strictEqual(typeof Require.contents, 'object', 'Contents should be an object'); }); it('Integrative test', () => { const mod = new Require('./modules/a') Object.entries(mod.contents).forEach(([path, content]) => { const fullPath = join(__dirname, '..', path) const actual = fs.readFileSync(fullPath, 'utf-8') assert(areStringsApproximatelyEqual(actual, content)) }) assert.notDeepStrictEqual(mod.contents, {}) assert.notDeepStrictEqual(Require.contents, {}) const scriptAfter = 'Object.entries(modules).forEach(([k,v]) => _modules[k] = v);' const fn = mod.fn({scriptAfter,parameters:['_modules','context']}) const modules = {}, context = {}; const result = fn(modules,context) const expected = { c: 'c', b: 'b', a: 'a' } assert.deepStrictEqual(result(), expected) assert.deepStrictEqual(context, expected) const expectedPaths = [ '/tests/modules/sub1/c.js', '/tests/modules/sub/b.js', '/tests/modules/a.js' ] assert.deepStrictEqual(Object.keys(modules), expectedPaths) // assert(Require.getModule('./modules/a').toString() === result.toString()) }) it('should handle cyclic dependencies', () => { try { const mod = new Require('./modules/d'); assert(false) } catch (error) { assert(error === 'Cyclic dependency between /tests/modules/e.js and /tests/modules/d.js') } }); it('Catch syntax error', () => { const mod = new Require('./modules/parent'); try { const result = mod.fn() // result() assert(false, 'Should throw error') } catch (error) { // console.log(error) assert(true) } }) it('Catch error', () => { const mod = new Require('./modules/parent1'); try { const result = mod.fn()() // result() assert(false, 'Should throw error') } catch (error) { // console.log(error) assert(error.stack.includes('at some /tests/modules/moduleWithError1.js (2:10)')) assert(error.stack.includes('at Object.____ /tests/modules/parent1.js (3:16)')) } // console.log(mod) }) it('node modules dependency', () => { const originalWarn = console.warn const msgs = [] console.warn = (msg) => msgs.push(msg) const mod = new Require('./modules/node-dependency'); const result = mod.fn()() console.warn = originalWarn // console.log(result) assert(typeof result.calledFrom === 'function') assert(typeof result.calledFrom1 === 'function') assert.deepStrictEqual(result.fs,{}) assert(msgs.length > 0) }) }); describe('Require class extended tests', () => { it('should allow changing the context name dynamically', async () => { const req = new Require('./modules/testModule', { customKey: 'initial value' }); const context = { customKey: 'customValue' }; const result = req.fn({parameters:['customContext']})(context); assert(JSON.stringify(result) === JSON.stringify({ result: 'Success', contextValue: 'customValue' })) }); it('should handle multiple contexts correctly', async () => { Require.contextName = 'firstContext' const req = new Require('./modules/testModule'); const firstResult = req.fn({parameters:['firstContext']})({ data: 'first' }) assert(JSON.stringify(firstResult) === JSON.stringify({ result: 'Success', contextValue: 'first' })) const secondResult = req.fn({parameters:['secondContext']})({ data: 'second' }) assert(JSON.stringify(secondResult) === JSON.stringify({ result: 'Success', contextValue: 'second' })) }); it('should correctly handle custom context names in errors', async () => { const req = new Require('./modules/moduleWithError'); try { req.fn({parameters:['customErrorContext']})({ errorDetail: 'critical' }); assert.fail('Should have thrown an error due to module error'); } catch (error) { assert(error.message.includes('customErrorContext'), 'Error does not correctly reference the custom context name'); } }); it('should handle multiple contexts correctly', async () => { const req = new Require('./modules/testModule'); const firstResult = req.fn({parameters:['firstContext']})({ data: 'first' }) assert(JSON.stringify(firstResult) === JSON.stringify({ result: 'Success', contextValue: 'first' })) const secondResult = req.fn({parameters:['secondContext']})({ data: 'second' }) assert(JSON.stringify(secondResult) === JSON.stringify({ result: 'Success', contextValue: 'second' })) }); it('should correctly handle custom context names in errors', async () => { const req = new Require('./modules/moduleWithError'); try { req.fn({parameters:['customErrorContext']})({ errorDetail: 'critical' }); assert.fail('Should have thrown an error due to module error'); } catch (error) { assert(error.message.includes('customErrorContext'), 'Error does not correctly reference the custom context name'); } }); }); describe('Require class extended tests 2', () => { it('should allow changing the context name dynamically', async () => { const req = new Require('./modules/testModule', { customKey: 'initial value' }); const context = { customKey: 'customValue' }; const result = req.fn({ parameters: ['customContext'] })(context); assert(JSON.stringify(result) === JSON.stringify({ result: 'Success', contextValue: 'customValue' })); }); it('should handle multiple contexts correctly', async () => { Require.contextName = 'firstContext'; const req = new Require('./modules/testModule'); const firstResult = req.fn({ parameters: ['firstContext'] })({ data: 'first' }); assert(JSON.stringify(firstResult) === JSON.stringify({ result: 'Success', contextValue: 'first' })); const secondResult = req.fn({ parameters: ['secondContext'] })({ data: 'second' }); assert(JSON.stringify(secondResult) === JSON.stringify({ result: 'Success', contextValue: 'second' })); }); it('should correctly handle custom context names in errors', async () => { const req = new Require('./modules/moduleWithError'); try { req.fn({ parameters: ['customErrorContext'] })({ errorDetail: 'critical' }); assert.fail('Should have thrown an error due to module error'); } catch (error) { assert(error.message.includes('customErrorContext'), 'Error does not correctly reference the custom context name'); } }); it('should apply scriptBefore and scriptAfter in fn options', () => { const mod = new Require('./modules/fnOptionsTest'); const scriptBefore = 'const x = 10;'; const scriptAfter = 'return result + x;'; const fn = mod.fn({ scriptBefore, scriptAfter }); const result = fn(); assert.strictEqual(result, 15); // Предполагая, что module.exports равно 5 }); it('should accept custom parameters in fn options', () => { const mod = new Require('./modules/fnOptionsTestParameters'); const fn = mod.fn({ parameters: ['customParam'] }); const result = fn(42); assert.strictEqual(result, 47); // Предполагая, что module.exports равно customParam + 5 }); it('should set function name in stringFn when name option is provided', () => { const mod = new Require('./modules/fnOptionsTest'); const fnString = mod.stringFn({ name: 'myCustomFunction' }); assert.ok(fnString.startsWith('function myCustomFunction('), 'Function name should be set to "myCustomFunction"'); // Проверяем, что функция с заданным именем работает корректно const func = eval(`(${fnString})`); const result = func(); assert.strictEqual(result, 5); // Предполагая, что module.exports равно 5 }); });