Location: PHPKode > projects > OpenPNE > OpenPNE-3.1.2/plugins/sfWebBrowserPlugin/test/unit/sfWebBrowserTest.php
<?php

include(dirname(__FILE__).'/../../../../test/bootstrap/unit.php');
require_once(dirname(__FILE__).'/../../lib/sfWebBrowser.class.php');
require_once(dirname(__FILE__).'/../../lib/sfFopenAdapter.class.php');
require_once(dirname(__FILE__).'/../../lib/sfCurlAdapter.class.php');
require_once(dirname(__FILE__).'/../../lib/sfSocketsAdapter.class.php');
require_once($sf_symfony_lib_dir.'/exception/sfException.class.php');
require_once(dirname(__FILE__).'/../../lib/sfWebBrowserInvalidResponseException.php');
require_once($sf_symfony_lib_dir.'/config/sfConfig.class.php');
require_once($sf_symfony_lib_dir.'/util/sfDomCssSelector.class.php');
require_once($sf_symfony_lib_dir.'/util/sfToolkit.class.php');

// Configuration
// -- this script is needed for some tests. It is located in plugin's test/unit/utils folder
$dump_headers_url = 'http://localhost/dumpheaders.php';

// tests
$nb_test_orig = 73;
$adapter_list = array('sfCurlAdapter', 'sfFopenAdapter', 'sfSocketsAdapter');

// -- sites used for testing requests
$example_site_url = 'http://www.google.com';
$askeet_params = array(
  'url'         => 'http://www.askeet.com',
  'login'       => 'francois',
  'password'    => 'llactnevda2',
);

// -- cookies, file and directory automatically created
$cookies_dir = dirname(__FILE__).'/../data/sfCurlAdapter';
$cookies_file = $cookies_dir.'/cookies.txt';

/**
 * stub class
 *
 **/
class myTestWebBrowser extends sfWebBrowser
{
  protected $requestMethod;
  public function call($uri, $method = 'GET', $parameters = array(), $headers = array(), $changeStack = true)
  {
    parent::call($uri, $method, $parameters, $headers, $changeStack);
    $this->requestMethod = $this->stack[$this->stackPosition]['method'];
  }
  public function getRequestMethod()
  {
    return $this->requestMethod;
  }
}

