Testování formuláře – simulace odeslání

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Casper
Člen | 253
+
0
-

Zdravím, snažím se nasimulovat odeslání formuláře, ale po „odeslání“ z formuláře nic nedostanu, dokonce ani metoda onSuccess[] se vůbec nezavolá. Dělám něco špatně?

Testovací presenter obsahuje pouze metodu renderDefault s odesláním TextResponse.

public function testSubmitted(){

	$request = new \Nette\Application\Request("Test", 'POST', array(
		"action" => "default",
		"do" => "contactForm-submit",
	), array(
		"name" => "John",
		"email" => "example@gmail.com",
		"subject" => "Testing",
		"content" => "Well...",
	));

	$presenterFactory = $this->container->getByType('Nette\Application\IPresenterFactory');
	$formFactory = $this->container->getByType('Forms\IContactFormFactory');

	$presenter = $presenterFactory->createPresenter('Test');
	$form = $formFactory->create();

	$presenter->addComponent($form, "contactForm");
	$presenter->run($request);

	var_dump($form->getErrors()); // prázdné
	var_dump($form->getValues()); // všechny hodnoty jsou NULL
}

Jedu na Nette 2.1dev

llook
Člen | 407
+
0
-

No jasně, request se předá formuláři, který si vytváří sám presenter (nejspíš metodou createComponentContactForm()) a potom testuješ úplně jiný formulář (jinou instanci), kterou si vytvoříš v testu. Zkus to takhle:

var_dump($presenter['contactForm']->getValues());
Casper
Člen | 253
+
0
-

Ten presenter je jen testovací, žádné továrničky v něm nejsou:

class TestPresenter extends \Nette\Application\UI\Presenter {
    public function renderDefault(){
        $this->sendResponse(new Nette\Application\Responses\TextResponse("ok"));
    }
}
vvoody
Člen | 910
+
0
-

Bez továrničky si ten signál nenájde cestu k tomu formu.

David Matějka
Moderator | 6445
+
0
-

myslim, ze pritomnost tovarnicky nehraje roli. ten formular je pripojenej pres addComponent, coz by melo byt dostacujici.. chyba bude tedy asi jinde

ted me napada, nevim presne jak to je, ale nemenilo se nejak, ze do parametr se u formularu posila v post?

Editoval matej21 (16. 10. 2013 20:26)

llook
Člen | 407
+
0
-

A jo, to addComponent jsem přehlídl. Tak bych hodil breakpoint do Presenter::run() a odkrokoval bych si to.

Casper
Člen | 253
+
0
-

Tak jsem si to odkrokoval a v metodě fireEvents při volání isSubmitted() je submittedBy FALSE, nikoli NULL a proto se nenačtou http data.

final public function isSubmitted(){
	if ($this->submittedBy === NULL) {
		$this->getHttpData();
	}
	return $this->submittedBy;
}

To bude asi ta příčina, protože díky tomu to z metody fireEvents vyskočí hned ven. Nicméně manuální nastavení setSubmittedBy na odesílací button nebo na NULL mi nepomohlo. Aneb při nastavení odesílací tlačítko, dostanu chyby ze všech required inputů, protože se nepřijmou žádná httpData. A na NULL to nastavit nelze díky setteru:

public function setSubmittedBy(ISubmitterControl $by = NULL){
	$this->submittedBy = $by === NULL ? FALSE : $by;
	return $this;
}

Co bych měl tedy udělat, aby se toto zjišťovalo korektně?

P.S. parametr do se skutečně odesílá v POSTu, nicméně to problém neřeší :)

David Matějka
Moderator | 6445
+
0
-

zkus do POST pridat jeste odesilaci tlacitko

Casper
Člen | 253
+
0
-

@matej21:

zkus do POST pridat jeste odesilaci tlacitko

To už jsem zkoušel, bohužel bezúspěšně :/

Casper
Člen | 253
+
0
-

Tak jsem na to kápnul, submittedBy bylo FALSE protože již při volání addComponent se volá getHttpData a ty v tu chvíli nejsou k dispozici, takže se nastaví na FALSE. Řešením je tedy nějaký vlastní callback pro připojení komponent v presenteru.

$presenter = $presenterFactory->createPresenter('Test');
$presenter->onStartup[] = function($thePresenter) use ($form) {
	$thePresenter->addComponent($form, "contactForm");
};
$response = $presenter->run($request);
vvoody
Člen | 910
+
0
-

Alebo neznásilňovať nette a napísať továrničku do presenteru miesto volanie addComponent pred run. ;)

llook
Člen | 407
+
0
-

vvoody napsal(a):

Alebo neznásilňovať nette a napísať továrničku do presenteru miesto volanie addComponent pred run. ;)

Tohle není znásilňování Nette, tohle je testování samotné komponenty bez nějakého konkrétního presenteru (protože komponenta je na konkrétním presenteru nezávislá). Řešení přes onStartup mi přijde velmi dobré.

vvoody
Člen | 910
+
0
-

Nie som do testovania nejaký odborník ale myslím že jeho pointa je nasimulovať najreálnejšie podmienky. Rozdiel medzi onStartup riešením a napísaním si vlastného presenteru s továrničkou je ten, že componenta je vytvorená v rozdielnych častiach životného cyklu presenteru čo by mohlo viesť k neodhaleniu určitých problémov.

llook
Člen | 407
+
0
-

To je pravda. Pak to lze teda dělat ještě takto:

class TestPresenter extends \Nette\Application\UI\Presenter
{
	public $componentFactories = array();

	protected function createComponent($name)
	{
		if (isset($this->componentFactories[$name]))
		{
			return $this->componentFactories[$name]($this, $name);
		}
		return parent::createComponent($name);
	}
}

...

$presenter = $presenterFactory->createPresenter('Test');
$presenter->componentFactories['contactForm'] = function() use ($form) {
	return $form;
};