UNPKG

als-require

Version:

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

359 lines (303 loc) 16.2 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="/require.js"></script> <!-- <script src="/require.min.js"></script> --> <title>Tests</title> </head> <body> </body> <script src="/node_modules/als-browser-test/index.js"></script> <script> describe('Basic tests', () => { it('Integrative test', async () => { const mod = new Require('./modules/a') assert(JSON.stringify(mod.contents) === '{}', 'mod.contents should be empty') assert(JSON.stringify(Require.contents) === '{}', 'Require.contents should be empty') await mod.getContent() assert(JSON.stringify(mod.contents) !== '{}', 'mod.contents not should be empty') assert(JSON.stringify(Require.contents) !== '{}', 'Require.contents not should be empty') 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 = JSON.stringify({ c: 'c', b: 'b', a: 'a' }) assert(JSON.stringify(result()) === expected, 'Result should be as expected') assert(JSON.stringify(context) === expected, 'context should be as expected') const expectedPaths = JSON.stringify([ '/tests/modules/sub1/c.js', '/tests/modules/sub/b.js', '/tests/modules/a.js' ]) assert(JSON.stringify(Object.keys(modules)), expectedPaths) const result1 = await Require.getModule('./modules/a',{parameters:['context']},{}) assert(result.toString() === result.toString()) }) it('should initialize with default properties', () => { const testContext = { some: 'context' }; const req = new Require('./path/to/module', testContext); assert(req.path === './path/to/module', 'Initial path is not set correctly'); assert(JSON.stringify(req.contents) === '{}', 'Contents should be initialized to an empty object'); }); it('should have static properties initialized', () => { assert(Require.contents !== undefined, 'Contents static property should be defined'); assert(typeof Require.contents === 'object', 'Contents should be an object'); }); it('should handle cyclic dependencies', async () => { const mod = new Require('./modules/d'); try { await mod.getContent() assert(false, 'Should throw error for cyclic') } catch (error) { assert(error === 'cyclic dependency between /tests/modules/e.js and /tests/modules/d.js') } }); it('Catch syntax error', async () => { const mod = new Require('./modules/parent'); await mod.getContent() try { const result = mod.build() // result() assert(false, 'Should throw error') } catch (error) { // console.log(error) assert(true) } }) it('Catch error', async () => { const mod = new Require('./modules/parent1'); await mod.getContent() const resultFn = mod.fn() try { resultFn() assert(false, 'Should throw error') } catch (error) { // console.log(error.stack) 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', async () => { const originalWarn = console.warn const msgs = [] console.warn = (msg) => msgs.push(msg) const mod = new Require('./modules/node-dependency'); await mod.getContent() const resultFn = mod.fn() const result = resultFn() console.warn = originalWarn // console.log(result) assert(typeof result.calledFrom === 'function') assert(typeof result.calledFrom1 === 'function') assert.deepStrictEqual(result.fs, {}) assert(msgs.length > 0) }) it('should allow changing the context name dynamically', async () => { const req = new Require('./modules/testModule', { customKey: 'initial value' }); const context = { customKey: 'customValue' }; await req.getContent(); 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'); await req.getContent(); 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'); await req.getContent(); 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('Other tests', () => { let logs = []; const logger = { warn: (msg) => logs.push(msg) }; const originalFetch = window.fetch; const { getNodeModules, standartNodeModules } = Require function makeFetch() { window.fetch = async (url, options) => { if (options && options.method === 'HEAD') { // Проверка существования package.json if (url.endsWith('package.json')) return { ok: true }; return { ok: false }; } // Чтение package.json if (url.includes('module-a/package.json')) return { ok: true, json: async () => ({ main: 'index.js' }) }; if (url.includes('module-b/package.json')) return { ok: true, json: async () => ({ main: 'lib/main.js' }) }; if (url.includes('module-c/package.json')) return { ok: true, json: async () => ({}) }; if (url.includes('module-d/package.json')) return { ok: true, json: async () => ({ main: 'src/app.js' }) }; return { ok: false }; }; } function returnFetch() { window.fetch = originalFetch; } it('Должен возвращать false для стандартных модулей Node.js', async () => { makeFetch() let result = true for (const module of standartNodeModules) { logs = [] const result = await getNodeModules([{ modulePath: module }], [], '', Require, logger); if (logs.includes(`The module "${module}" can't be imported and will be replaced with {}`)) continue result = false // assert(logs.includes(`The module "${module}" can't be imported and will be replaced with {}`)); // assert.strictEqual(result, ''); } assert(result) returnFetch() }); // it.only('Должен возвращать полный путь для существующего модуля с "main" в package.json', async () => { // const result = await getNodeModules([{ modulePath: 'module-a' }], [], 'const aa = require("module-a/some/test.js")', Require, logger); // console.log(result) // // assert.strictEqual(result, '/node_modules/module-a/index.js'); // }); // it('Должен возвращать полный путь для модуля с вложенным путём в "main" в package.json', async () => { // makeFetch() // const result = await getNodeModules([{ modulePath: 'module-b' }], [], '', Require, logger); // console.log(result) // // assert.strictEqual(result, '/node_modules/module-b/lib/main.js'); // returnFetch() // }); // it.only('Должен возвращать "index.js" по умолчанию, если "main" отсутствует в package.json', async () => { // makeFetch() // const result = await getNodeModules([{ modulePath: 'module-c' }], [], "require('module-c')", Require, logger); // // console.log(result) // // assert.strictEqual(result, '/node_modules/module-c/index.js'); // returnFetch() // }); // it.only('Должен возвращать false для несуществующих модулей', async () => { // makeFetch() // logs = [] // const result = await getNodeModules([{ modulePath: 'non-existent-module' }], [], '', Require, logger); // assert(logs.length > 0); // assert.strictEqual(result, ''); // returnFetch() // }); // it('Должен кешировать "main" из package.json', async () => { // const modulePath = 'module-a'; // const firstCall = await getNodeModules([{ modulePath }], [], '', Require, logger); // const secondCall = await getNodeModules([{ modulePath }], [], '', Require, logger); // assert.strictEqual(firstCall, '/node_modules/module-a/index.js'); // assert.strictEqual(secondCall, '/node_modules/module-a/index.js'); // }); // it('Должен корректно обрабатывать modulePath с относительным путём', async () => { // const result = await getNodeModules([{ modulePath: 'module-b/lib/utils' }], [], '', Require, logger); // assert.strictEqual(result, '/node_modules/module-b/lib/utils.js'); // }); // it('Должен корректно обрабатывать относительный путь в main', async () => { // const result = await getNodeModules([{ modulePath: 'module-d/src/utils' }], [], '', Require, logger); // assert.strictEqual(result, '/node_modules/module-d/src/utils.js'); // }); // window.fetch = originalFetch; }) describe('Require class extended tests 2', () => { it('should allow changing the context name dynamically', async () => { const req = new Require('./modules/testModule', { customKey: 'initial value' }); await req.getContent(); 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 () => { const req = new Require('./modules/testModule'); await req.getContent(); 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'); await req.getContent(); 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', async () => { const mod = new Require('./modules/fnOptionsTest'); await mod.getContent(); 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', async () => { const mod = new Require('./modules/fnOptionsTestParameters'); await mod.getContent(); const fn = mod.fn({ parameters: ['customParam'] }); const result = fn(42); assert.strictEqual(result, 47); // Предполагая, что module.exports равно customParam + 5 }); }); describe('Require class plugins tests', () => { it('should modify module content using a single plugin', async () => { const plugin = (mod) => { // Плагин заменяет слово 'original' на 'modified' mod.content = mod.content.replace(/original/g, 'modified'); }; const mod = new Require('./modules/pluginTest', { plugins: [plugin] }); await mod.getContent(); const fn = mod.fn(); const result = fn(); assert.strictEqual(result, 'This is a modified content.', 'Content should be modified by the plugin'); }); it('should apply multiple plugins sequentially', async () => { const plugin1 = (mod) => { // Плагин заменяет 'original' на 'temp' mod.content = mod.content.replace(/original/g, 'temp'); }; const plugin2 = (mod) => { // Плагин заменяет 'temp' на 'final' mod.content = mod.content.replace(/temp/g, 'final'); }; const mod = new Require('./modules/pluginTest', { plugins: [plugin1, plugin2] }); await mod.getContent(); const fn = mod.fn(); const result = fn(); assert.strictEqual(result, 'This is a final content.', 'Content should be modified by both plugins sequentially'); }); it('should not break if a plugin does not modify the content', async () => { const plugin = (module) => { // Пустой плагин, ничего не меняет }; const mod = new Require('./modules/pluginTest', { plugins: [plugin] }); await mod.getContent(); const fn = mod.fn(); const result = fn(); assert.strictEqual(result, 'This is a original content.', 'Content should remain unchanged'); }); it('should handle plugins that throw errors gracefully', async () => { const plugin = (module) => { // Плагин выбрасывает ошибку throw new Error('Plugin error'); }; try { const mod = new Require('./modules/pluginTest', { plugins: [plugin] }); await mod.getContent(); mod.fn(); assert.fail('Should have thrown an error'); } catch (error) { assert.strictEqual(error.message, 'Plugin error', 'Error message should match the plugin error'); } }); }); runTests() </script> </html>