Skip to content

Instantly share code, notes, and snippets.

@jonah-williams
Last active October 7, 2015 01:38
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonah-williams/3085287 to your computer and use it in GitHub Desktop.
Save jonah-williams/3085287 to your computer and use it in GitHub Desktop.
Delay execution of Kiwi specs until an asynchronous process finishes.
#import <Kiwi/Kiwi.h>
#import "KWSpec+WaitFor.h"
SPEC_BEGIN(Example)
describe(@"it takes a while", ^{
__block NSDictionary *apiResponse = nil;
beforeAll(^{
__block BOOL requestCompleted = NO;
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
requestCompleted = YES;
apiResponse = JSON;
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
requestCompleted = YES;
}
];
[operation start];
[KWSpec waitWithTimeout:3.0 forCondition:^BOOL() {
return requestCompleted;
}];
});
it(@"includes the related objects in the response", ^{
[[[apiResponse objectForKey:@"children"] should] containObjects:@"foo", @"bar", @"baz", nil];
});
});
SPEC_END
#import "KWSpec.h"
@interface KWSpec (WaitFor)
+ (void) waitWithTimeout:(NSTimeInterval)timeout forCondition:(BOOL(^)())conditionalBlock;
@end
#import "KWSpec+WaitFor.h"
@implementation KWSpec (WaitFor)
+ (void) waitWithTimeout:(NSTimeInterval)timeout forCondition:(BOOL(^)())conditionalBlock {
NSDate *timeoutDate = [[NSDate alloc] initWithTimeIntervalSinceNow:timeout];
while (conditionalBlock() == NO) {
if ([timeoutDate timeIntervalSinceDate:[NSDate date]] < 0) {
return;
}
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
}
}
@end
@atljeremy
Copy link

Jonah, first of all thank you for posting this. It was a huge help.

You might want to update the example_test.m to the following so that anyone who tries to implement your example will not run into issues with failing tests....

describe(@"it takes a while", ^{
    __block NSDictionary *apiResponse = nil;
    beforeAll(^{
        __block BOOL requestCompleted = NO;    
        AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request 
            success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
                requestCompleted = YES;
                apiResponse = JSON;
            } 
            failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
                requestCompleted = YES;
            }
        ];
        [operation start];

        [KWSpec waitWithTimeout:3.0 forCondition:^BOOL() {
            return requestCompleted;
        }];
    });
    it(@"includes the related objects in the response", ^{
        [[[apiResponse objectForKey:@"children"] should] containObjects:@"foo", @"bar", @"baz", nil];
    });
});

Please note the new name of the local variable that will receive the JSON response... apiResponse. This is to avoid an issue where response = JSON; was setting the NSHTTPURLResponse *response which is a param in the success block of the AFJSONRequestOperation and ultimately leading to failing tests.

@jonah-williams
Copy link
Author

@atljeremy thanks for catching that. Sorry I gave you a poor example. I've applied your change so hopefully you've saved everyone else from similar confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment