{"action":"created","issue":{"url":"https://api.github.com/repos/facebook/jest/issues/6671","repository_url":"https://api.github.com/repos/facebook/jest","labels_url":"https://api.github.com/repos/facebook/jest/issues/6671/labels{/name}","comments_url":"https://api.github.com/repos/facebook/jest/issues/6671/comments","events_url":"https://api.github.com/repos/facebook/jest/issues/6671/events","html_url":"https://github.com/facebook/jest/issues/6671","id":339973882,"node_id":"MDU6SXNzdWUzMzk5NzM4ODI=","number":6671,"title":"Nesting Promise.then() blocks causes module mock to reset","user":{"login":"RyanAtViceSoftware","id":10080111,"node_id":"MDQ6VXNlcjEwMDgwMTEx","avatar_url":"https://avatars2.githubusercontent.com/u/10080111?v=4","gravatar_id":"","url":"https://api.github.com/users/RyanAtViceSoftware","html_url":"https://github.com/RyanAtViceSoftware","followers_url":"https://api.github.com/users/RyanAtViceSoftware/followers","following_url":"https://api.github.com/users/RyanAtViceSoftware/following{/other_user}","gists_url":"https://api.github.com/users/RyanAtViceSoftware/gists{/gist_id}","starred_url":"https://api.github.com/users/RyanAtViceSoftware/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RyanAtViceSoftware/subscriptions","organizations_url":"https://api.github.com/users/RyanAtViceSoftware/orgs","repos_url":"https://api.github.com/users/RyanAtViceSoftware/repos","events_url":"https://api.github.com/users/RyanAtViceSoftware/events{/privacy}","received_events_url":"https://api.github.com/users/RyanAtViceSoftware/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":4,"created_at":"2018-07-10T19:18:49Z","updated_at":"2018-07-11T13:16:19Z","closed_at":null,"author_association":"NONE","body":"<!-- Love Jest? Please consider supporting our collective: 👉  https://opencollective.com/jest/donate -->\r\n\r\n## 🐛 Bug Report\r\nNesting Promise.then() blocks causes module mock to reset\r\n\r\nThis code was causing the `cross-fetch` mock we use to reset which was causing test to fail with `Cannot read property 'then' of undefined` error. This is because we mock `fetch()` (default `cross-fetch` export) in our test to return a `Promise.resolve(someData)` to fake network request.\r\n\r\n**Broke**\r\n\r\n```jsx\r\n handleInactivate() {\r\n    const {\r\n      selectedRows,\r\n      inactivateRetailers,\r\n      getRetailers,\r\n      selectionChanged,\r\n      getRetailersIncludingInactives,\r\n      userContext: { distributorId },\r\n      filter\r\n    } = this.props;\r\n\r\n    const selectedRetailersIds = selectedRows.map(r => r.id);\r\n\r\n    inactivateRetailers({ retailersIds: selectedRetailersIds })\r\n      .then(\r\n        () =>\r\n          filter.showInactive\r\n            ? getRetailersIncludingInactives(distributorId, {\r\n                useCaching: false,\r\n                noBusySpinner: false\r\n              })\r\n            : getRetailers(distributorId, false)\r\n              .then(() => {\r\n                getRetailersIncludingInactives(   // <====== this call blows up\r\n                  distributorId, {\r\n                  useCaching: false,\r\n                  noBusySpinner: true\r\n                });\r\n              }\r\n              )\r\n      )\r\n      .then(this.refreshGrid(this.retailers.retailersGrid))\r\n      .catch(handleError);\r\n  }\r\n```\r\nHowever, if we flatten out the promises like below the mock doesn't reset and nothing blows up.\r\n\r\n**Works**\r\n```jsx\r\n  handleInactivate() {\r\n    const {\r\n      selectedRows,\r\n      inactivateRetailers,\r\n      getRetailers,\r\n      selectionChanged,\r\n      getRetailersIncludingInactives,\r\n      userContext: { distributorId },\r\n      filter\r\n    } = this.props;\r\n\r\n    const selectedRetailersIds = selectedRows.map(r => r.id);\r\n\r\n    inactivateRetailers({ retailersIds: selectedRetailersIds })\r\n      .then(\r\n        () =>\r\n          filter.showInactive\r\n            ? getRetailersIncludingInactives(distributorId, {\r\n                useCaching: false,\r\n                noBusySpinner: false\r\n              })\r\n            : getRetailers(distributorId, false)\r\n      )\r\n      .then(() => filter.showInactive\r\n        ? Promise.resolve()\r\n        : getRetailersIncludingInactives(  // <=== logically same pattern but doesn't blow up\r\n          distributorId, {\r\n            useCaching: false,\r\n            noBusySpinner: true\r\n          }\r\n        )\r\n      )\r\n      .then(this.refreshGrid(this.retailers.retailersGrid))\r\n      .catch(handleError);\r\n  }\r\n```\r\n\r\n**How do I know that the mock is resetting?**\r\nTo validate this I added some logging code\r\n\r\n```console.log('===> about to fetch', fetch, fetch.mock && fetch.mock.calls);```\r\n\r\nand the output shows the `fetch.mock.calls` getting reset to be empty after a few calls as shown below.\r\n\r\n```bash\r\n  console.log src\\modules\\http\\http.js:86\r\n    ===> about to fetch function fetch() {return mockConstructor.apply(this,arguments);} []\r\n\r\n  console.log src\\modules\\http\\http.js:86\r\n    ===> about to fetch function fetch() {return mockConstructor.apply(this,arguments);} [ [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/items',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ] ]\r\n\r\n  console.log src\\modules\\http\\http.js:86\r\n    ===> about to fetch function fetch() {return mockConstructor.apply(this,arguments);} [ [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/items',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ],\r\n      [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/groups',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ] ]\r\n\r\n  console.log src\\modules\\http\\http.js:86\r\n    ===> about to fetch function fetch() {return mockConstructor.apply(this,arguments);} [ [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/items',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ],\r\n      [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/groups',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ],\r\n      [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/retailers',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ] ]\r\n\r\n  console.log src\\modules\\http\\http.js:86\r\n    ===> about to fetch function fetch() {return mockConstructor.apply(this,arguments);} [ [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/items',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ],\r\n      [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/groups',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ],\r\n      [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/retailers',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ],\r\n      [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/retailers/plusinactives',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ] ]\r\n\r\n  console.log src\\modules\\http\\http.js:86\r\n    ===> about to fetch function fetch() {return mockConstructor.apply(this,arguments);} [ [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/items',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ],\r\n      [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/groups',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ],\r\n      [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/retailers',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ],\r\n      [ 'http://localhost:55885/api/v1/pricesource/distributors/undefined/retailers/plusinactives',\r\n        { Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          headers: [Object] } ],\r\n      [ 'http://localhost:55885/api/v1/pricesource/deactivateRetailersRequest',\r\n        { body: '{\"retailersIds\":[\"-2\"]}',\r\n          headers: [Object],\r\n          Accept: 'application/json',\r\n          'Content-Type': 'application/json',\r\n          method: 'POST' } ] ]\r\n\r\n  console.log src\\modules\\http\\http.js:86\r\n    ===> about to fetch function fetch() {return mockConstructor.apply(this,arguments);} []\r\n```\r\n\r\n## To Reproduce\r\n\r\nSteps to reproduce the behavior:\r\n\r\nI put our code that causes this above. Because it's using nested promises it seems hard to create a small sample to pre\r\n\r\n## Expected behavior\r\n\r\nExpect the mock to continue to work and not reset during test run.\r\n\r\n## Link to repl or repo (highly encouraged)\r\n\r\nPlease provide either a [repl.it demo](https://repl.it/languages/jest) or a minimal repository on GitHub.\r\n\r\nIssues without a reproduction link are likely to stall.\r\n\r\n## Run `npx envinfo --preset jest`\r\n\r\nPaste the results here:\r\n\r\n```bash\r\nC:\\code\\FinTech PriceSource\\Dev\\PriceSource\\PriceSource.UI>npx envinfo --preset jest\r\nnpx: installed 1 in 3.191s\r\nPath must be a string. Received undefined\r\nnpx: installed 1 in 2.662s\r\nC:\\Users\\ryanvice\\AppData\\Roaming\\npm-cache\\_npx\\736\\node_modules\\envinfo\\dist\\cli.js\r\n\r\n  System:\r\n    OS: Windows 10\r\n    CPU: x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz\r\n  Binaries:\r\n    npm: 5.6.0 - C:\\Program Files\\nodejs\\npm.CMD\r\n```\r\n"},"comment":{"url":"https://api.github.com/repos/facebook/jest/issues/comments/404164843","html_url":"https://github.com/facebook/jest/issues/6671#issuecomment-404164843","issue_url":"https://api.github.com/repos/facebook/jest/issues/6671","id":404164843,"node_id":"MDEyOklzc3VlQ29tbWVudDQwNDE2NDg0Mw==","user":{"login":"RyanAtViceSoftware","id":10080111,"node_id":"MDQ6VXNlcjEwMDgwMTEx","avatar_url":"https://avatars2.githubusercontent.com/u/10080111?v=4","gravatar_id":"","url":"https://api.github.com/users/RyanAtViceSoftware","html_url":"https://github.com/RyanAtViceSoftware","followers_url":"https://api.github.com/users/RyanAtViceSoftware/followers","following_url":"https://api.github.com/users/RyanAtViceSoftware/following{/other_user}","gists_url":"https://api.github.com/users/RyanAtViceSoftware/gists{/gist_id}","starred_url":"https://api.github.com/users/RyanAtViceSoftware/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/RyanAtViceSoftware/subscriptions","organizations_url":"https://api.github.com/users/RyanAtViceSoftware/orgs","repos_url":"https://api.github.com/users/RyanAtViceSoftware/repos","events_url":"https://api.github.com/users/RyanAtViceSoftware/events{/privacy}","received_events_url":"https://api.github.com/users/RyanAtViceSoftware/received_events","type":"User","site_admin":false},"created_at":"2018-07-11T13:16:18Z","updated_at":"2018-07-11T13:16:18Z","author_association":"NONE","body":"That said in this case though the number of ticks would be the same for both block though right? All I did was move the nested `.then` to a changed `.then`. Maybe I'm lacking some understanding on some nuances here."}}
{"actor":{"display_login":"RyanAtViceSoftware"}}