hot-import
Version:
Hot Module Replacement (HMR) for Node.js
270 lines • 13.1 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
// tslint:disable:no-shadowed-variable
const test = require("blue-tape");
const fixtures_1 = require("../tests/fixtures");
const hot_import_1 = require("./hot-import");
// import { log } from 'brolog'
// log.level('silly')
const EXPECTED_TEXT = 'testing123';
test('callerResolve()', (t) => __awaiter(this, void 0, void 0, function* () {
const RELATIVE_FILE_PATH = './test';
const ABSOLUTE_FILE_PATH = path.resolve(__dirname, RELATIVE_FILE_PATH);
t.test('relative file path', (t) => __awaiter(this, void 0, void 0, function* () {
const filePath = hot_import_1.callerResolve(RELATIVE_FILE_PATH);
t.equal(filePath, ABSOLUTE_FILE_PATH, 'should turn relative to absolute');
}));
t.test('absolute file path', (t) => __awaiter(this, void 0, void 0, function* () {
const filePath = hot_import_1.callerResolve(ABSOLUTE_FILE_PATH);
t.equal(filePath, ABSOLUTE_FILE_PATH, 'should keep absolute as it is');
}));
t.test('callerExceptFile', (t) => __awaiter(this, void 0, void 0, function* () {
const filePath = hot_import_1.callerResolve(RELATIVE_FILE_PATH, __filename);
// console.log(filePath)
t.assert(filePath.endsWith(path.join(// cross platform: compatible with windows
'node_modules', 'tape', 'lib', 'test')), 'except the current file name');
}));
}));
test('newCall()', (t) => __awaiter(this, void 0, void 0, function* () {
class TextClass {
constructor(text) {
this.text = text;
}
}
const textClass = hot_import_1.newCall(TextClass, EXPECTED_TEXT);
t.equal(textClass.text, EXPECTED_TEXT, 'should instanciate class with constructor arguments');
}));
test('hotImport()', (t) => __awaiter(this, void 0, void 0, function* () {
t.test('class module(export=)', (t) => __awaiter(this, void 0, void 0, function* () {
var e_1, _a;
let file, Cls;
try {
for (var _b = __asyncValues(fixtures_1.changingClassModuleFixtures()), _c; _c = yield _b.next(), !_c.done;) {
const info = _c.value;
/**
* io event loop wait for fs.watch
* FIXME: Find out the reason...
*/
yield new Promise(setImmediate); // the first one is enough for Linux(Ubuntu 17.04)
yield new Promise(setImmediate); // the second one is needed for Windows 7
if (!Cls) {
file = info.file;
Cls = yield hot_import_1.hotImport(file);
}
else {
t.equal(file, info.file, 'should get same module file for fixtures(change file content only)');
}
yield new Promise(resolve => setTimeout(resolve, 10));
const result = new Cls(EXPECTED_TEXT);
t.equal(result.text, EXPECTED_TEXT, 'should get expected values from instance of class in module');
t.equal(result.id, info.returnValue, 'should import module class with right id:' + info.returnValue);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) yield _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
if (file) {
yield hot_import_1.hotImport(file, false);
}
}));
t.test('variable module(export const answer=)', (t) => __awaiter(this, void 0, void 0, function* () {
var e_2, _d;
let file, hotMod;
try {
for (var _e = __asyncValues(fixtures_1.changingVariableModuleFixtures()), _f; _f = yield _e.next(), !_f.done;) {
const info = _f.value;
/**
* io event loop wait for fs.watch
* FIXME: Find out the reason...
*/
yield new Promise(setImmediate); // the first one is enough for Linux(Ubuntu 17.04) with Node.js v8
yield new Promise(setImmediate); // the second one is needed for Windows 7
if (!hotMod) {
file = info.file;
hotMod = yield hot_import_1.hotImport(file);
}
else {
t.equal(file, info.file, 'should get same module file for fixtures(change file content only)');
}
yield new Promise(resolve => setTimeout(resolve, 10));
t.equal(hotMod.answer, info.returnValue, 'should get expected values from variable in module');
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_f && !_f.done && (_d = _e.return)) yield _d.call(_e);
}
finally { if (e_2) throw e_2.error; }
}
if (file) {
yield hot_import_1.hotImport(file, false);
}
}));
t.test('raw export module(export = () => "value")', (t) => __awaiter(this, void 0, void 0, function* () {
var e_3, _g;
let file, hotMod;
try {
for (var _h = __asyncValues(fixtures_1.changingRawFuncModuleFixtures()), _j; _j = yield _h.next(), !_j.done;) {
const info = _j.value;
/**
* io event loop wait for fs.watch
* FIXME: Find out the reason...
*/
yield new Promise(setImmediate); // the first one is enough for Linux(Ubuntu 17.04) with Node.js v8
yield new Promise(setImmediate); // the second one is needed for Windows 7
if (!hotMod) {
file = info.file;
hotMod = yield hot_import_1.hotImport(file);
}
else {
t.equal(file, info.file, 'should get same module file for fixtures(change file content only)');
}
yield new Promise(resolve => setTimeout(resolve, 10));
t.equal(hotMod(), info.returnValue, 'should get expected values from the return value of raw func in module');
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_j && !_j.done && (_g = _h.return)) yield _g.call(_h);
}
finally { if (e_3) throw e_3.error; }
}
if (file) {
yield hot_import_1.hotImport(file, false);
}
}));
t.test('module that only has a default export', (t) => __awaiter(this, void 0, void 0, function* () {
const EXPECTED_RETURN_VALUE = 42;
const DEFAULT_EXPORT_ONLY_MODULE_FILE = '../tests/fixtures/default-export-module';
const mod = yield hot_import_1.hotImport(DEFAULT_EXPORT_ONLY_MODULE_FILE);
t.equal(mod(), EXPECTED_RETURN_VALUE, 'should get the default export function return value right');
yield hot_import_1.hotImport(DEFAULT_EXPORT_ONLY_MODULE_FILE, false).catch(() => t.fail('rejected'));
}));
}));
test('importFile()', (t) => __awaiter(this, void 0, void 0, function* () {
t.test('const value', (t) => __awaiter(this, void 0, void 0, function* () {
var e_4, _k;
try {
for (var _l = __asyncValues(fixtures_1.changingVariableModuleFixtures()), _m; _m = yield _l.next(), !_m.done;) {
const info = _m.value;
const hotMod = yield hot_import_1.importFile(info.file);
t.equal(hotMod.answer, info.returnValue, 'should import file right with returned value ' + info.returnValue);
break; // only test once for importFile
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (_m && !_m.done && (_k = _l.return)) yield _k.call(_l);
}
finally { if (e_4) throw e_4.error; }
}
}));
t.test('class', (t) => __awaiter(this, void 0, void 0, function* () {
var e_5, _o;
try {
for (var _p = __asyncValues(fixtures_1.changingClassModuleFixtures()), _q; _q = yield _p.next(), !_q.done;) {
const info = _q.value;
const Module = yield hot_import_1.importFile(info.file);
const result = new Module(EXPECTED_TEXT);
t.equal(result.text, EXPECTED_TEXT, 'should instanciated class with constructor argument');
t.equal(result.id, info.returnValue, 'should import module class with right id');
break; // only test once for importFile
}
}
catch (e_5_1) { e_5 = { error: e_5_1 }; }
finally {
try {
if (_q && !_q.done && (_o = _p.return)) yield _o.call(_p);
}
finally { if (e_5) throw e_5.error; }
}
}));
}));
test('refreshImport()', (t) => __awaiter(this, void 0, void 0, function* () {
var e_6, _r;
let cls;
try {
for (var _s = __asyncValues(fixtures_1.changingClassModuleFixtures()), _t; _t = yield _s.next(), !_t.done;) {
const info = _t.value;
if (!cls) {
cls = yield hot_import_1.importFile(info.file);
hot_import_1.moduleStore[info.file] = cls;
hot_import_1.proxyStore[info.file] = hot_import_1.initProxyModule(info.file);
}
else {
yield hot_import_1.refreshImport(info.file);
t.notEqual(hot_import_1.moduleStore[info.file], cls, 'should be refreshed to new value');
}
}
}
catch (e_6_1) { e_6 = { error: e_6_1 }; }
finally {
try {
if (_t && !_t.done && (_r = _s.return)) yield _r.call(_s);
}
finally { if (e_6) throw e_6.error; }
}
}));
test('purgeRequireCache()', (t) => __awaiter(this, void 0, void 0, function* () {
const KEY = 'test-key';
const VAL = 'test-val';
for (const info of fixtures_1.emptyObjectModuleFixture()) {
const m0 = yield hot_import_1.importFile(info.file);
t.deepEqual(m0, info.returnValue, 'should get returnValue from module');
m0[KEY] = VAL;
const m1 = yield hot_import_1.importFile(info.file);
t.equal(m1[KEY], VAL, 'should keep value in require cache');
hot_import_1.purgeRequireCache(info.file);
const m2 = yield hot_import_1.importFile(info.file);
t.deepEqual(m2, info.returnValue, 'should get returnValue again after purge');
t.equal(m2[KEY], undefined, 'should no KEY exists any more');
}
}));
test('cloneProperties()', (t) => __awaiter(this, void 0, void 0, function* () {
const SRC = { text: EXPECTED_TEXT };
/* eslint padded-blocks: off */
const SRC_CLASS = class {
constructor(text) {
this.text = text;
}
};
t.test('object', (t) => __awaiter(this, void 0, void 0, function* () {
const dst = {};
hot_import_1.cloneProperties(dst, SRC);
t.equal(dst.text, EXPECTED_TEXT, 'should clone the text property');
}));
t.test('class', (t) => __awaiter(this, void 0, void 0, function* () {
const dst = {};
hot_import_1.cloneProperties(dst, SRC_CLASS);
t.equal(SRC_CLASS.prototype, dst.prototype, 'should clone the prototype for class');
}));
}));
test('VERSION', (t) => __awaiter(this, void 0, void 0, function* () {
t.ok(hot_import_1.VERSION.match(/^\d+\.\d+\.\d+$/), 'should get semver version');
t.equal(hot_import_1.VERSION, '0.0.0', 'should be 0.0.0 in source code');
}));
//# sourceMappingURL=hot-import.spec.js.map