JavaScript - mocking console in Jest / mock “was not called”












1















I'm trying to mock console.info which I know will be called when an imported function runs. The function consists entirely of a single fetch which, when not running in production, reports the request and response using console.info.



At the question Jest. How to mock console when it is used by a third-party-library?, the top-rated answer suggests overwriting global.console, so I'm using jest.spyOn to try that out:



import * as ourModule from "../src/ourModule";

test("Thing", () => {
// Tested function requires this. Including it here in case it's causing
// something quirky that readers of this question may know about
global.fetch = require("jest-fetch-mock");

const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
() => { console.error("mockInfo") }
);

ourModule.functionBeingTested("test");
expect(mockInfo).toHaveBeenCalled();
}


As expected, the output contains an instance of "mockInfo". However, then testing that with toHaveBeenCalled() fails.



expect(jest.fn()).toHaveBeenCalled()

Expected mock function to have been called, but it was not called.

40 |
41 | ourModule.functionBeingTested("test");
> 42 | expect(mockInfo).toHaveBeenCalled();
| ^
43 |

at Object.toHaveBeenCalled (__tests__/basic.test.js:42:22)

console.error __tests__/basic.test.js:38
mockInfo


I've tried moving the spyOn to before the module is loaded, as suggested in one of the comments on the answer, with no difference in result. What am I missing here?



Here's the function in question:



function functionBeingTested(value) {
const fetchData = {
something: value
};

fetch("https://example.com/api", {
method: "POST",
mode: "cors",
body: JSON.stringify(fetchData),
})
.then( response => {
if (response.ok) {
if (MODE != "production") {
console.info(fetchData);
console.info(response);
}
} else {
console.error(`${response.status}: ${response.statusText}`);
}
})
.catch( error => {
console.error(error);
});
}









share|improve this question

























  • What is the third party library function that you are calling?

    – brian-lives-outdoors
    Nov 19 '18 at 15:17











  • @brian-lives-outdoors: I'm not, that's from the other question.

    – Scott Martin
    Nov 19 '18 at 16:15











  • Can you show what ourModule.functionBeingTested does?

    – brian-lives-outdoors
    Nov 19 '18 at 16:19











  • It fetches a URL - I've added that to the question.

    – Scott Martin
    Nov 19 '18 at 16:39
















1















I'm trying to mock console.info which I know will be called when an imported function runs. The function consists entirely of a single fetch which, when not running in production, reports the request and response using console.info.



At the question Jest. How to mock console when it is used by a third-party-library?, the top-rated answer suggests overwriting global.console, so I'm using jest.spyOn to try that out:



import * as ourModule from "../src/ourModule";

test("Thing", () => {
// Tested function requires this. Including it here in case it's causing
// something quirky that readers of this question may know about
global.fetch = require("jest-fetch-mock");

const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
() => { console.error("mockInfo") }
);

ourModule.functionBeingTested("test");
expect(mockInfo).toHaveBeenCalled();
}


As expected, the output contains an instance of "mockInfo". However, then testing that with toHaveBeenCalled() fails.



expect(jest.fn()).toHaveBeenCalled()

Expected mock function to have been called, but it was not called.

40 |
41 | ourModule.functionBeingTested("test");
> 42 | expect(mockInfo).toHaveBeenCalled();
| ^
43 |

at Object.toHaveBeenCalled (__tests__/basic.test.js:42:22)

console.error __tests__/basic.test.js:38
mockInfo


I've tried moving the spyOn to before the module is loaded, as suggested in one of the comments on the answer, with no difference in result. What am I missing here?



Here's the function in question:



function functionBeingTested(value) {
const fetchData = {
something: value
};

fetch("https://example.com/api", {
method: "POST",
mode: "cors",
body: JSON.stringify(fetchData),
})
.then( response => {
if (response.ok) {
if (MODE != "production") {
console.info(fetchData);
console.info(response);
}
} else {
console.error(`${response.status}: ${response.statusText}`);
}
})
.catch( error => {
console.error(error);
});
}









share|improve this question

























  • What is the third party library function that you are calling?

    – brian-lives-outdoors
    Nov 19 '18 at 15:17











  • @brian-lives-outdoors: I'm not, that's from the other question.

    – Scott Martin
    Nov 19 '18 at 16:15











  • Can you show what ourModule.functionBeingTested does?

    – brian-lives-outdoors
    Nov 19 '18 at 16:19











  • It fetches a URL - I've added that to the question.

    – Scott Martin
    Nov 19 '18 at 16:39














1












1








1








I'm trying to mock console.info which I know will be called when an imported function runs. The function consists entirely of a single fetch which, when not running in production, reports the request and response using console.info.



