Skip to content
Snippets Groups Projects
RechercheControllerReservationTest.php 52.34 KiB
<?php
/**
 * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
 *
 * BOKEH is free software; you can redistribute it and/or modify
 * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
 * the Free Software Foundation.
 *
 * There are special exceptions to the terms and conditions of the AGPL as it
 * is applied to this software (see README file).
 *
 * BOKEH is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
 *
 * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
 * along with BOKEH; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
 */


abstract class RechercheControllerReservationTestCase
  extends AbstractControllerTestCase {

  protected $_json, $_xpath,
    $_storm_default_to_volatile = true;

  public function setUp() {
    parent::setUp();

    $this->fixture(Class_CodifAnnexe::class,
                   ['id' => 2,
                    'code' => '36',
                    'id_origine' => '36',
                    'libelle' => 'Annecy']);

    $this->fixture(Class_CodifAnnexe::class,
                   ['id' => 3,
                    'code' => '37',
                    'id_origine' => '37',
                    'libelle' => 'Cran']);

    $this->_xpath = new Storm_Test_XPath();
  }
}




abstract class RechercheControllerReservationWithPickupChoiceTestCase
  extends RechercheControllerReservationTestCase {

  public function setUp() {
    parent::setUp();
    Class_CosmoVar::setValueOf('site_retrait_resa',
                               Class_CosmoVar::PICKUP_LOCATION_CHOICE);
  }
}




class RechercheControllerReservationPickupAjaxActionWithChosenPickupTest
  extends RechercheControllerReservationWithPickupChoiceTestCase {

  public function setUp() {
    parent::setUp();

    $this->dispatch('recherche/reservation-pickup-ajax?id_bib=2&id_origine=12&code_annexe=36',true);

    $this->_json = json_decode($this->_response->getBody());
  }


  /** @test */
  public function shouldRenderAnnecyCheckedRadio() {
    $this->_xpath->assertXPath($this->_json->content,
                               '//input[@name="code_annexe"][@value="36"][@checked="checked"]',$this->_json->content);
  }


  /** @test */
  public function shouldRenderCranRadio() {
    $this->_xpath->assertXPath($this->_json->content,
                               '//input[@name="code_annexe"][@value="37"]');
  }


  /** @test */
  public function layoutShouldBeEmpty() {
    $this->_xpath->assertNotXPath($this->_json->content, '//div[@id="banniere"]');
  }
}




class RechercheControllerReservationPickupAjaxActionPostTest
  extends RechercheControllerReservationWithPickupChoiceTestCase {


  /** @test */
  public function responseShouldRedirectToReservationajaxAction() {
    $this->postDispatch('recherche/reservation-pickup-ajax',
                        ['id_bib' => 2,
                         'id_origine' => 12,
                         'code_annexe' => '36']);

    $this->assertRedirectTo('/recherche/reservationajax/code_annexe/36');
  }


  /** @test */
  public function withoutAvailablePickupLocationPostResponseShouldAnswerError() {
    Class_CodifAnnexe::deleteBy([]);
    $this->postDispatch('recherche/reservation-pickup-ajax',
                        ['id_bib' => 2,
                         'id_origine' => 12,
                         'code_annexe' => '36']);
    $json = json_decode($this->_response->getBody(), true);
    $this->assertContains('Aucun site de retrait disponible', $json['content']);
  }


  /** @test */
  public function withoutAvailablePickupLocationGETResponseShouldAnswerError() {
    Class_CodifAnnexe::deleteBy([]);
    $this->dispatch('recherche/reservation-pickup-ajax/id_bib/2/id_origine/12');
    $json = json_decode($this->_response->getBody(), true);
    $this->assertContains('Aucun site de retrait disponible', $json['content']);
  }


  /** @test */
  public function withPopupAndInspectorGadgetResponseShouldStillSendJSON() {
    Zend_Registry::get('session')->inspectorCalls = [serialize(new Class_InspectorGadget_ServiceCall('I', 'love', 'milk', 'coffee', '418'))];

    $this->postDispatch('recherche/reservation-pickup-ajax/render/popup/inspector_gadget/1',
                        ['id_bib' => 2,
                         'id_origine' => 12,
                         'code_annexe' => '36']);
    $this->assertNotNull($json = json_decode($this->_response->getBody(), true));
    $this->assertContains('<script>location.reload();</script>', $json['content']);
  }


  /** @test */
  public function responseShouldContainsJsonRedirectToReservationajaxAction() {
    $this->postDispatch('recherche/reservation-pickup-ajax/render/popup',
                        ['id_bib' => 2,
                         'id_origine' => 12,
                         'code_annexe' => '36']);
    $json = json_decode($this->_response->getBody(), true);
    $this->assertContains('<script>location.reload();</script>', $json['content']);
  }
}




class RechercheControllerReservationPickupAjaxActionTestWithChosenPickupDispatch
  extends RechercheControllerReservationWithPickupChoiceTestCase {

  protected $_sent_mails;

  public function setUp() {
    parent::setUp();

    $bib = $this
      ->fixture('Class_IntBib',
                ['id' => 1,
                 'comm_sigb' => Class_IntBib::COM_NANOOK,
                 'comm_params' => ['url_serveur' => 'http://bib.valensol.net']]);

    $this->jajm = $this
      ->fixture('Class_Users',
                ['id' => 1,
                 'login' => 'jajm',
                 'password' => 'secret',
                 'idabon' => '0000007',
                 'int_bib' => $bib,
                ]);

    $this->nanook = Storm_Test_ObjectWrapper::mock()
      ->whenCalled('isConnected')->answers(true)
      ->whenCalled('reserverExemplaire')->answers(['erreur' => '', 'statut' => true]);

    Class_WebService_SIGB_Nanook::setService(['url_serveur' => 'http://bib.valensol.net',
                                              'id_bib' => 1,
                                              'type' => Class_IntBib::COM_NANOOK,],
                                             $this->nanook);

    ZendAfi_Auth::getInstance()->logUser($this->jajm);

    $this->fixture('Class_Exemplaire', ['id' => 12]);

    $mock_transport = new MockMailTransport();
    Zend_Mail::setDefaultTransport($mock_transport);

    $this->dispatch('recherche/reservationajax/id/11760/id_int_bib/23/id_bib/23/id_origine/594105/code_annexe/23/render/popup/copy_id/12', true);

    $this->_sent_mails = $mock_transport->getSentMails();
  }


  /** @test */
  public function parameterCodeAnnexeShouldBeUsedForReservation() {
    $this->assertEquals('23',
                        $this->nanook->getAttributesForLastCallOn('reserverExemplaire')[2]);
  }


  /** @test */
  public function noEmailShouldHaveBeenSentWithDefaultConf() {
    $this->assertEmpty($this->_sent_mails);
  }
}




class RechercheControllerReservationPickupAjaxActionTestWithPatronLibraryPickup
  extends RechercheControllerReservationTestCase {

  public function setUp() {
    parent::setUp();

    $bib = $this
      ->fixture('Class_IntBib',
                ['id' => 12,
                 'comm_sigb' => Class_IntBib::COM_NANOOK,
                 'comm_params' => ['url_serveur' => 'http://bib.valensol.net']]);

    $this->jajm = $this->fixture('Class_Users',
                                 ['id' => 1,
                                  'login' => 'jajm',
                                  'password' => 'secret',
                                  'idabon' => '0000007',
                                  'int_bib' => $bib]);

    $this->nanook = Storm_Test_ObjectWrapper::mock()
      ->whenCalled('isConnected')->answers(true)
      ->whenCalled('reserverExemplaire')->answers(['erreur' => '', 'statut' => true])
      ->whenCalled('providesPickupLocations')->answers(false)
      ->whenCalled('getUserAnnexe')->answers('12');

    Class_WebService_SIGB_Nanook::setService(['url_serveur' => 'http://bib.valensol.net',
                                              'id_bib' => 12,
                                              'type' => Class_IntBib::COM_NANOOK,],
                                             $this->nanook);

    ZendAfi_Auth::getInstance()->logUser($this->jajm);

    Class_CosmoVar::setValueOf('site_retrait_resa',
                               Class_CosmoVar::PICKUP_LOCATION_PATRON);

    $this->fixture('Class_Exemplaire', ['id' => 12]);

    $this->dispatch('recherche/reservation-pickup-ajax?id_bib=2&id_origine=12&code_annexe=36&copy_id=12', true);
  }


  /** @test */
  public function getUserAnnexeResultShouldBeUsedForReservation() {
    $this->assertEquals('12',
                        $this->nanook->getAttributesForLastCallOn('reserverExemplaire')[2]);
  }
}




class RechercheControllerReservationPickupAjaxActionTestWithItemLibraryPickup
  extends RechercheControllerReservationTestCase {

  public function setUp() {
    parent::setUp();

    $bib = $this->fixture('Class_IntBib',
                          ['id' => 1,
                           'comm_sigb' => Class_IntBib::COM_NANOOK,
                           'comm_params' => ['url_serveur' => 'http://bib.valensol.net']]);

    $this->jajm = $this->fixture('Class_Users',
                                 ['id' => 1,
                                  'login' => 'jajm',
                                  'password' => 'secret',
                                  'idabon' => '0000007',
                                  'int_bib' => $bib
                                 ]);

    $this->nanook = Storm_Test_ObjectWrapper::mock()
      ->whenCalled('isConnected')->answers(true)
      ->whenCalled('providesPickupLocations')->answers(false)
      ->whenCalled('reserverExemplaire')->answers(['statut' => true, 'erreur' => '']);

    Class_WebService_SIGB_Nanook::setService(['url_serveur' => 'http://bib.valensol.net',
                                              'id_bib' => 1,
                                              'type' => Class_IntBib::COM_NANOOK,],
                                             $this->nanook);

    ZendAfi_Auth::getInstance()->logUser($this->jajm);

    Class_CosmoVar::setValueOf('site_retrait_resa',
                               Class_CosmoVar::PICKUP_LOCATION_ITEM);

    $this->fixture('Class_Exemplaire', ['id' => 12]);

    $this->dispatch('recherche/reservation-pickup-ajax?id_bib=2&id_origine=12&code_annexe=36&copy_id=12', true);
  }


  /** @test */
  public function itemAnnexeShouldBeUsedForReservation() {
    $this->assertEquals('36',
                        $this->nanook->getAttributesForLastCallOn('reserverExemplaire')[2]);
  }
}




class RechercheControllerReservationWithMailPostAction
  extends AbstractControllerTestCase {
  protected
    $_sent_mails,
    $_storm_default_to_volatile = true;

  public function setUp() {
    parent::setUp();

    $_SESSION["captcha_code"] = '1234';

    $mock_transport = new MockMailTransport();
    Zend_Mail::setDefaultTransport($mock_transport);

    $this->fixture('Class_Bib', ['id' => 4,
                                 'libelle' => 'Astrolabe',
                                 'mail' => 'zork@gloub.fr',]);

    $this->fixture('Class_Notice', ['id' => 4,
                                    'unimarc' => "01570nam0 2200325   450 0010007000000100033000070200017000400210027000571000041000841010008001251020007001331050018001401060006001582000106001642100075002702150044003452250023003893000125004123000020005373000137005573300265006943450018009594100051009775120027010286060033010556060060010886760012011487000045011608010039012052218529  a2-86642-370-4bbr.d8,95 EUR  aFRb00347575  aFRbDLE-20031204-51138  a20031107d2003    m  h0frey0103    ba| afre  aFR  ay   z   000y|  ar1 aCinema d'animationbTexte impriméedessin animé, marionnettes, images de synthèsefBernard Genin  a[Paris]c\"Cahiers du cinéma\"cSCEREN-CNDPdcop. 2003gimpr. en Italie  a95 p.cill., couv. ill. en coul.d19 cm2 aLes petits cahiers  aLa couv. porte en plus : \"du crayon à l'ordinateur, pour ou contre Disney, Europe-Japon : le dessin animé aujourd'hui\"  aBibliogr. p. 93  aSCEREN = Services, cultures, éditions, ressources pour l'éducation nationale. CNDP = Centre national de documentation pédagogique  aPrésente un historique du cinéma d'animation, un survol des différentes productions nationales à travers le monde (Etats-Unis, Japon, France, Canada), les techniques du volume animé, l'image de synthèse, mais aussi l'oeuvre de Disney et le film d'auteur.  b9782866423704 032525826tLes Petits cahiers (Paris)x1633-90531 aLe cinéma d'animation| 31053394aAnimation (cinéma)| 31031625aDessins animés32195497xHistoire et critique  a791.431 |32547161aGeninbBernardf1946-....4070 0aFRbBNFc20031107gAFNOR2intermrc"]);

    $this->postDispatch('/recherche/reservation/id_notice/4/id_bib/4/cote/XYZ',
                        ['user_name' => 'nanuk',
                         'demande' => 'je veux le livre',
                         'user_mail' => 'nanuk@gloub.com',
                         'code_saisi' => '1234']);
    $this->_sent_mails = $mock_transport->getSentMails();
    $this->first_mail = array_first($this->_sent_mails);
    $this->first_content = quoted_printable_decode($this->first_mail->getBodyText()->getContent());
    $this->last_mail = array_last($this->_sent_mails);
  }


  /** @test */
  public function twoMailsShouldHaveBeenSent() {
    $this->assertEquals(2, count($this->_sent_mails));
  }


  /** @test */
  public function firstMailFromShouldBeNanuk() {
    $this->assertEquals('nanuk@gloub.com',
                        $this->first_mail->getFrom());
  }


  /** @test */
  public function firstMailSubjectShouldBeDemandeDeReservation() {
    $this->assertContains('Demande de réservation de document',
                          quoted_printable_decode($this->first_mail->getSubject()));
  }


  /** @test */
  public function firstMailToShouldBeZork() {
    $this->assertContains('zork@gloub.fr',
                          $this->first_mail->getRecipients());
  }


  /** @test */
  public function titleShouldBePresent() {
    $this->assertTrue(false !== strpos($this->first_content, 'Titre : Cinema d\'animation'));
  }


  /** @test */
  public function authorShouldBePresent() {
    $this->assertTrue(false !== strpos($this->first_content, 'Auteur : Bernard Genin'),
                      $this->first_content);
  }


  /** @test */
  public function secondMailFromShouldBeNobody() {
    $this->assertEquals('nobody@noreply.fr',
                        $this->last_mail->getFrom());
  }


  /** @test */
  public function secondMailToShouldBeNanuk() {
    $this->assertContains('nanuk@gloub.com',
                          $this->last_mail->getRecipients());
  }
}




class RechercheControllerReservationWithWebServiceKohaTest
  extends AbstractControllerTestCase {
  protected $_storm_default_to_volatile = true;

  public function setUp() {
    parent::setUp();

    $webservice = 'http://bib.valensol.net';
    $bib = $this->fixture('Class_IntBib',
                          ['id' => 1,
                           'comm_sigb' => Class_IntBib::COM_KOHA,
                           'comm_params' => ['url_serveur' => $webservice]]);

    $this->jajm = $this->fixture('Class_Users',
                                 ['id' => 1,
                                  'login' => 'jajm',
                                  'password' => 'secret',
                                  'int_bib' => $bib,
                                 ]);

    ZendAfi_Auth::getInstance()->logUser($this->jajm);
    $this->koha = Storm_Test_ObjectWrapper::mock();
    $this->koha
      ->whenCalled('getServerRoot')
      ->answers($webservice);

    Class_WebService_SIGB_Koha::setService(['url_serveur' => $webservice,
                                            'id_bib' => 1,
                                            'type' => Class_IntBib::COM_KOHA],
                                           $this->koha);
  }


  protected function dispatchAndCheckContentEquals($expected) {
    $this->dispatch('/recherche/reservationajax/id_bib/1/copy_id/456/code_annexe/VS',
                    true);
    $this->json = json_decode($this->_response->getBody());
    $this->assertEquals($expected, $this->json->content);
  }


  /** @test */
  public function reservationAjaxWithItemRequiringCalendarHoldShouldRedirectToReservationCalendarAjax() {
    $this->fixture('Class_Exemplaire',
                   ['id' => 456,
                    'code_barres' => 123,
                    'id_int_bib' => 1,
                    'notice' => $this->fixture('Class_Notice',
                                               ['id' => 8890,
                                                'titre_principal' => 'Elementaire mon cher polar',
                                                'auteur_principal' => 'Conan Doyle'])]);

    $this->jajm->setIdabon(395749);

    $this->koha
      ->whenCalled('isConnected')
      ->answers(true)

      ->whenCalled('reserverExemplaire')
      ->willDo(function()
               {
                 throw new Class_WebService_SIGB_RequiresCalendarHoldException();
               });

    $this->dispatch('/recherche/reservationajax/id_bib/1/copy_id/456/code_annexe/VS');

    $this->assertRedirectTo('/recherche/reservation-calendar-ajax/id_bib/1/copy_id/456/code_annexe/VS');
  }


  /** @test */
  public function withMatchingHoldMessageShouldContainsPickupLocation() {
    $item = $this->fixture('Class_Exemplaire',
                           ['id' => 456,
                            'code_barres' => 123,
                            'id_int_bib' => 1]);

    $response = $this->_prepareEmprunteurHolding($item, 'Valensole');
    $expected_message = 'Votre réservation est enregistrée.<br>Nous vous informerons quand le document sera disponible pour être retiré à : Valensole';
    $this->_dispatchWithEmprunteurAndAssertContentEquals($response,
                                                         $expected_message);
  }


  /** @test */
  public function withMatchingHoldAndRecordWithBRInTitleMessageShouldContainsPickupLocationAndRecordTitleAuthor() {
    $exemplaire = $this->fixture('Class_Exemplaire',
                                 ['id' => 456,
                                  'code_barres' => 123,
                                  'id_int_bib' => 1,
                                  'notice' => $this->fixture('Class_Notice',
                                                             ['id' => 8890,
                                                              'titre_principal' => 'Albator <br /> Arcadia',
                                                              'auteur_principal' => 'Matsumoto'])]);
    $this->_dispatchWithEmprunteurAndAssertContentEquals(
      $this->_prepareEmprunteurHolding($exemplaire, 'Valensole'),
      'Votre réservation est enregistrée.<br>Nous vous informerons quand le document \'Albator  Arcadia / Matsumoto\' sera disponible pour être retiré à : Valensole');
  }


  /** @test */
  public function withMatchingHoldAndRecordWithoutAuthorMessageShouldContainsPickupLocationAndRecordTitleOnly() {
    $exemplaire = $this->fixture('Class_Exemplaire',
                                 ['id' => 456,
                                  'code_barres' => 123,
                                  'id_int_bib' => 1,
                                  'notice' => $this->fixture('Class_Notice',
                                                             ['id' => 8890,
                                                              'titre_principal' => 'Arcadia'])]);
    $this->_dispatchWithEmprunteurAndAssertContentEquals(
      $this->_prepareEmprunteurHolding($exemplaire, 'Valensole'),
      'Votre réservation est enregistrée.<br>Nous vous informerons quand le document \'Arcadia\' sera disponible pour être retiré à : Valensole');
  }


  /** @test */
  public function withoutMatchingHoldMessageShouldContainsDocumentNotFound() {
    $this->_dispatchWithEmprunteurAndAssertContentEquals(
      $this->_prepareEmprunteurHolding(null, 'Valensole'),
      'Document introuvable');
  }


  /** @test */
  public function withMatchingHoldAndNoPickupLocationShouldNotContainsPickupLocation() {
    $this->_dispatchWithEmprunteurAndAssertContentEquals(
      $this->_prepareEmprunteurHolding($this->fixture('Class_Exemplaire', ['id' => 456]),
                                       null),
      'Votre réservation est enregistrée.<br>Nous vous informerons quand le document sera disponible');
  }


  protected function _prepareEmprunteurHolding($item, $pickup_label) {
    $this->jajm->setIdabon(395749);

    $exemplaire = (new Class_WebService_SIGB_Exemplaire(2))
      ->setExemplaireOPAC($item);
    $hold = new Class_WebService_SIGB_Reservation(2, $exemplaire);
    $hold->setPickupLocationLabel($pickup_label)
         ->setCodeBarre(123);

    $emprunteur_jajm = Class_WebService_SIGB_Emprunteur::newInstance(2, 'jajm');
    $emprunteur_jajm->reservationsAdd($hold);
    return $emprunteur_jajm;
  }

  protected function _dispatchWithEmprunteurAndAssertContentEquals($emprunteur, $content) {
    $this->koha
      ->whenCalled('isConnected')->answers(true)
      ->whenCalled('reserverExemplaire')->answers(['statut' => true,
                                                   'erreur' => '',
                                                   'popup' => false])
      ->whenCalled('getEmprunteur')->answers($emprunteur);

    $this->dispatchAndCheckContentEquals($content);
  }


  /** @test */
  public function popupResultContentWithWebServiceErrorShouldContainsErreurDeCommunication() {
    $this->jajm->setIdabon(395749);

    $this->_prepareEmprunteurHolding($this->fixture('Class_Exemplaire', ['id' => 456]),
                                     'Valensole');

    $this->koha->whenCalled('isConnected')->answers(false);

    $this->dispatchAndCheckContentEquals("Une erreur de communication avec le serveur a fait échouer la requête. Merci de signaler ce problème à la bibliothèque.");
  }


  /** @test */
  public function withoutIdAbonpopupResultContentShouldContainsVousDevezVousConnecterSousVotreNumeroDeCarte() {
    $this->dispatchAndCheckContentEquals("Vous devez vous connecter sous votre numéro de carte pour effectuer une réservation.");
  }
}




class RechercheControllerReservationSerialWithWebServiceKohaTest
  extends AbstractControllerTestCase {
  protected $_storm_default_to_volatile = true;
  protected $_exemplaire;

  public function setUp() {
    parent::setUp();

    $webservice = 'http://bib.valensol.net';
    $bib = $this->fixture('Class_IntBib',
                          ['id' => 1,
                           'comm_sigb' => Class_IntBib::COM_KOHA,
                           'comm_params' => ['url_serveur' => $webservice]]);

    $data_profile = $this->fixture('Class_IntProfilDonnees',
                   ['id' => 433,
                    'id_article_periodique' => Class_IntProfilDonnees::SERIAL_FORMAT_KOHA]
    );

    $this->_exemplaire = $this->fixture('Class_Exemplaire',
                                 ['id' => 203609,
                                  'code_barres' => 1644067,
                                  'id_int_bib' => 1,
                                  'id_origine' => '259517-123',
                                  'data_profile' => $data_profile,
                                  'notice' => $this->fixture('Class_Notice',
                                                             ['id' => 205227,
                                                              'titre_principal' => 'Animan 210',
                                                              'type_doc' => Class_TypeDoc::PERIODIQUE
                                                             ])]);

    $this->jajm = $this->fixture('Class_Users',
                                 ['id' => 1,
                                  'login' => 'jajm',
                                  'password' => 'secret',
                                  'int_bib' => $bib,
                                 ]);

    Class_AdminVar::set('KOHA_MULTI_SITES','1');

    ZendAfi_Auth::getInstance()->logUser($this->jajm);
    $this->koha = Storm_Test_ObjectWrapper::mock();
    $this->koha
      ->whenCalled('getServerRoot')
      ->answers($webservice);

    Class_WebService_SIGB_Koha::setService(['url_serveur' => $webservice,
                                            'id_bib' => 1,
                                            'type' => Class_IntBib::COM_KOHA],
                                           $this->koha);
  }


  protected function dispatchAndCheckContentEquals($expected) {
    $this->dispatch('/recherche/reservationajax/id/205227-123/id_notice/205227-210/id_bib/1/copy_id/203609/code_annexe/VS',
                    true);
    $this->json = json_decode($this->_response->getBody());
    $this->assertEquals($expected, $this->json->content);
  }


  /** @test */
  public function functionGetBibNumberFromIdOrigineShouldReturn259517() {
    $this->assertEquals('259517', $this->_exemplaire->getBibNumberFromIdOrigine());
  }


  /** @test */
  public function withMatchingHoldAndRecordSerialMessageShouldContainsPickupLocationAndRecordTitle() {
    $response = $this->_prepareEmprunteurHolding($this->exemplaire, 'Valensole');
    $expected_message = 'Votre réservation est enregistrée.<br>Nous vous informerons quand le document \'Animan 210\' sera disponible pour être retiré à : Valensole';
    $this->_dispatchWithEmprunteurAndAssertContentEquals($response,
                                                         $expected_message);
  }


  protected function _prepareEmprunteurHolding($item, $pickup_label) {
    $this->jajm->setIdabon(395749);

    $exemplaire = (new Class_WebService_SIGB_Exemplaire(203609))
      ->setExemplaireOPAC($item);
    $hold = new Class_WebService_SIGB_Reservation(2, $exemplaire);
    $hold->setPickupLocationLabel($pickup_label)
         ->setCodeBarre(1644067);

    $emprunteur_jajm = Class_WebService_SIGB_Emprunteur::newInstance(2, 'jajm');
    $emprunteur_jajm->reservationsAdd($hold);
    return $emprunteur_jajm;
  }


  protected function _dispatchWithEmprunteurAndAssertContentEquals($emprunteur, $content) {
    $this->koha
      ->whenCalled('isConnected')->answers(true)
      ->whenCalled('reserverExemplaire')->answers(['statut' => true,
                                                   'erreur' => '',
                                                   'popup' => false])
      ->whenCalled('getEmprunteur')->answers($emprunteur);

    $this->dispatchAndCheckContentEquals($content);
  }
}



class RechercheControllerReservationCalendarAjaxTest extends AbstractControllerTestCase {
  protected
    $_storm_default_to_volatile = true,
    $_json,
    $_xpath;

  public function setUp() {
    parent::setUp();

    $item = $this->fixture('Class_Exemplaire',
                           ['id' => 456,
                            'id_origine' => 1,
                            'annexe' => 'VS']);

    $comm_sigb = $this->mock()
                      ->whenCalled('holdsForItem')
                      ->with($item)
                      ->answers(['statut' => true,
                                 'holds' => [(new Class_WebService_SIGB_Koha_Reservation(3,$item))
                                             ->setReserveDate('2020-01-15')
                                             ->setExpirationDate('2020-06-16'),
                                             (new Class_WebService_SIGB_Koha_Reservation(2,$item))
                                             ->setReserveDate('2019-07-26')
                                             ->setExpirationDate('2019-12-31')]]);

    Class_CommSigb::setInstance($comm_sigb);

    $this->dispatch('/recherche/reservation-calendar-ajax/id_bib/1/copy_id/456/code_annexe/VS',true);
    $this->_json = json_decode($this->_response->getBody());
    $this->_xpath = new Storm_Test_XPath();
  }


  /** @test */
  public function popupHoldsListShouldContainsDu26JuilletAu31Decembre() {
    $this->_xpath->assertXPathContentContains($this->_json->content,
                                              '//ul/li[1]',
                                              utf8_encode('Du 26 juillet 2019 au 31 décembre 2019'));
  }


  /** @test */
  public function popupHoldsListShouldContainsDu15JanvierAu16Juin() {
    $this->_xpath->assertXPathContentContains($this->_json->content,
                                              '//ul/li[2]',
                                              utf8_encode('Du 15 janvier 2020 au 16 juin 2020'));
  }


  /** @test */
  public function formActionShouldBeRechercheReservationCalendarAjax() {
    $this->_xpath->assertXPath($this->_json->content,
                               '//form[@action="/recherche/reservation-calendar-ajax/id_bib/1/copy_id/456/code_annexe/VS"]');
  }


  /** @test */
  public function formCancelButtonShouldCloseDialog() {
    $this->_xpath->assertXPath($this->_json->content,
                               '//button[@value="Annuler"][contains(@onclick, "opacDialogClose()")]');
  }


  /** @test */
  public function formShouldContainsSubmit() {
    $this->_xpath->assertXPath($this->_json->content,
                               '//input[@type="submit"][@value="Valider"]');
  }

  /** @test */
  public function responseShouldContainsInputDatePickerForResevationDate() {
    $this->_xpath->assertXPath($this->_json->content,
                               '//input[@name="reservedate"]');
  }


  /** @test */
  public function responseShouldContainsInputDatePickerForExpirationDate() {
    $this->_xpath->assertXPath($this->_json->content,
                               '//input[@name="expirationdate"]');
  }
}




class RechercheControllerReservationCalendarPostTest extends AbstractControllerTestCase {
  protected
    $_storm_default_to_volatile = true,
    $_comm_sigb;

  public function setUp() {
    parent::setUp();

    $item = $this->fixture('Class_Exemplaire',
                           ['id' => 456,
                            'code_barres' => 123,
                            'id_int_bib' => 1,
                            'notice' => $this->fixture('Class_Notice',
                                                       ['id' => 8890,
                                                        'titre_principal' => 'Elementaire mon cher polar',
                                                        'auteur_principal' => 'Conan Doyle'])]);

    $this->_comm_sigb = $this->mock()
                             ->whenCalled('holdsForItem')
                             ->with($item)
                             ->answers(['statut' => true,
                                        'holds' => []])
                             ->beStrict();

    Class_CommSigb::setInstance($this->_comm_sigb);
  }


  /** @test */
  public function withReserveDateAndExpirationDateShouldNotifyHoldSuccess() {
    $this->_comm_sigb
      ->whenCalled('ficheAbonne')
      ->with(Class_Users::getIdentity())
      ->answers(null)

      ->whenCalled('reserverExemplaire')
      ->with(1,456,'VS','2020-01-19','2020-05-25')
      ->answers(['statut' => true, 'erreur' => '']);

    $this->postDispatch('/recherche/reservation-calendar-ajax/id_bib/1/copy_id/456/code_annexe/VS',
                        ['reservedate' => '19/01/2020' ,
                         'expirationdate' => '25/05/2020']);

    $this->json = json_decode($this->_response->getBody());
    $this->assertContains('Votre réservation est enregistrée',
                          $this->json->content);
  }


  /** @test */
  public function withInvalidReserveDateShouldDisplayErrorReserveDateInvalide() {
    $this->postDispatch('/recherche/reservation-calendar-ajax/id_bib/1/copy_id/456/code_annexe/VS',
                        ['reservedate' => 'pouet' ,
                         'expirationdate' => '25/05/2020']);

    $this->json = json_decode($this->_response->getBody());
    $xpath = new Storm_Test_XPath();

    $xpath->assertXPathContentContains($this->json->content,
                                       '//ul[@class="errors"]/li',
                                       '\'pouet\' ne correspond pas au format de date attendu',
                                       $this->json->content);
  }


  /** @test */
  public function withDurationInferiorToMinimunShouldDisplayErrorDurationTooSmall() {
    $this->_comm_sigb->whenCalled('reserverExemplaire')
                     ->with(1,456,'VS','2020-05-10','2020-05-25')
                     ->answers(['statut' => false,
                                'erreur' => 'Durée minimale requise: 30 jours']);

    $this->postDispatch('/recherche/reservation-calendar-ajax/id_bib/1/copy_id/456/code_annexe/VS',
                        ['reservedate' => '10/05/2020' ,
                         'expirationdate' => '25/05/2020']);

    $this->json = json_decode($this->_response->getBody());
    $xpath = new Storm_Test_XPath();

    $xpath->assertXPathContentContains($this->json->content,
                                       '//ul[@class="errors"]',
                                       'Durée minimale requise: 30 jours');

    $xpath->assertXPath($this->json->content,
                        '//input[@name="reservedate"][@value="10/05/2020"]',
                        $this->json->content);
  }
}




class RechercheControllerReservationWithMailFormTest
  extends AbstractControllerTestCase {

  protected $_storm_default_to_volatile = true;

  public function setUp() {
    parent::setUp();

    $this->fixture('Class_Bib', ['id' => 88,
                                 'libelle' => 'My Library',
                                 'mail' => 'my@library.com']);

    $this->fixture('Class_Notice',
                   ['id' => 550171,
                    'type_doc' => 1,
                    'titre_principal' => 'Test record',
                    'auteur_principal' => 'Test author',
                    'editeur' => 'Test editor',
                   ]);

    $this->dispatch('/recherche/reservation/id/550171/id_int_bib/88/id_bib/88/id_notice/550171/cote/P+TRA', true);
  }


  /** @test */
  public function bibNameShouldBePresentInForm() {
    $this->assertXPath('//input[@type="text"][@disabled][@name="bib_name"][@value="My Library"]');
  }

  /** @test */
  public function shouldContainsUserName() {
    $this->assertXPath('//input[@type="text"][@name="user_name"]');
  }


  /** @test */
  public function shouldContainsMessage() {
    $this->assertXPath('//textarea[@name="demande"]');
  }


  /** @test */
  public function shouldContainsUserMail() {
    $this->assertXPath('//input[@type="email"][@name="user_mail"]');
  }


  /** @test */
  public function shouldContainsCaptcha() {
    $this->assertXPath('//input[@type="text"][@name="code_saisi"]');
  }
}




abstract class RechercheControllerReservationWithMailFormPostTestCase
  extends AbstractControllerTestCase {
  protected
    $_storm_default_to_volatile = true,
    $_mail_transport;

  public function setUp() {
    parent::setUp();

    $this->fixture('Class_Bib', ['id' => 88,
                                 'libelle' => 'My Library',
                                 'mail' => 'my@library.com']);

    $unimarc = (new Class_NoticeUnimarc_Fluent)
      ->zoneWithContent('001', '')
      ->zoneWithChildren('200', [ 'a' => 'Test record'], ' 0')
      ->zoneWithChildren('214', [ 'c' => 'Test editor'], ' 0')
      ->render();

    $this->fixture('Class_Notice',
                   ['id' => 550171,
                    'type_doc' => 1,
                    'auteur_principal' => 'Test author',
                    'unimarc' => $unimarc,
                   ]);

    $_SESSION['captcha_code'] = 'e2df0';

    Zend_Mail::setDefaultTransport($this->_mail_transport = new MockMailTransport());
  }


  protected function postDatas($datas) {
    $this->postDispatch('/recherche/reservation/id/550171/id_int_bib/88/id_bib/88/id_notice/550171/cote/P+TRA',
                        $datas);
  }


  protected function assertElementError($path, $message) {
    $this->assertXPathContentContains($path . '/following-sibling::ul[@class="errors"]/li', $message);
  }
}



class RechercheControllerReservationWithMailFormInvalidPostTest
  extends RechercheControllerReservationWithMailFormPostTestCase{

  /** @test */
  public function withEmptyPostAllFieldsShouldBeRequired() {
    $this->postDatas([]);

    foreach([
             ['//input[@name="user_name"]', 'Une valeur est requise'],
             ['//textarea[@name="demande"]', 'Une valeur est requise'],
             ['//input[@name="user_mail"]', 'Une valeur est requise'],
             ['//input[@name="code_saisi"]', 'Une valeur est requise'],
             ] as $case) {
      list($path, $message) = $case;
      $this->assertElementError($path, $message);
    }
  }


  /** @test */
  public function withBadMailShouldDisplayInvalidMail() {
    $this->postDatas(['user_mail' => 'bad mail address']);
    $this->assertElementError('//input[@name="user_mail"]', 'n\'est pas un email valide');
  }


  /** @test */
  public function withBadCaptchaShouldDisplayInvalidCaptchaHaveEmptyValue() {
    $this->postDatas(['code_saisi' => 'bad captcha code']);
    $this->assertElementError('//input[@name="code_saisi"][@value=""]',
                              'Le code anti-spam est incorrect');
  }
}




class RechercheControllerReservationWithMailFormValidPostTest
  extends RechercheControllerReservationWithMailFormPostTestCase{

  protected $_mails;

  public function setUp() {
    parent::setUp();

    Class_AdminVar::set('TEXTE_MAIL_RESA', 'Thanks for your hold');

    $this->postDatas(['user_name' => 'Testing user',
                      'demande' => 'testing demande',
                      'user_mail' => 'test@server.com',
                      'code_saisi' => 'e2df0']);

    $this->_mails = $this->_mail_transport->getSentMails();
  }


  protected function assertMailBodyContains($needle, $mail) {
    $this->assertContains($needle, quoted_printable_decode($mail->getBodyText(true)));
  }


  /** @test */
  public function validFormShouldSendTwoMails() {
    $this->assertCount(2, $this->_mails);
  }

  /** @test */
  public function mailsShouldHaveHoldQuerySubject() {
    foreach($this->_mails as $mail)
      $this->assertContains('Demande de réservation de document',
                            quoted_printable_decode($mail->getSubject()));
  }


  /** @test */
  public function firstMailRecipientShouldBeLibrary() {
    $this->assertContains('my@library.com', $this->_mails[0]->getRecipients());
  }


  /** @test */
  public function firstMailFromShouldBeUser() {
    $this->assertEquals('test@server.com', $this->_mails[0]->getFrom());
  }


  /** @test */
  public function firstMailBodyShouldContainsUserName() {
    $this->assertMailBodyContains('Testing user', $this->_mails[0]);
  }


  /** @test */
  public function firstMailBodyShouldContainsRecordInfo() {
    foreach(['Test record', 'P TRA', 'Test author', 'Test editor'] as $info)
      $this->assertMailBodyContains($info, $this->_mails[0]);
  }


  /** @test */
  public function firstMailBodyShouldUserMessage() {
    $this->assertMailBodyContains('testing demande', $this->_mails[0]);
  }


  /** @test */
  public function secondMailRecipientShouldBeUser() {
    $this->assertContains('test@server.com', $this->_mails[1]->getRecipients());
  }


  /** @test */
  public function secondMailFromShouldBeNobody() {
    $this->assertEquals('nobody@noreply.fr', $this->_mails[1]->getFrom());
  }


  /** @test */
  public function secondMailBodyShouldContainsTexteMailResa() {
    $this->assertMailBodyContains('Thanks for your hold', $this->_mails[1]);
  }


  /** @test */
  public function shouldRedirectToRecordView() {
    $this->assertRedirectTo('/opac/recherche/viewnotice/id/550171?type_doc=1');
  }
}



abstract class RechercheControllerReservationPickupAjaxWithNanookPickupLocationsTestCase
  extends RechercheControllerReservationTestCase{

  public function setUp() {
    parent::setUp();

    $bib = $this
      ->fixture('Class_IntBib',
                ['id' => 12,
                 'comm_sigb' => Class_IntBib::COM_NANOOK,
                 'comm_params' => ['url_serveur' => 'http://bib.valensol.net']]);

    $this->jajm = $this->fixture('Class_Users',
                                 ['id' => 1,
                                  'login' => 'jajm',
                                  'password' => 'secret',
                                  'idabon' => '0000007',
                                  'int_bib' => $bib]);

    $this->nanook = $this->mock()
      ->whenCalled('isConnected')->answers(true)
      ->whenCalled('providesPickupLocations')->answers(true)

      ->whenCalled('pickupLocationsFor')
      ->answers(['36' => 'Annecy',
                 '37' => 'Cran',
                 '45' => 'Istres',
                 '99' => 'Lunel <strong>(Disponible)</strong>']);

    Class_WebService_SIGB_Nanook::setService(['url_serveur' => 'http://bib.valensol.net',
                                              'id_bib' => 12,
                                              'type' => Class_IntBib::COM_NANOOK,],
                                             $this->nanook);

    ZendAfi_Auth::getInstance()->logUser($this->jajm);

    $this->fixture('Class_Exemplaire', ['id' => 12]);
  }


  public function choices() {
    return [[36], [37], [45]];
  }


  /**
   * @test
   * @dataProvider choices
   */
  public function choiceShouldBePresent($location_id) {
    $this->_xpath
      ->assertXPath($this->_json->content,
                    '//input[@type="radio"][@value="' . $location_id . '"]');
  }
}




class RechercheControllerReservationPickupAjaxNanookPickupLocationsPrecheckPatronTest
  extends RechercheControllerReservationPickupAjaxWithNanookPickupLocationsTestCase {

  public function setUp() {
    parent::setUp();

    $this->nanook->whenCalled('getUserAnnexe')->answers('45');

    $this->dispatch('recherche/reservation-pickup-ajax?id_bib=2&id_origine=12&code_annexe=37&copy_id=12', true);

    $this->_json = json_decode($this->_response->getBody());
  }


  /** @test */
  public function istresShouldBeChecked() {
    $this->_xpath
      ->assertXPath($this->_json->content, '//input[@type="radio"][@value="45"][@checked]');
  }
}




class RechercheControllerReservationPickupAjaxNanookPickupLocationsPrecheckRequestedTest
  extends RechercheControllerReservationPickupAjaxWithNanookPickupLocationsTestCase {

  public function setUp() {
    parent::setUp();

    $this->nanook->whenCalled('getUserAnnexe')->answers('66');

    $this->dispatch('recherche/reservation-pickup-ajax?id_bib=2&id_origine=12&code_annexe=37&copy_id=12', true);

    $this->_json = json_decode($this->_response->getBody());
  }


  /** @test */
  public function cranShouldBeChecked() {
    $this->_xpath
      ->assertXPath($this->_json->content, '//input[@type="radio"][@value="37"][@checked]');
  }
}




class RechercheControllerReservationPickupAjaxNanookPickupLocationsNoPrecheckTest
  extends RechercheControllerReservationPickupAjaxWithNanookPickupLocationsTestCase {

  public function setUp() {
    parent::setUp();

    $this->nanook->whenCalled('getUserAnnexe')->answers('66');

    $this->dispatch('recherche/reservation-pickup-ajax?id_bib=2&id_origine=12&code_annexe=77&copy_id=12', true);

    $this->_json = json_decode($this->_response->getBody());
  }


  /**
   *   @test
   *   @see https://forge.afi-sa.net/issues/128814
   */
  public function noSiteShouldBePreChecked() {
    $this->_xpath
      ->assertNotXPath($this->_json->content, '//input[@type="radio"][@checked]');
  }
}




class RechercheControllerReservationPickupAjaxNanookPickupLocationsStrongInLabel
  extends RechercheControllerReservationPickupAjaxWithNanookPickupLocationsTestCase {

  public function setUp() {
    parent::setUp();

    $this->nanook->whenCalled('getUserAnnexe')->answers('66');

    $this->dispatch('recherche/reservation-pickup-ajax?id_bib=2&id_origine=12&code_annexe=99&copy_id=12', true);

    $this->_json = json_decode($this->_response->getBody());
  }


  /**
    @see https://forge.afi-sa.net/issues/94332
    @test
  */
  public function LunelShouldContainStrong() {
    $this->_xpath
      ->assertXPath($this->_json->content, '//strong',$this->_json->content);
  }
}




