Ta odpowiedź jest oparta na odpowiedzi Andreasa Köberle .
Wdrożenie i zrozumienie jego rozwiązania nie było dla mnie łatwe, więc wyjaśnię je bardziej szczegółowo, jak to działa, oraz kilka pułapek, których należy unikać, mając nadzieję, że pomoże to przyszłym odwiedzającym.
A więc przede wszystkim konfiguracja:
używam Karmy jako narzędzia do uruchamiania testów i MochaJ jako platformy testowej.
Używanie czegoś takiego jak Squire nie działało dla mnie, z jakiegoś powodu, kiedy go używałem, framework testowy wyrzucał błędy:
TypeError: Nie można odczytać wywołania właściwości o wartości undefined
RequireJs ma możliwość mapowania identyfikatorów modułów na inne identyfikatory modułów. Pozwala również na stworzenie require
funkcji, która używa innej konfiguracji niż globalna require
.
Te cechy są kluczowe, aby to rozwiązanie działało.
Oto moja wersja kodu próbnego, w tym (dużo) komentarzy (mam nadzieję, że jest to zrozumiałe). Owinąłem go wewnątrz modułu, aby testy mogły go łatwo wymagać.
define([], function () {
var count = 0;
var requireJsMock= Object.create(null);
requireJsMock.createMockRequire = function (mocks) {
count++;
var map = {};
for (property in mocks) {
if (mocks.hasOwnProperty(property)) {
var moduleId = property;
var module = mocks[property];
var stubId = 'stub' + moduleId + count;
map[moduleId] = stubId;
define(stubId, function () {
return module;
});
}
}
var defaultContext = requirejs.s.contexts._.config;
var requireMockContext = { baseUrl: defaultContext.baseUrl };
requireMockContext.context = "context_" + count;
requireMockContext.map = {
"*": map
};
return require.config(requireMockContext);
};
return requireJsMock;
});
Największa pułapka natknąłem, który kosztował mnie dosłownie godzinami, było stworzenie config RequireJs. Próbowałem (głęboko) go skopiować i zastąpić tylko niezbędne właściwości (takie jak kontekst lub mapa). To nie działa! Skopiuj tylko baseUrl
, to działa dobrze.
Stosowanie
Aby z niego skorzystać, wymagaj go w swoim teście, utwórz makiety, a następnie przekaż go createMockRequire
. Na przykład:
var ModuleMock = function () {
this.method = function () {
methodCalled += 1;
};
};
var mocks = {
"ModuleIdOrPath": ModuleMock
}
var requireMocks = mocker.createMockRequire(mocks);
A tutaj przykład pełnego pliku testowego :
define(["chai", "requireJsMock"], function (chai, requireJsMock) {
var expect = chai.expect;
describe("Module", function () {
describe("Method", function () {
it("should work", function () {
return new Promise(function (resolve, reject) {
var handler = { handle: function () { } };
var called = 0;
var moduleBMock = function () {
this.method = function () {
methodCalled += 1;
};
};
var mocks = {
"ModuleBIdOrPath": moduleBMock
}
var requireMocks = requireJsMock.createMockRequire(mocks);
requireMocks(["js/ModuleA"], function (moduleA) {
try {
moduleA.method();
expect(called).to.equal(1);
resolve();
} catch (e) {
reject(e);
}
});
});
});
});
});
});
define
funkcję. Jest jednak kilka różnych opcji. Opublikuję odpowiedź w nadziei, że będzie pomocna.