Chapter 13. Handling of dynamic data

Table of Contents

13.1. Submitting the correct form data
13.1.1. Extracting the jsessionid-parameter
13.1.2. Generating the request dynamically
13.1.3. Conclusion

In the previous chapter, a test case was built from a recording, and in both setups, i.e. with a simulated and a real setup, the test was successful. But this test case does only check the status codes of the returned pages, and the communication of the participants in the test case is defined statically and does not adapt to the real communication. E.g. if a server reply contains a session ID, that should be further used by the client, the client does not use this ID for the future communication but it uses the session ID that was transmitted at the creation of the test case.

For advanced applications this behavior is not sufficient. This chapter gives an idea how test cases, that have been made with a recording, can be modified so that the dynamic data of the communication is used, and the test case becomes more useful.

In this chapter the test case that was built in the previous chapter will be used.

Let's change the test case and look what's happening to visualize that the test case we have until now is not very useful. The sent password will be altered, and the expected result will be a failure, because the search site of the hotel booking application is not reached.

To change the sent password, open the template 0002-Request in the folder generated/bookingExampleLoginTest and edit it. The file might appear empty in the design view because the file does not contain XML code, but the content of the file becomes visible in the Source tab of the XML editor.

Figure 13.1. Changing the sent password

Changing the sent password


The sent request is hard to read, but the right place of the password can be found when searching the string password= in the template. Change the value of the string, save and rerun the test case.

The test case does not fail, as expected. To explain this behavior the third request/response pair of the generated test case can be examined:

Figure 13.2.  The fourth request/response pair of the test case

The fourth request/response pair of the test case


It can be seen that the only assertion in the 0003-Check event asserts that the status of the returned site is OK (200). And this is the case, even if the login page and not the hotel search page is returned.

To ensure that the main page of the application is displayed, an additional assertion must be added that tests if the correct page is sent. An easy way to test this could be checking if the text "Search Hotels" can be found in the returned web site. This must be done at the event 0003-Check. The returned web site is a HTML site, so for further processing it is necessary to make the returned site XML compliant. This can be done with help of the predefined filter HTMLCompletion. Add this filter by dragging the Add Inputfilter() button to the event 0003-Check, selecting the filter HTMLCompletion and pressing the OK button.

[Note]HTMLCompletion

HTML as opposed to XHTML is not well-formed XML and therefore not a valid XML document. This filter manipulates the document it receives in a way that the resulting document will be well-formed XML (e.g. by completion of non-closed element tags).

Figure 13.3.  Adding the HTMLCompletion filter

Adding the HTMLCompletion filter


Now it can be asserted that the returned page contains the string "Search Hotels". In this example it is sufficient to test if the returned page contains a node that contains the text "Search Hotels". This can be asserted if the XPath expression //*[contains(.,"Search Hotels")] has a result.

Now add the assertion:

  1. Drag the Add Assertion() button to the event 0003-Check

  2. Name the assertion isSearchHotelPage

  3. Choose the exits operator

  4. Choose String for the data type

  5. Press Add Document in the left column of the dialog

  6. Select the Path argument and then set it to //*[contains(.,"Search Hotels")] by pressing Add Constant and specifying the expression.

  7. Press OK

Figure 13.4.  Assert that the Search Hotels page is reached

Assert that the Search Hotels page is reached


The assertion should now look like in Figure 13.5, “ The assertion in the event ”

Figure 13.5.  The assertion in the event

The assertion in the event


Now rerun the test case. The result is still a successful test run, although the password for the login is still set wrong.

To explain this behavior the test case must be examined further. Take a look at the event that performs the sending of the login data, i.e. 0002-Request. This request does not request the main page of the application, that contains the search form, as expected. It sends the login data to the login page itself. The server replies with a redirect to the main page, which is the search page.

Figure 13.6.  The fourth request/response Pair

The fourth request/response Pair


As an experiment, open a browser window and try to load the page to which the server redirects. The full address of this page can be found in the redirect parameter of the protocol of the redirecting event, i.e. 0002-Response. Copy the full URL (with the query parameter) to the location bar of the browser. The browser will display the main page, but there is no user logged in.

This behavior is related with the query parameter conversationId. This ID is used by JBoss Seam to determine which page is sent back.

Examining the request following the redirect makes clear why the server responds always in the same way: The conversation header parameter of the request's protocol is set to a fixed value. To treat the server's redirects in the right way, the conversationId parameter must be saved from the redirect and than used in the next request.

The saving of the conversationId must be done multiple times in this test case. To avoid duplicate code the saving of the conversationId will be done in a module, that can be inserted at the appropriate places at the test case:

  1. Create a module called handleRedirect

  2. Add the actor Client to the module, using the Actor setup dialog in the context menu

  3. Drag the Add Event() button to the lifeline of the Client actor, and name the event handleRedirect

Figure 13.7.  The handleRedirect module

The handleRedirect module


First the value of the request parameter must be saved. The complete URL of the redirect is stored in the context _peta/transport/header/location. The conversationId parameter will be fetched from the URL with the predefined plug-in ExtractQueryParameterFromURL. Do this by performing the following steps:

  1. Add a new context to the event handleRedirect by dragging the Add Context() button to the event

  2. Name the new context variable conversation

  3. Add the plug-in ExtractQueryParameterFromURL

  4. Set the URL argument to a reference to the context variable _peta/transport/header/location

  5. Set the key argument to conversationId

Figure 13.8.  Extract the conversationId

Extract the conversationId


Although the path that is returned by the redirect never changes, it should be treated correctly. Do this with the following steps:

  1. Add an other context, and name it path

  2. To extract the path from an URL, the plug-in ExtractPathFromURL is predefined. Add this plug-in.

  3. Set the URL argument to a reference to the context variable _peta/transport/header/location

Figure 13.9.  Extract the path

Extract the path


The module created in the last step can be now used in the test case: Insert the module after each redirect, i.e. after the events 0002-Check and 0004-Check.

Figure 13.10.  The complete test case

The complete test case


Now, all parameters that are necessary to perform the redirect are known, so the requests following the redirects can be modified in a way that they request the correct page:

  1. Expand event 0003-Request

  2. Double click on the protocol to edit its properties

  3. Change the constant value of the argument query/conversationId to a reference to the context variable conversation

  4. Change the constant value of the argument path to a reference to the context variable path

Figure 13.11.  Using the context variables in the request

Using the context variables in the request


As there is an other redirect in event 0004-Response, repeat the last steps for event 0005-Response.

Now, the test case is ready to be run. Click the Run ( ) button in the toolbar to rerun the test case. As expected, the test case fails. Now change the password in the template 0002-Request back to the correct value and run the test case again. It will succeed.

The test case works now correctly, but there is still one flaw: The session ID, that is transmitted in the requests, e.g. in 0002-Request is not changed dynamically but is set to a fixed value. Although in this case the test case works correct, this may lead to problems.

13.1. Submitting the correct form data

Event 0001-Request requests the login form of the web application. This is sent back and in the next event the client sends a request with method post and the data that was filled in the form in the body of the message.

Now, let's examine the form that is sent by the server. Open the template 0001-Response. It contains the HTML code of the login that is displayed by the browser. The page contains a form. All the data that was entered in the form will be committed to the server in the next request of the client. The way how the data is committed is defined with the attributes method and action of the form element. The method attribute defines, as it name says, the method that is used to commit the data, i.e. get or post. In this example the method is set to post, i.e. the data will be sent in the body of the request. The action attribute defines the URI where to send the data. The URI may just consist of a path. In this case the server to whom the last request was sent should be addressed in the next request. If the path is relative, the path relative to the last requested path should be used. In this example the action attribute is set to /home.seam;jsessionid=A98F7477D17A1CB712D1A73B9ABE68ED , i.e. URI /home.seam is addressed on the server that was addressed in the preceding event. The stuff behind the ; is called the parameter.

The parameter changes every time the form is requested. This can be seen in the log, when the test case is run multiple times and the log level in the launch configuration is set to debug. Consult Chapter 6, Create a launch configuration for details on how the log level is set in a launch configuration. But the generated test case always sends requests with the jsessionid that was correct at the recording time. This can be seen in the log file and in the template 0002-Request.

In the following it will be shown how the jsessionid parameter can be extracted from the form and how it can be sent in the body of the next request to the server.

13.1.1. Extracting the jsessionid-parameter