$t = new lime_test($nb_test_orig * count($adapter_list), new lime_output_color());
foreach($adapter_list as $adapter)
{
  $t->diag('current adapter: '.$adapter);

  $t->diag('initialization');
  $b = new sfWebBrowser(array(), $adapter);
  
  $t->is($b->getUserAgent(), '', 'a new browser has an empty user agent');
  $t->is($b->getResponseText(), '', 'a new browser has an empty response');
  $t->is($b->getResponseCode(), '', 'a new browser has an empty response code');
  $t->is($b->getResponseHeaders(), array(), 'a new browser has empty reponse headers');
  
  $t->diag('utility methods');
  $b = new sfWebBrowser(array(), $adapter);
  $t->is($b->setUserAgent('foo bar')->getUserAgent(), 'foo bar', 'setUserAgent() sets the user agent');
  $t->is($b->setResponseText('foo bar')->getResponseText(), 'foo bar', 'setResponseText() extracts the response');
  $t->is($b->setResponseCode('foo 123 bar')->getResponseCode(), '123', 'setResponseCode() extracts the three-digits code');
  $t->is($b->setResponseCode('foo 12 bar')->getResponseCode(), '', 'setResponseCode() fails silently when response status is incorrect');
  $t->is_deeply($b->setResponseHeaders(array('HTTP1.1 200 OK', 'foo: bar', 'bar: baz'))->getResponseHeaders(), array('Foo' => 'bar', 'Bar' => 'baz'), 'setResponseHeaders() extracts the headers array');
  $t->is_deeply($b->setResponseHeaders(array('ETag: "535a8-9fb-44ff4a13"', 'WWW-Authenticate: Basic realm="Myself"'))->getResponseHeaders(), array('ETag' => '"535a8-9fb-44ff4a13"', 'WWW-Authenticate' => 'Basic realm="Myself"'), 'setResponseHeaders() extracts the headers array and accepts response headers with several uppercase characters');
  $t->is_deeply($b->setResponseHeaders(array('HTTP1.1 200 OK', 'foo: bar', 'bar:baz', 'baz:bar'))->getResponseHeaders(), array('Foo' => 'bar'), 'setResponseHeaders() ignores malformed headers');
  
  $t->diag('exceptions');
  $b = new sfWebBrowser(array(), $adapter);
  try
  {
    $b->get('htp://askeet');
    $t->fail('get() throws an exception when passed an uri which is neither http nor https');
  }
  catch (Exception $e)
  {
    $t->pass('get() throws an exception when passed an uri which is neither http nor https');
  }
  
  $t->diag('simple GET request');
  $t->like($b->get($dump_headers_url)->getResponseText(), '/\[REQUEST_METHOD\] => GET/', 'get() performs a GET request');
  $t->isa_ok($b, 'sfWebBrowser', 'get() make a web request and returns a browser object');
  $t->is($b->getResponseCode(), 200, 'get() fills up the browser status code with the response');
  $t->like($b->get($example_site_url)->getResponseHeader('Content-Type'), '/text\/html/', 'get() populates the header array');
  $t->like(strtolower($b->getResponseText()), '/<\/body>/', 'get() populates the HTML of the response');
  
  $t->diag('simple HEAD request');
  $t->like($b->head($dump_headers_url)->getResponseHeader('Content-Type'), '/text\/html/', 'head() populates the header array');
  $t->is($b->getResponseText(), '', 'HEAD requests do not return a response body');
  
  $t->diag('simple POST request');
  $t->like($b->post($dump_headers_url)->getResponseText(), '/\[REQUEST_METHOD\] => POST/', 'post() performs a POST request');
  $t->like($b->post($dump_headers_url, array('post body'))->getResponseText(), '/post body/', 'post() sends body to server');
  
  $t->diag('simple PUT request');
  $t->like($b->put($dump_headers_url)->getResponseText(), '/\[REQUEST_METHOD\] => PUT/', 'put() performs a PUT request');
  $t->like($b->put($dump_headers_url, array('PUT body'))->getResponseText(), '/PUT body/', 'put() sends body to server');
  
  $t->diag('simple DELETE request');
  $t->like($b->delete($dump_headers_url)->getResponseText(), '/\[REQUEST_METHOD\] => DELETE/', 'delete() performs a DELETE request');
  
  $t->diag('arbitrary request');
  $t->like($b->call($dump_headers_url, 'MICHEL')->getResponseText(), '/\[REQUEST_METHOD\] => MICHEL/', 'call() supports any HTTP methods');
  
  
  $t->diag('Response formats methods');
  $b = new sfWebBrowser(array(), $adapter);
  $b->get($example_site_url);
  $t->like($b->getResponseText(), '/<body .*>/', 'getResponseText() returns the response text');
  $t->unlike($b->getResponseBody(), '/<body>/', 'getResponseBody() returns the response body');
  $t->isa_ok($b->getResponseDom(), 'DOMDocument', 'getResponseDom() returns the response Dom');
  $t->isa_ok($b->getResponseDomCssSelector(), 'sfDomCssSelector', 'getResponseDomCssSelector() returns a CSS selector on the response Dom');
  $b->get('http://rss.cnn.com/rss/cnn_topstories.rss');
  $t->isa_ok($b->getResponseXml(), 'SimpleXMLElement', 'getResponseXml() returns the response as a SimpleXML Element');
  $b->get('http://www.w3.org/StyleSheets/home.css');
  try
  {
    $b->getResponseXml();
    $t->fail('Incorrect XML throws an exception');
  }
  catch (Exception $e)
  {
    $t->pass('Incorrect XML throws an exception');
  }
  
  try
  {
    $t->diag('absolute and relative URls');
    $b = new sfWebBrowser(array(), $adapter);
    $t->like($b->get($askeet_params['url'])->getResponseText(), '/<h1>featured questions<\/h1>/', 'get() understands absolute urls');
    $t->like($b->get($askeet_params['url'].'/index/1')->getResponseText(), '/<h1>popular questions<\/h1>/', 'get() understands absolute urls');
    $t->like($b->get('/recent/1')->getResponseText(), '/<h1>recent questions<\/h1>/', 'get() understands relative urls with a trailing slash');
    $t->like($b->get('/')->get('recent/1')->getResponseText(), '/<h1>recent questions<\/h1>/', 'get() understands relative urls without a trailing slash');
    
    $t->diag('interaction methods');
    $b = new sfWebBrowser(array(), $adapter);
    $t->like($b->get($askeet_params['url'])->click('activities')->getResponseText(), '/tag "activities"/', 'click() clicks on a link and executes the related request');
    $t->like($b->get($askeet_params['url'])->click('/tag/activities')->getResponseText(), '/tag "activities"/', 'click() clicks on a link and executes the related request');
    $t->like($b->click('askeet')->getResponseText(), '/<h1>featured questions<\/h1>/', 'click() clicks on an image if it finds the argument in the alt');
    $t->like($b->click('search it', array('search' => 'foo'))->getResponseText(), '/<h1>questions matching "foo"<\/h1>/', 'click() clicks on a form input');
    $t->like($b->setField('search', 'bar')->click('search it')->getResponseText(), '/<h1>questions matching "bar"<\/h1>/', 'setField() fills a form input');
  }
  catch (Exception $e)
  {
    $t->fail(sprintf('%s : skipping askeet related tests', $e->getMessage()));  
  }
  
  try
  {
    $t->diag('GET request with parameters');
    $b = new sfWebBrowser(array(), $adapter);
    $test_params = array('foo' => 'bar', 'baz' => '1');
    $t->like($b->get($dump_headers_url, $test_params)->getResponseText(), '/\?foo=bar&baz=1/', 'get() can pass parameters with the second argument');
    $t->like($b->get($dump_headers_url.'?'.http_build_query($test_params))->getResponseText(), '/\?foo=bar&baz=1/', 'get() can pass parameters concatenated to the URI as a query string');
    $t->unlike($b->get($dump_headers_url.'?'.http_build_query($test_params))->getResponseText(), '/\?foo=bar&baz=1\&/', 'get() with an URL already containing request parameters doesn\'t add an extra &');
    $t->like($b->get($dump_headers_url.'?'.http_build_query($test_params), array('biz' => 'bil'))->getResponseText(), '/\?foo=bar&baz=1&biz=bil/', 'get() can pass parameters concatenated to the URI as a query string and other parameters as a second argument');
  
    $b = new sfWebBrowser(array(), $adapter);
    $b->get($dump_headers_url);
  
    $t->diag('Default request headers');
    $headers = array('Accept-language' => 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3');
    $b = new sfWebBrowser($headers, $adapter);
    $t->like($b->get($dump_headers_url)->getResponseText(), "/fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3/", 
             'sfWebBrowser constructor accepts default request headers as first parameter');
    $t->like($b->get($dump_headers_url, array(), array('Accept-language' => 'en-gb;q=0.8,en-us;q=0.5,en;q=0.3'))->getResponseText(), "/en-gb;q=0.8,en-us;q=0.5,en;q=0.3/", 
             'Default request headers are overriden by request specific headers');
    
    $t->diag('Request headers support');
    $b = new sfWebBrowser(array(), $adapter);
    $headers = array('Accept-language' => 'fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3',
                     'Accept'          => 'text/xml');
    $t->like($b->get($dump_headers_url, array(), $headers)->getResponseText(), "/fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3/", 
             'get() can pass request headers with the third argument');
    
    $t->like($b->post($dump_headers_url, array(), $headers)->getResponseText(), "/fr,fr-fr;q=0.8,en-us;q=0.5,en;q=0.3/", 
             'post() can pass request headers with the third argument');

    $msg = "get() can pass request headers not common that are defined uppercase in RFC 2616";
    try
    {
      $t->like($b->get($dump_headers_url, array(), array('TE' =>'trailers, deflate;q=0.5'))->getResponseText(), "/\[TE\] => trailers, deflate;q=0.5/", 
               $msg);
    }
    catch (Exception $e)
    {
      $t->fail($msg);
    }
    
    $msg = 'get() can pass request headers not common that are IE7 dependent: see http://www.w3.org/2006/http-header, now: ';
    $field = '';
    try
    {
      $headers = array('UA-CPU'=>'x86', 'UA-OS'=>'MacOS', 'UA-Color'=>'color16', 'UA-Pixels'=>'240x320');
      $resp = $b->get($dump_headers_url, array(), $headers)->getResponseText();
      foreach ($headers as $field => $value)
      {
        $t->like($resp, "/\[$field\] => $value/", $msg.$field);
      }
    }
    catch (Exception $e)
    {
      $t->fail($msg.field.' - header refused');
    }
    
    $t->diag('Encoded response body support');
    
    $headers = array('Accept-Encoding' => 'gzip');
    $t->like($b->get($dump_headers_url, array(), $headers)->getResponseText(), "/gzip/", 
             'getResponseText() can decode gzip encoded response body');
    
    $headers = array('Accept-Encoding' => 'deflate');
    $t->like($b->get($dump_headers_url, array(), $headers)->getResponseText(), "/deflate/", 
             'getResponseText() can decode deflate encoded response body');
    
    $encodings = array();
    if (function_exists('gzuncompress'))
    {
      $encodings[] = 'deflate';
    }
    if (function_exists('gzinflate'))
    {
      $encodings[] = 'gzip';
    }
    $target_headers = implode(',', $encodings);
    $t->like($b->get($dump_headers_url, array(), $headers)->getResponseText(), "/$target_headers/", 
             'sfWebBrowser autosets accept-encoding headers depending on php capabilities');
  
    $encodings = array();
    if (function_exists('gzinflate'))
    {
      $encodings[] = 'gzip';
    }
    if (function_exists('gzuncompress'))
    {
      $encodings[] = 'deflate';
    }
    $headers = array('accept-encoding' => 'bzip2');
    array_unshift($encodings, 'bzip2');
    $target_headers = implode(',', $encodings);
    $t->like($b->get($dump_headers_url, array(), $headers)->getResponseText(), "/$target_headers/", 
             'it is possible to set supplementary encodings');
  
    $t->diag('history methods');
    $b = new sfWebBrowser(array(), $adapter);
    $b->get($dump_headers_url);
    $b->get($dump_headers_url.'?foo=bar');
    $b->back();
    $t->unlike($b->getResponseText(), '/foo=bar/', 'back() executes again the previous request in the history');
    $b->forward();
    $t->like($b->getResponseText(), '/foo=bar/', 'forward() executes again the next request in the history');
    $b->reload();
    $t->like($b->getResponseText(), '/foo=bar/', 'reload() executes again the current request in the history');
  }
  catch (Exception $e)
  {
    $t->fail(sprintf('%s : skipping tests that need it', $e->getMessage()));  
  }
  
  $t->diag('Error management');
  try
  {
    $b->get('http://nonexistent');
    $t->fail('an exception is thrown when an adapter error occurs');
  }
  catch (Exception $e)
  {
    $t->pass('an exception is thrown when an adapter error occurs');
  }
  
  $t->diag('responseIsError()');
  $t->is($b->get($example_site_url . '/nonexistentpage.html')->responseIsError(), true, 'responseIsError() returns true when response is an error');
  $t->is($b->get($example_site_url)->responseIsError(), false, 'responseIsError() returns false when response is not an error');
  
  $t->diag('browser restart');
  $b->restart();
  try
  {
    $b->reload();  
    $t->fail('restart() reinitializes the browser history');
  } 
  catch (Exception $e)
  {
    $t->pass('restart() reinitializes the browser history');  
  }
  $t->is($b->getResponseText(), '', 'restart() reinitializes the response');
  
  $t->diag('redirects');
  $b = new sfWebBrowser(array(), $adapter);
  $b->get('http://www.symfony-project.com/trac/wiki/sfUJSPlugin');
  $t->like($b->getResponseText(), '/learn more about the unobtrusive approach/', 'follows 302 redirect after a GET');
  
  $b = new myTestWebBrowser(array(), $adapter);
  $b->call($askeet_params['url'].'/index.php/login', 'POST', array('nickname' => $askeet_params['login'], 'password' => $askeet_params['password']));
  //$t->like($b->getResponseText(), '/url='.preg_quote($askeet_params['url'], '/').'\/index\.php/', 'does NOT follow a 302 redirect after a POST');
  $t->like($b->getResponseText(), '/featured questions/', 'follows 302 redirect after POST ****** DESPITE THE HTTP SPEC ******');
  $t->is($b->getRequestMethod(), 'GET', 'request method is changed to GET after POST for 302 redirect ***** DESPITE THE HTTP SPEC *****');
  $t->todo('request method is changed to GET after POST for 303 redirect');
  
  if ($adapter == 'sfCurlAdapter')
  {
    $t->diag('cookies');
    $b = new sfWebBrowser(array(), $adapter, array(
      'cookies'      => true,
      'cookies_file' => $cookies_file,
      'cookies_dir'  => $cookies_dir,
    ));
    $b->call($askeet_params['url'].'/login', 'POST', array(
      'nickname' => $askeet_params['login'],
      'password' => $askeet_params['password'],
    ));
    $t->like($b->getResponseBody(), '/'.$askeet_params['login'].' profile/', 'Understands cookies');
  
    rmdir($cookies_dir);
    rmdir(dirname(__FILE__).'/../data');
  
    $t->diag('file uploads');
    $b->post($dump_headers_url, array(
      'test_file' => realpath(__FILE__),
    ));
    $t->like($b->getResponseText(), '/\[test_file\]/', 'uploads a file');
  }
  else
  {
    $t->todo('Understands cookies');
    $t->todo('Uploads a file');
  }

  $t->diag('make XML exchanges to test Content-Type');
  $url = 'http://www.abundanttech.com/WebServices/Population/population.asmx';
  $headers = array(
    'Soapaction'      => 'http://www.abundanttech.com/WebServices/Population/getWorldPopulation',
    'Content-Type'    => 'text/xml'
  );
  $requestBody = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><getWorldPopulation xmlns="http://www.abundanttech.com/WebServices/Population" /></soap:Body></soap:Envelope>';
  $b = new sfWebBrowser(array(), $adapter);
  $b->post($url, $requestBody, $headers);
  $t->like($b->getResponseText(), '/<Country>World<\/Country>/', 'make a low-level SOAP call without parameter');

  $url = 'http://www.abundanttech.com/WebServices/Population/population.asmx';
  $headers = array(
    'Soapaction'      => 'http://www.abundanttech.com/WebServices/Population/getPopulation',
    'Content-Type'    => 'text/xml'
  );
  $requestBody = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pop="http://www.abundanttech.com/WebServices/Population"><soapenv:Header/><soapenv:Body><pop:getPopulation><pop:strCountry>Comoros</pop:strCountry></pop:getPopulation></soapenv:Body></soapenv:Envelope>';
  $b = new sfWebBrowser(array(), $adapter);
  $b->post($url, $requestBody, $headers);
  $t->like($b->getResponseText(), '/<Country>Comoros<\/Country>/', 'make a low-level SOAP call with parameter');
}
Return current item: OpenPNE