Issuing a synchronous HTTP GET request or invoking shell script in JavaScript from iOS UIAutomation

后端 未结 5 943
日久生厌
日久生厌 2021-02-09 08:05

I am trying to use Apple\'s UIAutomation to write unit tests for an iOS Application that has a server-side component. In order to setup the test server in various states (as wel

5条回答
  •  轻奢々
    轻奢々 (楼主)
    2021-02-09 08:42

    Folks,

    I was able to work around this by sending HTTP requests to the iOS client to process and return the results in a UIAlertView. Note that all iOS code modifications are wrapped in #if DEBUG conditional compilation directives.

    First, setup your client to send out notifications in the event of a device shake. Read this post for more information.

    Next, in your iOS main app delegate add this code:

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(deviceShakenShowDebug:)
                                                 name:@"DeviceShaken" 
                                               object:nil];
    

    Then add a method that looks something like this:

    - (void) deviceShakenShowDebug:(id)sender
    {
        if (!self.textFieldEnterDebugArgs)
        {
            self.textFieldEnterDebugArgs = [[[UITextField alloc] initWithFrame:CGRectMake(0, 0, 260.0, 25.0)] autorelease];
            self.textFieldEnterDebugArgs.accessibilityLabel = @"AlertDebugArgsField";
            self.textFieldEnterDebugArgs.isAccessibilityElement = YES;
            [self.textFieldEnterDebugArgs setBackgroundColor:[UIColor whiteColor]];
            [self.tabBarController.selectedViewController.view addSubview:self.textFieldEnterDebugArgs];
            [self.tabBarController.selectedViewController.view bringSubviewToFront:self.textFieldEnterDebugArgs];
        }
        else
        {
            if ([self.textFieldEnterDebugArgs.text length] > 0)
            {
                if ([self.textFieldEnterDebugArgs.text hasPrefix:@"http://"])
                {
                    [self doDebugHttpRequest:self.textFieldEnterDebugArgs.text];    
                }
            }
        }
    }
    
    - (void)requestDidFinishLoad:(TTURLRequest*)request
    {
            NSString *response = [[[NSString alloc] initWithData:((TTURLDataResponse*)request.response).data 
                                                        encoding:NSUTF8StringEncoding] autorelease];
    
            UIAlertView *resultAlert = 
                [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Request Loaded",@"")
                                           message:response
                                          delegate:nil
                                 cancelButtonTitle:NSLocalizedString(@"OK",@"")
                                 otherButtonTitles:nil] autorelease];
            resultAlert.accessibilityLabel = @"AlertDebugResult";
            [resultAlert show];
    }
    

    This code will add a UITextField to the very top view controller after a shake, slapped right above any navigation bar or other UI element. UIAutomation, or you the user, can manually enter a URL into this UITextField. When you shake the device again, if the text begins with "http" it will issue an HTTP request in code (exercise for the reader to implement doDebugHttpRequest).

    Then, in my UIAutomation JavaScript file, I have defined the following two functions:

    function httpGet(url, delayInSec) {
      if (!delayInSec) delay = 1;
      var alertDebugResultSeen = false;
      var httpResponseValue = null;
    
      UIATarget.onAlert = function onAlert(alert) {    
        httpResponseValue = alert.staticTexts().toArray()[1].name();
        alert.buttons()[0].tap();
        alertDebugResultSeen = true;
      }
    
      var target = UIATarget.localTarget();
      var application = target.frontMostApp();
      target.shake(); // bring up the input field
      application.mainWindow().textFields()["AlertDebugArgsField"].setValue(url);
      target.shake(); // send back to be processed
      target.delay(delayInSec);
      assertTrue(alertDebugResultSeen);
      return httpResponseValue;
    }
    
    function httpGetJSON(url, delayInSec) {
      var response = httpGet(url, delayInSec);
      return eval('(' + response + ')');
    }
    

    Now, in my javascript file, I can call

    httpGet('http://localhost:3000/do_something')
    

    and it will execute an HTTP request. If I want JSON data back from the server, I call

    var jsonResponse = httpGetJSON('http://localhost:3000/do_something')
    

    If I know it is going to be a long-running call, I call

    var jsonResponse = httpGetJSON('http://localhost:3000/do_something', 10 /* timeout */)
    

    I've been using this approach successfully now for several weeks.

提交回复
热议问题