As a first step, the action attribute of the form element will be extracted from the last sent document. Then the value of the jsessionid parameter will be extracted from the complete value of the action string. Here we don't have a predefined plug-in to do that, so the value has to be extracted by hand. If this has to be done often, it might be taken to account to build a new plug-in that accomplishes this task, because in this way it is easier to reuse but more laborious. So, for this example the built-in Eval-plug-in will be used. This plug-in can be utilized to evaluate simple expressions.

In the last step the template 0002-Request will be replaced by a filter that creates the request body dynamically.

So let's go to work: First extract the action attribute from the last received document. The action attribute is part of the form element, which is part of the body of a file with root element html. So the action attribute can be easy found with the XPath expression /html/body/form/@action. Create a context variable called action that stores the variable:

  1. To make the test case more clear, the extraction of the jsessionid string will be put in a single event. Therefore drag the Add Event() button to the lifeline of the client, below the event 0001-Check and name the event getSessionID.

    Figure 13.12.  The getSessionID Event

    The getSessionID Event


  2. Add a context by dragging the Add Context() button to the event we have just created and name it action.

  3. We want to access the last received document, so press the Add Document button.

  4. Select the path argument, press Add Constant… and enter /html/body/form/@action to assign the value of the action attribute to the context variable action.

    Figure 13.13.  Get the action from the form element

    Get the action from the form element


Now, the value of the action attribute of the form can be accessed through the action context variable.

Figure 13.14.  The event with the action context

The event with the action context


The following step will be more complicated. First the position of the string jsessionid= must be found. This is done by evaluating the function lastIndexOf with the Eval-plug-in.

[Note]The Eval-plug-in

The Eval-plug-in is a plug-in that is designed to evaluate simple expressions "on the fly" if writing a new plug-in is too costly. It provides many arithmetical, string and boolean operators, which are mostly similar to their equal named java counterparts. Consult the PETA-Core Reference Manual for a complete list of the available functions.

A defined variable can be referenced in the expression to evaluate with the syntax #{<variable-name>}

The variables are defined with the help of keyed parameters. These parameters can be, depending on their type, number, string or boolean. The keys of the parameters are the variable names that can be referenced in the evaluation expression.

The Eval-plug-in can transform the returned value, depending on its data type to a correct string. This is specified by using the argument returnType of the plug-in. The return type can be number, string or boolean.

For further information about the Eval-plug-in, consult the PETA-Core Reference Manual.

