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 requirefunkcji, 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);
}
});
});
});
});
});
});
definefunkcję. Jest jednak kilka różnych opcji. Opublikuję odpowiedź w nadziei, że będzie pomocna.