aboutsummaryrefslogtreecommitdiff
path: root/vendors/simpletest/docs/en/form_testing_documentation.html
blob: fe0fcccf027cca293d2474e4149d19c0d3a43fd2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Simple Test documentation for testing HTML forms</title>
<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
</head>
<body>
<div class="menu_back"><div class="menu">
<a href="index.html">SimpleTest</a>
                |
                <a href="overview.html">Overview</a>
                |
                <a href="unit_test_documentation.html">Unit tester</a>
                |
                <a href="group_test_documentation.html">Group tests</a>
                |
                <a href="mock_objects_documentation.html">Mock objects</a>
                |
                <a href="partial_mocks_documentation.html">Partial mocks</a>
                |
                <a href="reporter_documentation.html">Reporting</a>
                |
                <a href="expectation_documentation.html">Expectations</a>
                |
                <a href="web_tester_documentation.html">Web tester</a>
                |
                <span class="chosen">Testing forms</span>
                |
                <a href="authentication_documentation.html">Authentication</a>
                |
                <a href="browser_documentation.html">Scriptable browser</a>
</div></div>
<h1>Form testing documentation</h1>
        This page...
        <ul>
<li>
            Changing form values and successfully
            <a href="#submit">Submitting a simple form</a>
        </li>
<li>
            Handling <a href="#multiple">widgets with multiple values</a>
            by setting lists.
        </li>
<li>
            Bypassing javascript to <a href="#hidden-field">set a hidden field</a>.
        </li>
<li>
            <a href="#raw">Raw posting</a> when you don't have a button
            to click.
        </li>
</ul>
<div class="content">
        <p><a class="target" name="submit"><h2>Submitting a simple form</h2></a></p>
            <p>
                When a page is fetched by the <span class="new_code">WebTestCase</span>
                using <span class="new_code">get()</span> or
                <span class="new_code">post()</span> the page content is
                automatically parsed.
                This results in any form controls that are inside &lt;form&gt; tags
                being available from within the test case.
                For example, if we have this snippet of HTML...
<pre>
&lt;form&gt;
    &lt;input type="text" name="a" value="A default" /&gt;
    &lt;input type="submit" value="Go" /&gt;
&lt;/form&gt;
</pre>
                Which looks like this...
            </p>
            <p>
                <form class="demo">
                    <input type="text" name="a" value="A default">
                    <input type="submit" value="Go">
                </form>
            </p>
            <p>
                We can navigate to this code, via the
                <a href="http://www.lastcraft.com/form_testing_documentation.php">LastCraft</a>
                site, with the following test...
<pre>
class SimpleFormTests extends WebTestCase {
    <strong>
    function testDefaultValue() {
        $this-&gt;get('http://www.lastcraft.com/form_testing_documentation.php');
        $this-&gt;assertField('a', 'A default');
    }</strong>
}
</pre>
                Immediately after loading the page all of the HTML controls are set at
                their default values just as they would appear in the web browser.
                The assertion tests that a HTML widget exists in the page with the
                name "a" and that it is currently set to the value
                "A default".
                As usual, we could use a pattern expectation instead if a fixed
                string.
            </p>
            <p>
                We could submit the form straight away, but first we'll change
                the value of the text field and only then submit it...
<pre>
class SimpleFormTests extends WebTestCase {

    function testDefaultValue() {
        $this-&gt;get('http://www.my-site.com/');
        $this-&gt;assertField('a', 'A default');<strong>
        $this-&gt;setField('a', 'New value');
        $this-&gt;click('Go');</strong>
    }
}
</pre>
                Because we didn't specify a method attribute on the form tag, and
                didn't specify an action either, the test case will follow
                the usual browser behaviour of submitting the form data as a <em>GET</em>
                request back to the same location.
                SimpleTest tries to emulate typical browser behaviour as much as possible,
                rather than attempting to catch missing attributes on tags.
                This is because the target of the testing framework is the PHP application
                logic, not syntax or other errors in the HTML code.
                For HTML errors, other tools such as
                <a href="http://www.w3.org/People/Raggett/tidy/">HTMLTidy</a> should be used.
            </p>
            <p>
                If a field is not present in any form, or if an option is unavailable,
                then <span class="new_code">WebTestCase::setField()</span> will return
                <span class="new_code">false</span>.
                For example, suppose we wish to verify that a "Superuser"
                option is not present in this form...