At the question Jest. How to mock console when it is used by a third-party-library?, the top-rated answer suggests overwriting global.console, so I'm using jest.spyOn to try that out:



import * as ourModule from "../src/ourModule";

test("Thing", () => {
// Tested function requires this. Including it here in case it's causing
// something quirky that readers of this question may know about
global.fetch = require("jest-fetch-mock");

const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
() => { console.error("mockInfo") }
);

ourModule.functionBeingTested("test");
expect(mockInfo).toHaveBeenCalled();
}


As expected, the output contains an instance of "mockInfo". However, then testing that with toHaveBeenCalled() fails.



expect(jest.fn()).toHaveBeenCalled()

Expected mock function to have been called, but it was not called.

40 |
41 | ourModule.functionBeingTested("test");
> 42 | expect(mockInfo).toHaveBeenCalled();
| ^
43 |

at Object.toHaveBeenCalled (__tests__/basic.test.js:42:22)

console.error __tests__/basic.test.js:38
mockInfo


I've tried moving the spyOn to before the module is loaded, as suggested in one of the comments on the answer, with no difference in result. What am I missing here?



Here's the function in question:



function functionBeingTested(value) {
const fetchData = {
something: value
};

fetch("https://example.com/api", {
method: "POST",
mode: "cors",
body: JSON.stringify(fetchData),
})
.then( response => {
if (response.ok) {
if (MODE != "production") {
console.info(fetchData);
console.info(response);
}
} else {
console.error(`${response.status}: ${response.statusText}`);
}
})
.catch( error => {
console.error(error);
});
}









share|improve this question
















I'm trying to mock console.info which I know will be called when an imported function runs. The function consists entirely of a single fetch which, when not running in production, reports the request and response using console.info.



At the question Jest. How to mock console when it is used by a third-party-library?, the top-rated answer suggests overwriting global.console, so I'm using jest.spyOn to try that out:



import * as ourModule from "../src/ourModule";

test("Thing", () => {
// Tested function requires this. Including it here in case it's causing
// something quirky that readers of this question may know about
global.fetch = require("jest-fetch-mock");

const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
() => { console.error("mockInfo") }
);

ourModule.functionBeingTested("test");
expect(mockInfo).toHaveBeenCalled();
}


As expected, the output contains an instance of "mockInfo". However, then testing that with toHaveBeenCalled() fails.



expect(jest.fn()).toHaveBeenCalled()

Expected mock function to have been called, but it was not called.

40 |
41 | ourModule.functionBeingTested("test");
> 42 | expect(mockInfo).toHaveBeenCalled();
| ^
43 |

at Object.toHaveBeenCalled (__tests__/basic.test.js:42:22)

console.error __tests__/basic.test.js:38
mockInfo


I've tried moving the spyOn to before the module is loaded, as suggested in one of the comments on the answer, with no difference in result. What am I missing here?



Here's the function in question:



function functionBeingTested(value) {
const fetchData = {
something: value
};

fetch("https://example.com/api", {
method: "POST",
mode: "cors",
body: JSON.stringify(fetchData),
})
.then( response => {
if (response.ok) {
if (MODE != "production") {
console.info(fetchData);
console.info(response);
}
} else {
console.error(`${response.status}: ${response.statusText}`);
}
})
.catch( error => {
console.error(error);
});
}






javascript unit-testing asynchronous mocking jestjs






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 19 '18 at 17:19







Scott Martin

















asked Nov 19 '18 at 14:01









Scott MartinScott Martin

151114




151114













  • What is the third party library function that you are calling?

    – brian-lives-outdoors
    Nov 19 '18 at 15:17











  • @brian-lives-outdoors: I'm not, that's from the other question.

    – Scott Martin
    Nov 19 '18 at 16:15











  • Can you show what ourModule.functionBeingTested does?

    – brian-lives-outdoors
    Nov 19 '18 at 16:19











  • It fetches a URL - I've added that to the question.

    – Scott Martin
    Nov 19 '18 at 16:39



















  • What is the third party library function that you are calling?

    – brian-lives-outdoors
    Nov 19 '18 at 15:17











  • @brian-lives-outdoors: I'm not, that's from the other question.

    – Scott Martin
    Nov 19 '18 at 16:15











  • Can you show what ourModule.functionBeingTested does?

    – brian-lives-outdoors
    Nov 19 '18 at 16:19











  • It fetches a URL - I've added that to the question.

    – Scott Martin
    Nov 19 '18 at 16:39

















What is the third party library function that you are calling?

– brian-lives-outdoors
Nov 19 '18 at 15:17





What is the third party library function that you are calling?