For the position of the jsessionid value in the action string, a new context variable will be defined:

  1. Drag the Add Context() button to the event getSessionID, beneath the definition of the action context variable. And name the new context indexOfSessionID.

  2. Add the Eval-plug-in by pressing Add plug-in button.

  3. Enter an expression that computes the position of the jsessionid string, e.g. lastIndexOf(#{action},'jsessionid=',length(#{action})) . The lastIndexOf(String s, String str, int fromIndex) function returns the position of the string str in the string s searching from the position fromIndex. The length function returns the length of a string.

    Figure 13.15.  The expression for getting the sessionid

    The expression for getting the sessionid


  4. Now the variable action must be passed to the Eval-plug-in. To do this

    1. Select the Eval-plug-in

    2. Press Add Argument

    3. Select string and press OK

    4. Enter action as key and press the OK button.

    5. Select the string argument and press Add Reference…

    6. Enter action as key or select the action context variable in the assisting dialog that is shown if Browse… has been pressed.

    Figure 13.16.  The definition of the action variable

    The definition of the action variable


  5. Fianlly the return type must be specified. To do this

    1. Select the Eval-plug-in and press Add Argument…

    2. Select the returnType argument and press OK

    3. Select the returnType's value, press Add Constant… and enter number for the value. This lets the plug-in return the result in a sensible format for numbers.

    Figure 13.17.  The definition of the returnType

    The definition of the returnType


Figure 13.18.  The event with the indexOfSessionID context variable

The event with the indexOfSessionID context variable


We have now the position of the jsessionid parameter in the URI of the action attribute of the received form. With the help of this, the value of the jsessionid parameter can be taken from the URI. This will be done again with the Eval-plug-in.

The value will be stored in a new context variable named jsessionID.

  1. To add the context variable drag the Add Context() button to the event getSessionID below the context variable definition indexOfSessionID.

  2. Name the context variable sessionID

  3. Add the Eval-plug-in by pressing Add Plug-in… and selecting the Eval-plug-in

  4. Select the argument expression and press Add Constant…. Enter substring(#{action}, #{indexOfSessionID}, length(#{action})) as value and press OK. The substring(String s, int begin, int end) does the same as its Java counterpart: It returns a substring of s that begins with the index begin and ends with the index end.

    Figure 13.19.  Definition of the sessionID context variable with the expression

    Definition of the sessionID context variable with the expression


  5. The expression contains two variables, i.e, #{action} and #{indexOfSessionID}. These variables must be assigned by a parameter.

    1. First assign the context variable action to the #{action} variable in the Eval expression. This is done with the same steps as above:

      Select the Eval-plug-in press Add Argument… select string and press OK then enter action as key and press OK.

      Select the new argument, and press Add Reference…. Enter action as key and press OK .

      Figure 13.20.  Definition of the sessionID context variable with assignment of the action variable

      Definition of the sessionID context variable with assignment of the action variable


    2. Next the context variable indexOfSessionID will be assigned to the second variable #{indexOfSessionID} #{indexOfSessionID}: This will be done as for the variable #{action} with the difference that the indexOfSessionID context variable should be interpreted as a number and not as a string. So the argument that passes the context variable to the Eval expression must be in this case a number.

      Select the Eval plug-in, press Add Argument… select number and press OK then enter indexOfSessionID and press OK.

      Next select the argument indexOfSessionID and press Add Reference…, enter indexOfSessionID and press OK.

    Figure 13.21.  Definition of the sessionID context variable with assignment of the indexOfSessionID variable

    Definition of the sessionID context variable with assignment of the indexOfSessionID variable


  6. The expected value of the substring function is a string, so the returnType argument must be set to string. To do this, select the Eval-plug in, press Add Argument… select the returnType argument. Press OK and select the returnType argument, press Add Constant and enter string.

    Figure 13.22.  Definition of the sessionID context variable with definition of the returnType

    Definition of the sessionID context variable with definition of the returnType


Now the sessionid parameter will be stored in the context variable sessionID.

Figure 13.23.  The complete event for extracting the session ID

The complete event for extracting the session ID


Example 13.1, “Extracting the session ID” shows how the generated XML code of the event should look like.

Example 13.1. Extracting the session ID

  ...
  <event actor="Client" name="getSessionID">
    <context key="action">
      <document>
        <path>
          <constant value="/html/body/form/@action"/>
        </path>
      </document>
    </context>
    <context key="indexOfSessionID">
      <plugin name="Eval">
        <argument name="expression">
          <constant value="lastIndexOf(#{action},'jsessionid=',length(#{action}))"/>
        </argument>
        <argument key="action" name="string">
          <reference key="action"/>
        </argument>
        <argument name="returnType">
          <constant value="number"/>
        </argument>
      </plugin>
    </context>
    <context key="sessionID">
      <plugin name="Eval">
        <argument name="expression">
          <constant value="substring(#{action}, #{indexOfSessionID}, length(#{action}))"/>
        </argument>
        <argument key="action" name="string">
          <reference key="action"/>
        </argument>
        <argument key="indexOfSessionID" name="number">
          <reference key="indexOfSessionID"/>
        </argument>
        <argument name="returnType">
          <constant value="string"/>
        </argument>
      </plugin>
    </context>
  </event>
  ...


13.1.2. Generating the request dynamically

In the next step, the body with the data that was entered into the form plus the data that was in hidden elements of the form, must be generated. Until now the sent data was stored in the template 0002-Request.xml. This file does not contain xml, but the plain message that was sent by the browser. Because it does not contain xml, it is not possible to manipulate it with compositions, substitutions or omissions.

Because of this, the template will be disposed and the message will be generated on the fly by a filter that can encode the submitted form data in a proper way.

Before the template of the request will be deleted we will use it to find out what data is sent. The content of the file /template/generated/bookingExampleLogin/0002-Request.xml will look approximately like this:

jsf_tree_64=H4sIAAAAAAAAAK2RwUrDQBCGx9JiFUHUg1dBsSKSYCmK9Gah
2pJSsFWQHso2WdPUZHfdTGy9ePPuA%2FgE0ifwCbx59SW8enZj0qYHoTl4GZ
jh%2F%2Fj%2FmRl%2FQc6XcMalrRFBzD7VvIcbYlJftcJ1TIIOZ1pbUtpCGZ
gYSNogjNhU7iTDCvcEZ5Rh9Xrz86X%2B%2FZGBbAeWumbfcS2p5lDvGMpCjy
z02EKfsdDTWpQNWO2ak67iEt9HWDcG5J7oLmG2rvQOs5VsJZHVrDt4hEwHFr
uhMypkozPDNHsDamJ5JAIZR%2F2Pa5TfxoX3tafn1wzASADAgh%2FGgCCsOd
Xno14g7IdZRlrkNY2t9dFztXNVmgGKAA3Soy5CtutYJTFl9%2BawNabQNh0h
Qj7wqWTEowm9O4duUN9XC0auxxMurMvR7ESk3uI3SYuakoZZhHrdkEsr4Qvp
sqjv5ZTxYTEhD%2BaQ6iceYdZpgMhZjJfSB49xw2G3MXykqO05VJVLL7pRUa
m3%2FlZf1q4cOrzgHIX4Afwk28eOAwAA&jsf_state_64=H4sIAAAAAAAAAJ
VWTWwbRRQe%2F4Q4aVLy05ZWbanlhiBEWOfHSZyk0Dp10lis0yg2FTQHd7w7
sTdZ7y674%2ByGqFE59AICgRBVkYJA4sIBLlxAPYEQIJAAEYkLEhIHJIQEVO
LCj0RhZnb9E3s3NSN5bM9%2BM%2B%2FN97739r3zK2gr66B%2FhV%2BDG5CT
oVLgLubXkIBnXvrqyTd6jIdkPwCWBgAIlJ8G24COYPVXu0aGoYNetruMJZlb
gEYxDbW29u8%2B%2BvjIlW8CwD8POmUVivNQwKqeAh24qCOjqMqipZ09x47p
MkNk7iEfHwb9ql7g1vKqYXAGgiVuKXFhzqAGg01oYFnMfE%2FNPK8KUEbbf%
2FZe2Rn%2B6xc%2FCKZAqEhcElQR8aBdUMsK1jcx6GMXjtILRzNYl5TCDA9C
9G8ZFhA110HgG1CXoILZX0v7lwwMAAZ%2BkSEOYNC5kE3zudlEJnUegwPRol
pCnFXEJZm61V9zK6HrcJOXDGw9u3vytc%2Fg6wHgS4GgIT2DGLk%2BM0jnKr
E1so%2FUyMYgmJPEUQ3bF7a4VSggg5tX9RLFHPJgKYDBUUEtcUZZYTtkhA0u
nVh%2BPJdKYhCKCZOr43lhzA2VWFriU3NJcpdo0zOppMlcEq3Csozn7cWBhK
bJm1l1HSkLO18nZ5Qbb3ZR9ZiH93BDLto3evufTy0MlmiwoQaFIuJKm%2FZ9
dKSISF%2BXMEfB3AKZ6BWX2TLSZ6GBuIVUMjm3mDt%2FMZ1OLCZzqcWlJ7KZ
XGYu2yzGDMK3ktdfvfHB%2B7EAc6aL8uKwRPTWRzmdzsmSsp4rSqKIlByVlf
tgFN9LNoZYwEIuATvssuaELkZC11sfOh7mkax5xM1Hl%2B%2BrRQg5XpGVso
F0BZaQi4cu1o9Xf3W4%2B1Y7r0FaWWRhDLoZQxVMa96KU9bee%2FkY0m9z3r
YB5TIisRpskhUiOYwKUNi8RCGzkiKS3AT28DE1eW3LwgLbM2dppMAYkqrUb9
PBUftmBNkAMzuvrfzw4Z2X%2FQzWX4XVEG9dfy7z%2B%2BXdM37H%2Fv0V%2
B82HpUhaBG69nT%2F1wOc3qV3KwZQ5AHpOb1EGuQqNV52qVVdyNc0yHwEP12
VK%2BNzoyFB8JMzoejTSeETEYkqtap6dNauqMoLKl2H92rc7f%2F%2FmB77L
Dt%2Bk0jgKfsznJXCigG5TEnFxOjwyOa5ZM16i6nZ7HdgynySH9NfLKE2oIV
W1RaGjmLWvyP9fzk1pdGGwRdurk7Uk06BhmKoutpZkJ%2B6aZNXzSM2pZyeD
BB1V06yCas3f%2BKh3mtHlcfZwgs1xNp%2Bp02LFVqtanBiKjzVosXqEo0Vq
4qz9dc5TYy2L7KC7yNoIUyP0PXjIRWVGi6GOk%2F7Dw899a2hbkyexxojOlj
FWFdId2K8WCmnNp6m43dA86F0W0wgXVbGhLpIk54GvhMFx1tZYUSRHbWCtMM
1YnieTytmI3ls6j1VrYiPuvegXz%2F%2F4R%2BxFv1PqpomNU3XVsRFPy%2B
P3y9vxrqdeuV0pj6YZAQdPb8lqQVI4Nu8RpN2eNXapTtP27u6ln34%2BuXWh
0qUCV%2BFODY0Mx8OkASUeUOnWm4qwatOdEFhvGObpopdq78mzyN69BjSLZK
Lx3cqThqNeIhOtSQTmLaeIG2zeIIRH9iGclzDSofzCsat3VvAnwRrnJ0BIRw
XSkiLdhW2K2aKOWOYgGNjD5tjw0PhklczKGRHPnqkyLOs%2Fpe6Gom4MAAA%
3D&jsf_viewid=%2Fhome.xhtml&_id2%3Ausername=petatest&_id2%3A
password=veritpeta&_id2%3A_id14=Account+Login&_id2_SUBMIT=1&
_id2%3A_link_hidden_=

This string is URL encoded and separated by semicolons. If the content is decoded and separated at the semicolons, the parameters are easier to determine:

jsf_tree_64

This parameter is necessary for JSF, as it was not visible on the page it must have been in a hidden element. We'll get it's value from the submitted form.

jsf_state_64

As jsf_tree_64 this is stored in a hidden element, and we will get it's value from the form.

jsf_viewid

This is also a hidden input field. It could be set manually to /home.xhtml, but can be taken from the form as well.

_id2:username

This value, together with the _id2:password are the only parameters that can be filled into the form. It will be set manually to the account name that was set up in Section 12.1, “Preparations” .

_id2:password

The value of this form is also entered into the form, it will be specified manually.

_id2:_id14

This value comes from a hidden input field. It can be taken from the form or set manually to Account Login

_id2_SUBMIT

This value comes from a hidden input field, and can be taken from an input field or can be set manually to 1

_id2:_link_hidden_

The value of this parameter comes from a hidden input field and is empty, so it will be set to an empty string.

The encoded form data will be created with the filter HTMLFormEncoder. This filter encodes the data of its parameters to a body of a HTML request.

[Note]The HTMLFormEncoder filter

Inserts an HTML Form parameter with name as specified by the key attribute and the provided value into the result message.

The encoded parameters are attached to a template, so if a completely new message should be generated, a new empty template must be created. To do this, press the New message template () button, enter emptyTemplate as name for the template and select the template folder of in the PETA base path as parent folder. Press Finish to create the template, then delete all content of the file and save.

Figure 13.24.  The empty template

The empty template


Now delete the old template from the event 0002-Request and add the new template emptyTemplate to the event 0002-Request by dragging the to the events operation.

Figure 13.25.  The event with the empty template

The event with the empty template


Finally, the HTMLFormEncoder output filter must be added to the operation of 0002-Request, by dragging the Add Outputfilter() button to the event. Then specify its arguments:

  1. First add the jsf_tree_64 parameter, by pressing the Add Argument… button, selecting parameter, pressing OK entering jsf_tree_64 and pressing OK .

    Then the correct value in the document must be assigned to the argument's value: To do this press Add Document, select the Path argument of the document, press Add Constant… and enter /html/body/form/input[@id='jsf_tree_64']/@value as path.

    Figure 13.26.  Inserting the parameter for the jsf_tree_64

    Inserting the parameter for the jsf_tree_64


The the other parameters are added similar, if they are hidden input fields the Path argument of the document must be altered, otherwise, the document must be replaced by a constant.

  1. For the jsf_state_64 parameter to the same as for the jsf_tree_64 parameter, except that the name must be changed do jsf_state_64 and the path must be /html/body/form/input[@id='jsf_state_64']/@value .

    Figure 13.27.  Inserting the parameter for jsf_state_64

    Inserting the parameter for jsf_state_64


  2. As for the other hidden input values the value of jsf_viewid should be extracted from the form. To do this, do the same steps as above, but name the parameter jsf_viewid and use for the path expression of the document /html/body/form/input[@id='jsf_viewid']/@value.

    Figure 13.28. Inserting the parameter for jsf_viewid

    Inserting the parameter for jsf_viewid


  3. For the _id2:username parameter do the same as above, but change the parameters key to _id2:username and instead of adding a document add a constant containing the user name that was specified in Section 12.1, “Preparations” .

    Figure 13.29. Inserting the parameter for the username

    Inserting the parameter for the username


  4. For the _id2:password do the same as in the previous paragraph, but change the name to _id2:password and enter as value the password that was specified in Section 12.1, “Preparations” .

    Figure 13.30.  Inserting the parameter for the password

    Inserting the parameter for the password


  5. For the _id2:_id14 parameter do the same as for the jsf_tree_64 parameter,but the name must be changed do _id2:_id14 and the path must be /html/body/form//input[@id='_id2:_id14']/@value . Please note the double slash behind the form node in the expression. This must be added, because the hidden input field is enclosed with other tags.

    Figure 13.31.  Inserting the parameter for _id2:_id14

    Inserting the parameter for _id2:_id14


  6. The insertion of the _id2_SUBMIT parameter is done as the other parameters for hidden input fields. Set the name to _id2_SUBMIT and the expression to /html/body/form/input[@name='_id2_SUBMIT']/@value . Please note here that the node is referenced with its name and not with its id, as the other fields, because this field does not have an id.

    Figure 13.32.  Inserting the parameter for _id2_SUBMIT

    Inserting the parameter for _id2_SUBMIT


  7. Finally,, add the _id2:_link_hidden_ parameter, as this parameter has no value, this will not be taken from the form, but will be set to a constant empty string. Do this as the insertion of the parameters for non-hidden fields.

    Figure 13.33.  Inserting the parameter for _id2_SUBMIT

    Inserting the parameter for _id2_SUBMIT


Example 13.2, “Generating the request dynamically” shows the code snippet of the test case that does create the request.

Example 13.2. Generating the request dynamically

    ...
      <template id="emptyTemplate"/>
      <outputfilter name="HtmlFormEncoder">
        <argument key="jsf_tree_64" name="parameter">
          <document>
            <path>
              <constant value="/html/body/form/input[@id='jsf_tree_64']/@value"/>
            </path>
          </document>
        </argument>
        <argument key="jsf_state_64" name="parameter">
          <document>
            <path>
              <constant value="/html/body/form/input[@id='jsf_state_64']/@value"/>
            </path>
          </document>
        </argument>
        <argument key="jsf_viewid" name="parameter">
          <document>
            <path>
              <constant value="/html/body/form/input[@id='jsf_viewid']/@value"/>
            </path>
          </document>
        </argument>
        <argument key="_id2:username" name="parameter">
          <constant value="petatest"/>
        </argument>
        <argument key="_id2:password" name="parameter">
          <constant value="veritpeta"/>
        </argument>
        <argument key="_id2:_id14" name="parameter">
          <document>
            <path>
              <constant value="/html/body/form//input[@id='_id2:_id14']/@value"/>
            </path>
          </document>
        </argument>
        <argument key="_id2_SUBMIT" name="parameter">
          <document>
            <path>
              <constant value="/html/body/form/input[@name='_id2_SUBMIT']/@value"/>
            </path>
          </document>
        </argument>
        <argument key="_id2:_link_hidden_" name="parameter">
          <constant value=""/>
        </argument>
      </outputfilter>
      ...


Now the test case is ready to run. Try out what has been built: Let the test case run in the Simulated and the Real setup. It will succeed as expected. Try to run the test case with a wrong password. The password can be changed more comfortable as in the first try, just by changing the value of the parameter _id2:password in the HTMLEncoder filter in event 0002-Response. When the test case is run now, it will fail as expected.

13.1.3. Conclusion

At the beginning of this chapter we started with a recorded test case. This test case did run successful, but it was not very smart: It just asserted the correct status codes of the returned pages.

When the password was changed as an experiment we detected this drawback, and we refined the test case in that way the wrong password was detected.

Then we detected that there are more places where the test case does not behave as in the normal setting, so we started to reuse the data that was sent back in a form for the next request, that was built dynamically.

As a result we have a test case that imitates the normal behavior of a real client.