<pre>
&lt;strong&gt;Select type of user to add:&lt;/strong&gt;
&lt;select name="type"&gt;
    &lt;option&gt;Subscriber&lt;/option&gt;
    &lt;option&gt;Author&lt;/option&gt;
    &lt;option&gt;Administrator&lt;/option&gt;
&lt;/select&gt;
</pre>
                Which looks like...
            </p>
            <p>
                <form class="demo">
                    <strong>Select type of user to add:</strong>
                    <select name="type">
                        <option>Subscriber</option>
                        <option>Author</option>
                        <option>Administrator</option>
                    </select>
                </form>
            </p>
            <p>
                The following test will confirm it...
<pre>
class SimpleFormTests extends WebTestCase {
    ...
    function testNoSuperuserChoiceAvailable() {<strong>
        $this-&gt;get('http://www.lastcraft.com/form_testing_documentation.php');
        $this-&gt;assertFalse($this-&gt;setField('type', 'Superuser'));</strong>
    }
}
</pre>
                The selection will not be changed on a failure to set
                a widget value.
            </p>
            <p>
                Here is the full list of widgets currently supported...
                <ul>
                    <li>Text fields, including hidden and password fields.</li>
                    <li>Submit buttons including the button tag, although not yet reset buttons</li>
                    <li>Text area. This includes text wrapping behaviour.</li>
                    <li>Checkboxes, including multiple checkboxes in the same form.</li>
                    <li>Drop down selections, including multiple selects.</li>
                    <li>Radio buttons.</li>
                    <li>Images.</li>
                </ul>
            </p>
            <p>
                The browser emulation offered by SimpleTest mimics
                the actions which can be perform by a user on a
                standard HTML page. Javascript is not supported, and
                it's unlikely that support will be added any time
                soon.
            </p>
            <p>
                Of particular note is that the Javascript idiom of
                passing form results by setting a hidden field cannot
                be performed using the normal SimpleTest
                commands. See below for a way to test such forms.
            </p>
        
        <p><a class="target" name="multiple"><h2>Fields with multiple values</h2></a></p>
            <p>
                SimpleTest can cope with two types of multivalue controls: Multiple
                selection drop downs, and multiple checkboxes with the same name
                within a form.
                The multivalue nature of these means that setting and testing
                are slightly different.
                Using checkboxes as an example...
<pre>
&lt;form class="demo"&gt;
    &lt;strong&gt;Create privileges allowed:&lt;/strong&gt;
    &lt;input type="checkbox" name="crud" value="c" checked&gt;&lt;br&gt;
    &lt;strong&gt;Retrieve privileges allowed:&lt;/strong&gt;
    &lt;input type="checkbox" name="crud" value="r" checked&gt;&lt;br&gt;
    &lt;strong&gt;Update privileges allowed:&lt;/strong&gt;
    &lt;input type="checkbox" name="crud" value="u" checked&gt;&lt;br&gt;
    &lt;strong&gt;Destroy privileges allowed:&lt;/strong&gt;
    &lt;input type="checkbox" name="crud" value="d" checked&gt;&lt;br&gt;
    &lt;input type="submit" value="Enable Privileges"&gt;
&lt;/form&gt;
</pre>
                Which renders as...
            </p>
            <p>
                <form class="demo">
                    <strong>Create privileges allowed:</strong>
                    <input type="checkbox" name="crud" value="c" checked><br>
                    <strong>Retrieve privileges allowed:</strong>
                    <input type="checkbox" name="crud" value="r" checked><br>
                    <strong>Update privileges allowed:</strong>
                    <input type="checkbox" name="crud" value="u" checked><br>
                    <strong>Destroy privileges allowed:</strong>
                    <input type="checkbox" name="crud" value="d" checked><br>
                    <input type="submit" value="Enable Privileges">
                </form>
            </p>
            <p>
                If we wish to disable all but the retrieval privileges and
                submit this information we can do it like this...
