2017-08-08 1 views
2

Ich habe zwei Dateien, getItemInfo.js, um API-Aufrufe und getItemInfo.test.js, die die jeweilige Jest-Testdatei ist.Warum wird das Versprechen abgelehnt() in meinem jest.mock zu einem then() statt einem catch()?

In der Testdatei verspottete ich den HTTP-Aufruf ausgelöst durch Knotenmodul request-promise. Die Frage ist auf dem zweiten Codeblock, umgeben von ********* ist. Grundsätzlich, warum ist der reject() Fehler immer noch zu einem then() Block in der zweiten Einheit Test gehen?

// getItemInfo.js 

const rp = require('request-promise'); 

const getItemInfo = (id) => { 
    const root = 'https://jsonplaceholder.typicode.com/posts/'; 
    const requestOptions = { 
     uri: `${root}/${id}`, 
     method: 'GET', 
     json: true 
    } 

    return rp(requestOptions) 
    .then((result) => { 
     return result; 
    }) 
    .catch((err) => { 
     return err; 
    }); 
}; 

module.exports = { 
    getItemInfo: getItemInfo 
}; 

Und hier ist meine Jest Einheit Testdatei.

// getItemInfo.test.js 
const ItemService = require('./getItemInfo'); 

jest.mock('request-promise',() => (options) => { 
    const id = Number.parseInt(options.uri.substring(options.uri.lastIndexOf('/') + 1)); 

    return new Promise((resolve, reject) => { 
     if (id === 12) { 
      return resolve({ 
       id: id, 
       userId: 1, 
       title: '', 
       body: '' 
      }); 
     } else { 
      return reject('something went wrong'); // <-- HERE IS THE REJECT 
     } 
    }) 
}); 

describe('getItemInfo',() => { 
    it('can pass', done => { 
     const TEST_ID = 12 
     ItemService.getItemInfo(TEST_ID).then((result) => { 
      console.log('result:',result); 
      expect(result.id).toBe(TEST_ID); 
      expect(result.userId).toBeDefined(); 
      expect(result.title).toBeDefined(); 
      expect(result.body).toBeDefined(); 
      done(); 
     }); 
    }); 

    it('can fail', (done) => { 
     const TEST_ID = 13; 
     ItemService.getItemInfo(TEST_ID) 
     .catch((err) => { 
      // ************* 
      // This "catch" block never runs 
      // even if the jest.mock above Promise.rejects 
      // Why is that??? 
      // ************* 
      console.log('catch():', err); 
      done(); 
     }) 
     .then((result) => { 
      // this block runs instead. 
      // and it returns "then: something went wrong" 
      console.log('then():', result); 
      done(); 
     }); 
    }); 
}); 

Dies ist der Ausgang des Komponententests. Der Befehl lautet einfach jest. Die letzte Zeile sollte von der catch() Anweisung ausgeführt werden, nicht die then():

PASS ./getItemInfo.test.js 
getItemInfo 
    ✓ can pass (9ms) 
    ✓ can fail (1ms) 

Test Suites: 1 passed, 1 total 
Tests:  2 passed, 2 total 
Snapshots: 0 total 
Time:  0.703s, estimated 1s 
Ran all test suites. 
----------------|----------|----------|----------|----------|----------------| 
File   | % Stmts | % Branch | % Funcs | % Lines |Uncovered Lines | 
----------------|----------|----------|----------|----------|----------------| 
All files  |  100 |  100 |  100 |  100 |    | 
getItemInfo.js |  100 |  100 |  100 |  100 |    | 
----------------|----------|----------|----------|----------|----------------| 
console.log getItemInfo.test.js:25 
    result: { id: 12, userId: 1, title: '', body: '' } 

console.log getItemInfo.test.js:48 
    then(): something went wrong 

Was mache ich falsch?

+1

Weil '.catch ((err) => { return err; });' behandelt den Fehler! Das willst du wahrscheinlich nicht tun. – Bergi

Antwort

3

Warum lehnt das Versprechen() in meinem jest.mock zu einem then() statt einem catch() ab?

Ihre .catch() Handler wird ein abgelehnt Versprechen in einer aufgelösten Versprechen Umwandlung und somit nur die äußere .then() Handler aufgerufen wird.

Wenn Sie .catch() wie folgt verwenden:

.catch((err) => { 
    return err; 
}); 

und rethrow den Fehler nicht oder zurückgeben abgelehnt Versprechen, dann wird die Ablehnung „behandelt“ und das zurückgegebene Versprechen wird aufgelöst betrachtet, nicht abgelehnt. Das ist wie mit einem Versuch/Fang. In einem catch-Handler wird die Ausnahme behandelt, es sei denn, Sie werfen sie erneut.

Sie können sehen, dass in diesem einfachen Code-Schnipsel:

new Promise((resolve, reject) => { 
 
    reject(new Error("reject 1")); 
 
}).catch(err => { 
 
    // returning a normal value here (anything other than a rejected promise) 
 
    // causes the promise chain to flip to resolved 
 
    return err; 
 
}).then(val => { 
 
    console.log("Promise is now resolved, not rejected"); 
 
}).catch(err => { 
 
    console.log("Don't get here"); 
 
});


Es gibt wirklich keinen Grund für eine dieser beiden:

.then((result) => { 
    return result; 
}) 
.catch((err) => { 
    return err; 
}); 

Sie können beide nur entfernen von ihnen. Der .then() Handler ist nur überflüssiger Code und der .catch() Handler isst die Ablehnung und wandelt sie in ein gelöstes Versprechen um.

Wenn Sie den Handler .catch() behalten möchten, aber die Ablehnung nach oben weiterleiten lassen möchten, müssen Sie sie erneut ausführen.

.catch((err) => { 
    console.log(err); 
    throw err;  // keep promise rejected so reject will propagate upwards 
}); 
2

Da Sie die Ablehnung in eine Auflösung umgewandelt haben:

.catch((err) => { 
    return err; 
}); 

Wenn Sie die Ablehnung wollen aus getItemInfo propagieren, entfernen Sie den catch Handler von getItemInfo.

Denken Sie daran, dass catch und then beide schaffen und zurück Versprechen und ihre Handler behandelt werden, um die gleiche:

  1. Wenn Sie ein Wert von ihnen das Versprechen then/catch erstellt wird aufgelöst mit, dass das Rück Wert.

  2. Wenn Sie ein thenable von ihnen zurückkehren , das Versprechen then/catch geschaffen, dass thenable nachgeführt wird (aufgelöst oder abgelehnt basierend auf, was das thenable tut).

  3. Wenn Sie Wurf in ihnen das Versprechen then/catch erstellt mit diesem Fehler zurückgewiesen.

Sie brauchen nur ein catch Handler, wenn:

  • Sie sind nicht die Kette entlang, um etwas anderes vorbei (die Sie in getItemInfo sind) oder

  • Sie müssen Transformieren Sie einen Fehler in irgendeiner Weise, indem Sie ihn entweder in eine Auflösung (Recovery) umwandeln oder in einen anderen Fehler transformieren. Um letzteres zu tun, geben Sie throw zurück oder geben ein Versprechen zurück, das abgelehnt wird.

Verwandte Themen