Skip to content

Commit

Permalink
Make the moment loader works in Jest env (closes DevExpress#2500) (De…
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreyBelym authored and kirovboris committed Dec 18, 2019
1 parent 28b1ac9 commit c8db6ab
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 71 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
"map-reverse": "^1.0.1",
"mkdirp": "^0.5.1",
"moment": "^2.10.3",
"moment-duration-format": "^2.2.2",
"moment-duration-format-commonjs": "^1.0.0",
"mustache": "^2.1.2",
"nanoid": "^1.0.1",
"node-version": "^1.0.0",
Expand Down
83 changes: 14 additions & 69 deletions src/utils/moment-loader.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,24 @@
import resolveFrom from 'resolve-from';
import momentDurationFormatSetup from 'moment-duration-format-commonjs';


const MOMENT_MODULE_NAME = 'moment';
const DURATION_FORMAT_MODULE_NAME = 'moment-duration-format';
const MOMENT_MODULE_NAME = 'moment';

function restoreInitialCacheState (module, path) {
if (module)
require.cache[path] = module;
else
delete require.cache[path];
}

function getSideMomentModulePath (sidePath) {
try {
return resolveFrom(sidePath, MOMENT_MODULE_NAME);
}
catch (err) {
return '';
}
}

function getModulesPaths () {
const durationFormatModulePath = require.resolve(DURATION_FORMAT_MODULE_NAME);

return {
durationFormatModulePath,

mainMomentModulePath: require.resolve(MOMENT_MODULE_NAME),
sideMomentModulePath: getSideMomentModulePath(durationFormatModulePath)
};
}

function getCachedAndCleanModules (modulePath) {
const cachedModule = require.cache[modulePath];

delete require.cache[modulePath];
function loadMomentModule () {
const momentModulePath = require.resolve(MOMENT_MODULE_NAME);
const savedMomentModule = require.cache[momentModulePath];

require(modulePath);
delete require.cache[savedMomentModule];

return { cachedModule, cleanModule: require.cache[modulePath] };
}

function getMomentModules ({ mainMomentModulePath, sideMomentModulePath }) {
const { cachedModule, cleanModule } = getCachedAndCleanModules(mainMomentModulePath);

return {
sideModule: require.cache[sideMomentModulePath],
mainModule: cleanModule,
cachedModule
};
}

function getMomentModuleWithDurationFormatPatch () {
const modulesPaths = getModulesPaths();
const momentModules = getMomentModules(modulesPaths);
const moment = require(momentModulePath);

const { sideMomentModulePath, mainMomentModulePath, durationFormatModulePath } = modulesPaths;
momentDurationFormatSetup(moment);

if (sideMomentModulePath && sideMomentModulePath !== mainMomentModulePath) {
require.cache[sideMomentModulePath] = momentModules.mainModule;

require(durationFormatModulePath);

restoreInitialCacheState(momentModules.sideModule, sideMomentModulePath);
}
else {
const durationFormatSetup = require(durationFormatModulePath);

if (!sideMomentModulePath)
durationFormatSetup(momentModules.mainModule.exports);
}

restoreInitialCacheState(momentModules.cachedModule, mainMomentModulePath);
if (savedMomentModule)
require.cache[momentModulePath] = savedMomentModule;
else
delete require.cache[momentModulePath];

return momentModules.mainModule.exports;
return moment;
}

export default getMomentModuleWithDurationFormatPatch();
export default loadMomentModule();
55 changes: 54 additions & 1 deletion test/server/util-test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const path = require('path');
const Module = require('module');
const fs = require('fs');
const del = require('del');
const expect = require('chai').expect;
Expand All @@ -9,6 +10,7 @@ const TempDirectory = require('../../lib/utils/temp-directory
const { replaceLeadingSpacesWithNbsp } = require('../../lib/utils/string');
const getCommonPath = require('../../lib/utils/get-common-path');


describe('Utils', () => {
it('Correct File Path', () => {
expect(correctFilePath('\\test')).eql('/test');
Expand Down Expand Up @@ -131,7 +133,7 @@ describe('Utils', () => {
});

it('Get common path', () => {
const pathFragemts = [ 'home', 'user1', 'tmp' ];
const pathFragemts = ['home', 'user1', 'tmp'];
const path1 = path.join(...pathFragemts);
const path2 = path.join(pathFragemts[0], pathFragemts[1]);
const path3 = path.join(pathFragemts[0], pathFragemts[2]);
Expand All @@ -141,4 +143,55 @@ describe('Utils', () => {
expect(getCommonPath([path1, path2])).eql(path2);
expect(getCommonPath([path1, path2, path3])).eql(pathFragemts[0]);
});

describe('Moment Module Loader', () => {
const moduleCacheDesciptor = Object.getOwnPropertyDescriptor(Module, '_cache');
const originalLoad = Module._load;

beforeEach(() => {
for (const cachedModule of Object.keys(require.cache))
delete require.cache[cachedModule];
});

afterEach(() => {
Module._load = originalLoad;

Object.defineProperty(Module, '_cache', moduleCacheDesciptor);
});

it('Should work when multiple moment modules are installed (GH-1750)', () => {
const momentModulePath = require.resolve('moment');

for (const cachedModule of Object.keys(require.cache))
delete require.cache[cachedModule];

Module._load = function (...args) {
const modulePath = Module._resolveFilename(...args);

// NOTE: Remove cached moment module to simulate multiple installations of moment
if (modulePath === modulePath)
delete Module._cache[momentModulePath];

return originalLoad.apply(this, args);
};

const moment = require('../../lib/utils/moment-loader');

expect(moment.duration.format).to.be.ok;
});

it('Should work when modules cache is disabled (GH-2500)', () => {
Object.defineProperty(Module, '_cache', {
enumerable: true,
configurable: true,

get: () => Object.create(null),
set: v => v
});

const moment = require('../../lib/utils/moment-loader');

expect(moment.duration.format).to.be.ok;
});
});
});

0 comments on commit c8db6ab

Please sign in to comment.