class RechercheControllerReservationPickupAjaxAndNotifyByMailEnabledTest
  extends RechercheControllerReservationWithPickupChoiceTestCase {

  protected $_sent_mails = [];

  public function setUp() {
    parent::setUp();

    Class_Profil::getCurrentProfil()->setMailSite('admin@example.com');

    $int_bib = $this
      ->fixture('Class_IntBib',
                ['id' => 1,
                 'comm_sigb' => Class_IntBib::COM_KOHA,
                 'use_card_number' => 12345,
                 'comm_params' => ['url_serveur' => 'http://bib.valensol.net/cgi-bin/koha/ilsdi.pl']]);

    $bib = $this->fixture('Class_Bib',
                          ['id' => 1,
                           'notify_on_new_resa' => 1,
                           'mail'=>'adminpukapuka@example.com',
                           'int_bib' => $int_bib]);
    $this->fixture(Class_CodifAnnexe::class,
                   ['id' => 34,
                    'libelle'=>'BDM',
                    'id_origine' => 23]);

    $this->jajm = $this
      ->fixture('Class_Users',
                ['id' => 1,
                 'login' => 'jajm',
                 'password' => 'secret',
                 'nom'    => 'Monsieur',
                 'prenom' => 'Julian',
                 'idabon' => '00004',
                 'int_bib' => $int_bib,
                 'id_sigb' =>'0000007',
                 'bib' => $bib
                ]);

    $this->mock = Storm_Test_ObjectWrapper::mock()
      ->whenCalled('isConnected')->answers(true)
      ->whenCalled('open_url')
      ->with('http://bib.valensol.net/cgi-bin/koha/ilsdi.pl?service=HoldTitle&patron_id=0000007&bib_id=13&request_location=127.0.0.1&pickup_location=23')
      ->answers('<HoldTitle>
                                   <title>Mireille l\'abeille</title>
                                   <pickup_location>Bibliothèque Départementale de la Meuse</pickup_location>
                                 </HoldTitle>')
      ->whenCalled('reserverExemplaire')->answers(['statut'=>true,'erreur'=>'']);

    Class_WebService_SIGB_Koha::setService(['url_serveur' => 'http://bib.valensol.net/cgi-bin/koha/ilsdi.pl',
                                            'id_bib' => 1,
                                            'type' => Class_IntBib::COM_KOHA,],
                                           $this->mock);

    ZendAfi_Auth::getInstance()->logUser($this->jajm);

    $this->fixture('Class_Exemplaire', ['id' => 12,
                                        'id_origine' =>13,
                                        'code_barres' =>12341,
                                        'notice'=> $this->fixture('Class_Notice',
                                                                  ['id'=>54,
                                                                   'titre_principal' => "Mireille l'Abeille",
                                                                   'type_doc' => Class_TypeDoc::LIVRE])
                                        ]);

    $mock_transport = new MockMailTransport();
    Zend_Mail::setDefaultTransport($mock_transport);

    $this->dispatch('recherche/reservationajax/id/11760/id_int_bib/23/id_bib/23/id_origine/594105/code_annexe/23/render/popup/copy_id/12', true);

    $this->_sent_mails = $mock_transport->getSentMails();
  }


  /** @test */
  public function parameterCodeAnnexeShouldBeUsedForReservation() {
    $this->assertEquals('23',
                        $this->mock->getAttributesForLastCallOn('reserverExemplaire')[2]);
  }


  /** @test */
  public function mailShouldHaveBeenSent() {
    $this->assertEquals(1, count($this->_sent_mails));
  }


  /** @test */
  public function mailSubjectShouldContainsJulianMonsieurSurExemplaire12341() {
    $this->assertContains("Julian Monsieur ? =?utf-8?Q?sur l'exemplaire 12341",
                          quoted_printable_decode(current($this->_sent_mails)->getSubject()));
  }


  /** @test */
  public function mailToShouldBeAdminPukaPukaAtExampleDotCom() {
    $this->assertContains("adminpukapuka@example.com",current($this->_sent_mails)->getRecipients()[0]);
  }


  /** @test */
  public function mailFromShouldBeMailAdminAtExampleDotCom() {
    $this->assertContains("admin@example.com",current($this->_sent_mails)->getFrom());
  }


  public function expectedData() {
    return [['Titre : Mireille l\'Abeille'],
            ['Annexe de retrait : BDM'],
            ['Julian Monsieur 00004'],
            ['Code Barre : 12341'],
            ['Type de Document : Livres'],
    ];
  }


  /**
   * @test
   * @dataProvider expectedData
   */
  public function mailBodyShouldContainsContent($content) {
    $this->assertContains($content,quoted_printable_decode(current($this->_sent_mails)->getBodyHtml(true)));
  }
}




require_once 'tests/fixtures/KohaFixtures.php';

class RechercheControllerReservationWithWebServiceKohaAndItypesTest
  extends AbstractControllerTestCase {

  protected $_xpath;

  public function setUp() {
    parent::setUp();

    Class_WebService_SIGB_AbstractRESTService::shouldThrowError(true);

    $koha_service_params = ['url_serveur' => 'http://bib.valensol.net',
                            'grouped_holds_itypes' => " PRET_MALLE
 OUT
PRET_GLACIERE
PRET_VALISE",
                            'bundled_holds_minimal_duration' => 30,
                            'bundled_holds_maximal_duration' => 60,
                            'id_bib' => 1,
                            'type' => 5];

    $bib = $this->fixture('Class_IntBib',
                          ['id' => 1,
                           'comm_sigb' => Class_IntBib::COM_KOHA,
                           'comm_params' => $koha_service_params]);

    $http_client = $this
      ->mock()

      ->whenCalled('open_url')
      ->with('http://bib.valensol.net?service=GetRecords&id=678')
      ->answers(KohaFixtures::getRecordsWithGroupHoldsItypes())

      ->beStrict();

    Class_WebService_SIGB_Koha::getService($koha_service_params)
      ->setWebClient($http_client);

    $record =
      $this->fixture(Class_Notice::class,
                     ['id' => 8890,
                      'titre_principal' => 'Elementaire mon cher polar',
                      'auteur_principal' => 'Conan Doyle']);

    $this->fixture(Class_Exemplaire::class,
                   ['id' => 456,
                    'id_origine' => 678,
                    'code_barres' => 5360246264,
                    'id_int_bib' => 1,
                    'notice' => $record]);

    $this->fixture(Class_CodifAnnexe::class,
                   ['id' => 3,
                    'code' => 'VS',
                    'id_origine' => 'VS',
                    'libelle' => 'Cran',
                    'no_pickup' => '0']);

    $this->fixture(Class_CodifAnnexe::class,
                   ['id' => 4,
                    'code' => 'AN',
                    'id_origine' => 'AN',
                    'libelle' => 'Annecy',
                    'no_pickup' => '0']);

    Class_CosmoVar::setValueOf('site_retrait_resa', 1);

    $user = $this->fixture('Class_Users',
                           ['id' => 1,
                            'login' => 'jajm',
                            'password' => 'secret',
                            'int_bib' => $bib,
                            'id_site' => 3,
                            'idabon' => '395749'
                           ]);
    $this->_xpath = new Storm_Test_XPath();
    ZendAfi_Auth::getInstance()->logUser($user);
  }


  /** @test */
  public function reservationShouldSelectUserAnnexeByDefault() {
    $emprunteur = new Class_WebService_SIGB_Emprunteur('395749', 'jajm');
    $emprunteur->setLibraryCode('VS');
    Class_CommSigb::setInstance($this->mock()
                                ->whenCalled('ficheAbonne')
                                ->answers(['fiche' => $emprunteur]));


    $this->dispatch('/recherche/reservation-pickup-ajax/id_bib/1/copy_id/456/code_annexe/AN');
    $json = json_decode($this->_response->getBody());
    $this->_xpath
     ->assertXPath($json->content, '//input[@type="radio"][@name="code_annexe"][ @value="VS"][ @checked="checked"]', $json->content);
  }


  /** @test */
  public function reservationAjaxWithItemRequiringCalendarHoldShouldRedirectToReservationCalendarAjaxWithoutException() {
    $this->postDispatch('/recherche/reservation-pickup-ajax/id_bib/1/copy_id/456/code_annexe/VS',
                        ['code_annexe' => 'VS']);

    $this->assertRedirectTo('/recherche/reservationajax/id_bib/1/copy_id/456/code_annexe/VS');
  }


  /** @test */
  public function dispatchReservationajaxShouldRenderCalendar() {
    $this->dispatch('/recherche/reservationajax/id_bib/1/copy_id/456/code_annexe/VS');
    $this->assertRedirectTo('/recherche/reservation-calendar-ajax/id_bib/1/copy_id/456/code_annexe/VS');
  }
}