<pre>
class SimpleFormTests extends WebTestCase {
    ...<strong>
    function testDisableNastyPrivileges() {
        $this-&gt;get('http://www.lastcraft.com/form_testing_documentation.php');
        $this-&gt;assertField('crud', array('c', 'r', 'u', 'd'));
        $this-&gt;setField('crud', array('r'));
        $this-&gt;click('Enable Privileges');
    }</strong>
}
</pre>
                Instead of setting the field to a single value, we give it a list
                of values.
                We do the same when testing expected values.
                We can then write other test code to confirm the effect of this, perhaps
                by logging in as that user and attempting an update.
            </p>
        
        <p><a class="target" name="hidden-field"><h2>Forms which use javascript to set a hidden field</h2></a></p>
            <p>
                If you want to test a form which relies on javascript to set a hidden
                field, you can't just call setField().
                The following code will <em>not</em> work:
<pre>
class SimpleFormTests extends WebTestCase {
    function testMyJavascriptForm() {
        <strong>// This does *not* work</strong>
        $this-&gt;setField('a_hidden_field', '123');
        $this-&gt;clickSubmit('OK');
    }
}
</pre>
                Instead, you need to pass the additional form parameters to the
                clickSubmit() method:
<pre>
class SimpleFormTests extends WebTestCase {
    function testMyJavascriptForm() {
        // Pass the hidden field value as an additional POST variable
        <strong>$this-&gt;clickSubmit('OK', array('a_hidden_field'=&gt;'123'));</strong>
    }

}
</pre>
            </p>
            <p>
                Bear in mind that in doing this you're effectively stubbing out a
                part of your software (the javascript code in the form), and
                perhaps you might be better off using something like 
                <a href="http://selenium.openqa.org/">Selenium</a> to ensure a complete
                acceptance test.
            </p>
        
        <p><a class="target" name="raw"><h2>Raw posting</h2></a></p>
            <p>
                If you want to test a form handler, but have not yet written
                or do not have access to the form itself, you can create a
                form submission by hand.
<pre>
class SimpleFormTests extends WebTestCase {
    ...<strong>    
    function testAttemptedHack() {
        $this-&gt;post(
                'http://www.my-site.com/add_user.php',
                array('type' =&gt; 'superuser'));
        $this-&gt;assertNoText('user created');
    }</strong>
}
</pre>
                By adding data to the <span class="new_code">WebTestCase::post()</span>
                method, we are attempting to fetch the page as a form submission.
            </p>
        
    </div>
        References and related information...
        <ul>
<li>
            SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
        </li>
<li>
            SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
        </li>
<li>
            The <a href="http://simpletest.org/api/">developer's API for SimpleTest</a>
            gives full detail on the classes and assertions available.
        </li>
</ul>
<div class="menu_back"><div class="menu">
<a href="index.html">SimpleTest</a>
                |
                <a href="overview.html">Overview</a>
                |
                <a href="unit_test_documentation.html">Unit tester</a>
                |
                <a href="group_test_documentation.html">Group tests</a>
                |
                <a href="mock_objects_documentation.html">Mock objects</a>
                |
                <a href="partial_mocks_documentation.html">Partial mocks</a>
                |
                <a href="reporter_documentation.html">Reporting</a>
                |
                <a href="expectation_documentation.html">Expectations</a>
                |
                <a href="web_tester_documentation.html">Web tester</a>
                |
                <span class="chosen">Testing forms</span>
                |
                <a href="authentication_documentation.html">Authentication</a>
                |
                <a href="browser_documentation.html">Scriptable browser</a>
</div></div>
<div class="copyright">
            Copyright<br>Marcus Baker 2006
        </div>
</body>
</html>