angularjs - Unit testing a recursive method that calls a promise-returning function -
below simplified version of code trying test: simple queue periodically emptied. each number in queue, http post made send (in example fictional) api address. if post successful, number shifted off queue , next number considered.
class queue { queue: array<number>; processingqueue: boolean; constructor(public $http: angular.ihttpservice) { this.queue = new array<number>(); this.processingqueue = false; } startqueueprocessor() { this.processingqueue = false; setinterval(() => { if (!this.processingqueue) this.processqueue(); }, 1000); } postnumber(number: number): angular.ihttppromise<{}> { return this.$http.post('http://mydummyurl.com/givemeanumber', number); } processqueue(): void { this.processingqueue = true; // processing queue, make sure setinterval not trigger processing run if (this.queue.length !== 0) { // there numbers deal with? const item = this.queue[0]; // first number in queue this.postnumber(item) // post (returns promise) .then( () => { // if successful... this.queue.shift(); // we've dealt item, remove queue this.processqueue(); // check queue again (recurses until items have been dealt with) }, () => { // if unsuccessful... this.processingqueue = false; // went wrong, stop } ); } else { this.processingqueue = false; // queue empty, stop processing } } enqueue(number: number): void { // add number queue this.queue.push(number); } }
the test wish create check that, after having 3 items added queue, single call processqueue()
empty it.
something (mocked in jasmine):
describe('queueing', () => { var queueservice; beforeeach(inject((_$httpbackend_, $injector) => { httpbackend = _$httpbackend_; httpbackend.whenpost().respond(200); queueservice = $injector.get('queue'); })); it('should clear queue when processqueue() called once', () => { queueservice.enqueue(1); queueservice.enqueue(2); queueservice.enqueue(3); expect(queueservice.queue.length).tobe(3); queueservice.processqueue(); // somehow wait processqueue() complete expect(queueservice.queue.length).tobe(0); }); });
my issue second expect()
fails message expected 3 0
. assume due promises being returned postnumber()
not being waited for, hence queue not empty time second expect()
called.
how wait processqueue()
complete before attempting assert queue has been emptied?
you should modify processqueue return promise. easiest way marking method async
keyword , using await
later on:
async processqueue(): promise<void> { this.processingqueue = true; // processing queue, make sure setinterval not trigger processing run if (this.queue.length !== 0) { // there numbers deal with? const item = this.queue[0]; // first number in queue try { await this.postnumber(item); // post (returns promise) // if successful... this.queue.shift(); // we've dealt item, remove queue this.processqueue(); // check queue again (recurses until items have been dealt with) } catch { this.processingqueue = false; // went wrong, stop } } else { this.processingqueue = false; // queue empty, stop processing } }
and in test:
it('should clear queue when processqueue() called once', async (done) => { queueservice.enqueue(1); queueservice.enqueue(2); queueservice.enqueue(3); expect(queueservice.queue.length).tobe(3); await queueservice.processqueue(); // somehow wait processqueue() complete expect(queueservice.queue.length).tobe(0); done(); });
hope helps.
Comments
Post a Comment