This last sprint cycle for my team was probably the most productive sprint in terms of producing code but we ran into a lot of issues when it came to dealing with Promise objects. As I have mentioned in my previous blog posts, when making calls to to a pouchDB instance (i.e. db.put(), db.remove(), db.get(), etc…) those calls return what is known as a Promise object. At Mozilla.org I found a good definition of Promise objects. They describe them as “a proxy for a value not necessarily known when the promise is created.” Hence, using promises allows developers to write asynchronous code fairly easily. The reason I say this is because asynchronous functions may have multiple expected outcomes/return values without knowing the order in which they will be generated. Before promises, asynchronous functions were handled using callbacks which would either deal with any errors the function might generate or execute the function as expected. You can refer to this link for a more in-depth explanation on the benefits of using Promise Objects instead of callbacks for asynchronous code.
Below is a diagram depicting how promises operate:
As you can see above, promise objects may be chained together using .then() which provides the capability to easily write functions with multiple asynchronous actions expected.
Initially, my team and I didn’t have a great grasp on the concept of Promise Objects and were expecting our code to return explicit values. Here’s an example of our addDoc() function in which we expected to get a boolean value to be returned:
The problem with this is that our function was actually returning a promise object which that returned true when the necessary conditions were satisfied. After doing some research and working with the team who were writing the offline data capture service we realized our function was actually returning a Promise Object. Furthermore, we figured out that we could expand the functionality of our addDoc() method by utilizing the chaining of promises. With this knowledge, we re-wrote our addDoc() method so that it expected a Promise Object to be returned and could update an existing record if it’s ID was found in the PouchDB instance. Here is what the addDoc() function looked like after making those changes:
Testing functions that return promise objects also proved to be quite difficult. Here is a screen shot, taken from my gitHub page, depicting the test we wrote for the addDoc() method:
As you can see, highlighted in red, we initially had our function call inside the expect() part of our test. Then, we changed our test (shown highlighted in green) by moving the expect() inside of the .then() call after the addDoc() function. Subsequently, our test successfully passed and we thought we were on the right track. However, some of our functions had long chains of promises with multiple asynchronous actions expected. Thus, some of our tests were producing output that was hard to explain because we were still expecting our code to execute in a synchronous manner like if-else statements. In other words, anticipating that the result of each .then() call would be returned in a synchronous fashion, which was not the case.
In hindsight, a better method of testing our functions may have been just simply testing whether the correct pouchDB function was getting called the right time. We were trying to test whether the promises returned in our functions were, themselves, returning correct values. It may have been better practice to just log the responses of promise objects called in our code rather than testing the expected return values since asynchronous code may return things in an unforeseen order.
From the blog CS@Worcester – Caleb's Computer Science Blog by calebscomputerscienceblog and used with permission of the author. All other rights reserved by the author.