– brian-lives-outdoors
Nov 19 '18 at 15:17













@brian-lives-outdoors: I'm not, that's from the other question.

– Scott Martin
Nov 19 '18 at 16:15





@brian-lives-outdoors: I'm not, that's from the other question.

– Scott Martin
Nov 19 '18 at 16:15













Can you show what ourModule.functionBeingTested does?

– brian-lives-outdoors
Nov 19 '18 at 16:19





Can you show what ourModule.functionBeingTested does?

– brian-lives-outdoors
Nov 19 '18 at 16:19













It fetches a URL - I've added that to the question.

– Scott Martin
Nov 19 '18 at 16:39





It fetches a URL - I've added that to the question.

– Scott Martin
Nov 19 '18 at 16:39












1 Answer
1






active

oldest

votes


















1
















Issue



console.info is called in a Promise callback which hasn't executed by the time ourModule.functionBeingTested returns and the expect runs.



Solution



Make sure the Promise callback that calls console.info has run before running the expect.



The easiest way to do that is to return the Promise from ourModule.functionBeingTested:



function functionBeingTested(value) {
const fetchData = {
something: value
};

return fetch("https://example.com/api", { // return the Promise
method: "POST",
mode: "cors",
body: JSON.stringify(fetchData),
})
.then(response => {
if (response.ok) {
if (MODE != "production") {
console.info(fetchData);
console.info(response);
}
} else {
console.error(`${response.status}: ${response.statusText}`);
}
})
.catch(error => {
console.error(error);
});
}


...and wait for it to resolve before asserting:



test("Thing", async () => {  // use an async test function...
// Tested function requires this. Including it here in case it's causing
// something quirky that readers of this question may know about
global.fetch = require("jest-fetch-mock");

const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
() => { console.error("mockInfo") }
);

await ourModule.functionBeingTested("test"); // ...and wait for the Promise to resolve
expect(mockInfo).toHaveBeenCalled(); // SUCCESS
});





share|improve this answer
























  • Of course - now that you point it out it's obvious. I'm pretty new to async code so it didn't occur to me. Thanks a bunch.

    – Scott Martin
    Nov 19 '18 at 17:19






  • 1





    @ScottMartin no problem, glad it helped

    – brian-lives-outdoors
    Nov 19 '18 at 17:26











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53376293%2fjavascript-mocking-console-in-jest-mock-was-not-called%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1
















Issue



console.info is called in a Promise callback which hasn't executed by the time ourModule.functionBeingTested returns and the expect runs.



Solution



Make sure the Promise callback that calls console.info has run before running the expect.



The easiest way to do that is to return the Promise from ourModule.functionBeingTested:



function functionBeingTested(value) {
const fetchData = {
something: value
};

return fetch("https://example.com/api", { // return the Promise
method: "POST",
mode: "cors",
body: JSON.stringify(fetchData),
})
.then(response => {
if (response.ok) {
if (MODE != "production") {
console.info(fetchData);
console.info(response);
}
} else {
console.error(`${response.status}: ${response.statusText}`);
}
})
.catch(error => {
console.error(error);
});
}


...and wait for it to resolve before asserting:



test("Thing", async () => {  // use an async test function...
// Tested function requires this. Including it here in case it's causing
// something quirky that readers of this question may know about
global.fetch = require("jest-fetch-mock");

const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
() => { console.error("mockInfo") }
);

await ourModule.functionBeingTested("test"); // ...and wait for the Promise to resolve
expect(mockInfo).toHaveBeenCalled(); // SUCCESS
});





share|improve this answer
























  • Of course - now that you point it out it's obvious. I'm pretty new to async code so it didn't occur to me. Thanks a bunch.

    – Scott Martin
    Nov 19 '18 at 17:19






  • 1





    @ScottMartin no problem, glad it helped

    – brian-lives-outdoors
    Nov 19 '18 at 17:26
















1
















Issue



console.info is called in a Promise callback which hasn't executed by the time ourModule.functionBeingTested returns and the expect runs.



Solution



Make sure the Promise callback that calls console.info has run before running the expect.



The easiest way to do that is to return the Promise from ourModule.functionBeingTested:



function functionBeingTested(value) {
const fetchData = {
something: value
};

return fetch("https://example.com/api", { // return the Promise
method: "POST",
mode: "cors",
body: JSON.stringify(fetchData),
})
.then(response => {
if (response.ok) {
if (MODE != "production") {
console.info(fetchData);
console.info(response);
}
} else {
console.error(`${response.status}: ${response.statusText}`);
}
})
.catch(error => {
console.error(error);
});
}


...and wait for it to resolve before asserting:



test("Thing", async () => {  // use an async test function...
// Tested function requires this. Including it here in case it's causing
// something quirky that readers of this question may know about
global.fetch = require("jest-fetch-mock");

const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
() => { console.error("mockInfo") }
);

await ourModule.functionBeingTested("test"); // ...and wait for the Promise to resolve
expect(mockInfo).toHaveBeenCalled(); // SUCCESS
});





share|improve this answer
























  • Of course - now that you point it out it's obvious. I'm pretty new to async code so it didn't occur to me. Thanks a bunch.

    – Scott Martin
    Nov 19 '18 at 17:19






  • 1





    @ScottMartin no problem, glad it helped

    – brian-lives-outdoors
    Nov 19 '18 at 17:26














1












1








1









Issue



console.info is called in a Promise callback which hasn't executed by the time ourModule.functionBeingTested returns and the expect runs.



Solution



Make sure the Promise callback that calls console.info has run before running the expect.



The easiest way to do that is to return the Promise from ourModule.functionBeingTested:



function functionBeingTested(value) {
const fetchData = {
something: value
};

return fetch("https://example.com/api", { // return the Promise
method: "POST",
mode: "cors",
body: JSON.stringify(fetchData),
})
.then(response => {
if (response.ok) {
if (MODE != "production") {
console.info(fetchData);
console.info(response);
}
} else {
console.error(`${response.status}: ${response.statusText}`);
}
})
.catch(error => {
console.error(error);
});
}


...and wait for it to resolve before asserting:



test("Thing", async () => {  // use an async test function...
// Tested function requires this. Including it here in case it's causing
// something quirky that readers of this question may know about
global.fetch = require("jest-fetch-mock");

const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
() => { console.error("mockInfo") }
);

await ourModule.functionBeingTested("test"); // ...and wait for the Promise to resolve
expect(mockInfo).toHaveBeenCalled(); // SUCCESS
});





share|improve this answer















Issue



console.info is called in a Promise callback which hasn't executed by the time ourModule.functionBeingTested returns and the expect runs.



Solution



Make sure the Promise callback that calls console.info has run before running the expect.



The easiest way to do that is to return the Promise from ourModule.functionBeingTested:



function functionBeingTested(value) {
const fetchData = {
something: value
};

return fetch("https://example.com/api", { // return the Promise
method: "POST",
mode: "cors",
body: JSON.stringify(fetchData),
})
.then(response => {
if (response.ok) {
if (MODE != "production") {
console.info(fetchData);
console.info(response);
}
} else {
console.error(`${response.status}: ${response.statusText}`);
}
})
.catch(error => {
console.error(error);
});
}


...and wait for it to resolve before asserting:



test("Thing", async () => {  // use an async test function...
// Tested function requires this. Including it here in case it's causing
// something quirky that readers of this question may know about
global.fetch = require("jest-fetch-mock");

const mockInfo = jest.spyOn(global.console, "info").mockImplementation(
() => { console.error("mockInfo") }
);

await ourModule.functionBeingTested("test"); // ...and wait for the Promise to resolve
expect(mockInfo).toHaveBeenCalled(); // SUCCESS
});






share|improve this answer












share|improve this answer



share|improve this answer










answered Nov 19 '18 at 17:07









brian-lives-outdoorsbrian-lives-outdoors

5,245322




5,245322













  • Of course - now that you point it out it's obvious. I'm pretty new to async code so it didn't occur to me. Thanks a bunch.

    – Scott Martin
    Nov 19 '18 at 17:19






  • 1





    @ScottMartin no problem, glad it helped

    – brian-lives-outdoors
    Nov 19 '18 at 17:26



















  • Of course - now that you point it out it's obvious. I'm pretty new to async code so it didn't occur to me. Thanks a bunch.

    – Scott Martin
    Nov 19 '18 at 17:19






  • 1





    @ScottMartin no problem, glad it helped

    – brian-lives-outdoors
    Nov 19 '18 at 17:26

















Of course - now that you point it out it's obvious. I'm pretty new to async code so it didn't occur to me. Thanks a bunch.

– Scott Martin
Nov 19 '18 at 17:19





Of course - now that you point it out it's obvious. I'm pretty new to async code so it didn't occur to me. Thanks a bunch.

– Scott Martin
Nov 19 '18 at 17:19




1




1





@ScottMartin no problem, glad it helped

– brian-lives-outdoors
Nov 19 '18 at 17:26





@ScottMartin no problem, glad it helped

– brian-lives-outdoors
Nov 19 '18 at 17:26


















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53376293%2fjavascript-mocking-console-in-jest-mock-was-not-called%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

ComboBox Display Member on multiple fields

Is it possible to collect Nectar points via Trainline?