source: sipei/modules/cck/tests/content.crud.test @ fc0b1f8

drupal-6.x
Last change on this file since fc0b1f8 was ffa4103, checked in by Luis Peña <lpena@…>, 12 años ago

Cambiando el nombre de modulos a modules

  • Propiedad mode establecida a 100755
File size: 49.5 KB
Línea 
1<?php
2// $Id: content.crud.test,v 1.4.2.16 2008/12/08 12:41:08 yched Exp $
3
4// TODO:
5// - Test search indexing
6// - Test values reordering with preview and failed validation
7
8/**
9 * Base class for CCK CRUD tests.
10 * Defines many helper functions useful for writing CCK CRUD tests.
11 */
12class ContentCrudTestCase extends DrupalWebTestCase {
13  var $enabled_schema = FALSE;
14  var $content_types  = array();
15  var $nodes          = array();
16  var $last_field     = NULL;
17  var $next_field_n   = 1;
18
19  /**
20   * Enable CCK, Text, and Schema modules.
21   */
22  function setUp() {
23    $args = func_get_args();
24    $modules = array_merge(array('content', 'schema', 'text'), $args);
25    call_user_func_array(array('parent','setUp'), $modules);
26    module_load_include('inc', 'content', 'includes/content.crud');
27  }
28
29  // Database schema related helper functions
30
31  /**
32   * Checks that the database itself and the reported database schema match the
33   * expected columns for the given tables.
34   * @param $tables An array containing the key 'per_field' and/or the key 'per_type'.
35   *  These keys should have array values with table names as the keys (without the 'content_' / 'content_type_' prefix)
36   *  These keys should have either NULL value to indicate the table should be absent, or
37   *  array values containing column names. The column names can themselves be arrays, in
38   *  which case the contents of the array are treated as column names and prefixed with
39   *  the array key.
40   *
41   * For example, if called with the following as an argument:
42   * array(
43   *   'per_field' => array(
44   *     'st_f1' => array('delta', 'field_f1' => array('value, 'format')),
45   *     'st_f2' => NULL,    // no content_field_f2 table
46   *   ),
47   *   'per_type' => array(
48   *     'st_t1' => array('field_f2' => array('value'), 'field_f3' => array('value', 'format')),
49   *     'st_t2' => array(), // only 'nid' and 'vid' columns
50   *     'st_t3' => NULL,    // no content_type_t3 table
51   *   ),
52   * )
53   * Then the database and schema will be checked to ensure that:
54   *   content_st_f1 table contains fields nid, vid, delta, field_f1_value, field_f1_format
55   *   content_st_f2 table is absent
56   *   content_type_st_t1 table contains fields nid, vid, field_f2_value, field_f3_value, field_f3_format
57   *   content_type_st_t2 table contains fields nid, vid
58   *   content_type_st_t3 table is absent
59   */
60  function assertSchemaMatchesTables($tables) {
61    $groups = array('per_field' => 'content_', 'per_type' => 'content_type_');
62
63    foreach ($groups as $group => $table_prefix) {
64      if (isset($tables[$group])) {
65        foreach ($tables[$group] as $entity => $columns) {
66          if (isset($columns)) {
67            $db_columns = array('nid', 'vid');
68            foreach ($columns as $prefix => $items) {
69              if (is_array($items)) {
70                foreach ($items as $item) {
71                  $db_columns[] = $prefix .'_'. $item;
72                }
73              }
74              else {
75                $db_columns[] = $items;
76              }
77            }
78            $this->_assertSchemaMatches($table_prefix . $entity, $db_columns);
79          }
80          else {
81            $this->_assertTableNotExists($table_prefix . $entity);
82          }
83        }
84      }
85    }
86  }
87
88  /**
89   * Helper function for assertSchemaMatchesTables
90   * Checks that the given database table does NOT exist
91   * @param $table Name of the table to check
92   */
93  function _assertTableNotExists($table) {
94    $this->assertFalse(db_table_exists($table), t('Table !table is absent', array('!table' => $table)));
95  }
96
97  /**
98   * Helper function for assertSchemaMatchesTables
99   * Checks that the database and schema for the given table contain only the expected fields.
100   * @param $table Name of the table to check
101   * @param $columns Array of column names
102   */
103  function _assertSchemaMatches($table, $columns) {
104    // First test: check the expected structure matches the stored schema.
105    $schema = drupal_get_schema($table, TRUE);
106    $mismatches = array();
107    if ($schema === FALSE) {
108      $mismatches[] = t('table does not exist');
109    }
110    else {
111      $fields = $schema['fields'];
112      foreach ($columns as $field) {
113        if (!isset($fields[$field])) {
114          $mismatches[] = t('field !field is missing from table', array('!field' => $field));
115        }
116      }
117      $columns_reverse = array_flip($columns);
118      foreach ($fields as $name => $info) {
119        if(!isset($columns_reverse[$name])) {
120          $mismatches[] = t('table contains unexpected field !field', array('!field' => $name));
121        }
122      }
123    }
124    $this->assertEqual(count($mismatches), 0, t('Table !table matches schema: !details',
125      array('!table' => $table, '!details' => implode($mismatches, ', '))));
126
127    // Second test: check the schema matches the actual db structure.
128    // This is the part that relies on schema.module.
129    if (!$this->enabled_schema) {
130      $this->enabled_schema = module_exists('schema');
131    }
132    if ($this->enabled_schema) {
133      // Clunky workaround for http://drupal.org/node/215198
134      $prefixed_table = db_prefix_tables('{'. $table .'}');
135      $inspect = schema_invoke('inspect', $prefixed_table);
136      $inspect = isset($inspect[$table]) ? $inspect[$table] : NULL;
137      $compare = schema_compare_table($schema, $inspect);
138      if ($compare['status'] == 'missing') {
139        $compare['reasons'] = array(t('table does not exist'));
140      }
141    }
142    else {
143      $compare = array('status' => 'unknown', 'reasons' => array(t('cannot enable schema module')));
144    }
145    $this->assertEqual($compare['status'], 'same', t('Table schema for !table matches database: !details',
146      array('!table' => $table, '!details' => implode($compare['reasons'], ', '))));
147  }
148
149  // Node data helper functions
150
151  /**
152   * Helper function for assertNodeSaveValues. Recursively checks that
153   * all the keys of a table are present in a second and have the same value.
154   */
155  function _compareArrayForChanges($fields, $data, $message, $prefix = '') {
156    foreach ($fields as $key => $value) {
157      $newprefix = ($prefix == '') ? $key : $prefix .']['. $key;
158      if (is_array($value)) {
159        $compare_to = isset($data[$key]) ? $data[$key] : array();
160        $this->_compareArrayForChanges($value, $compare_to, $message, $newprefix);
161      }
162      else {
163        $this->assertEqual($value, $data[$key], t($message, array('!key' => $newprefix)));
164      }
165    }
166  }
167
168  /**
169   * Checks that after a node is saved using node_save, the values to be saved
170   * match up with the output from node_load.
171   * @param $node Either a node object, or the index of an acquired node
172   * @param $values Array of values to be merged with the node and passed to node_save
173   * @return The values array
174   */
175  function assertNodeSaveValues($node, $values) {
176    if (is_numeric($node) && isset($this->nodes[$node])) {
177      $node = $this->nodes[$node];
178    }
179    $node = $values + (array)$node;
180    $node = (object)$node;
181    node_save($node);
182    $this->assertNodeValues($node, $values);
183    return $values;
184  }
185
186  /**
187   * Checks that the output from node_load matches the expected values.
188   * @param $node Either a node object, or the index of an acquired node (only the nid field is used)
189   * @param $values Array of values to check against node_load. The node object must contain the keys in the array,
190   *  and the values must be equal, but the node object may also contain other keys.
191   */
192  function assertNodeValues($node, $values) {
193    if (is_numeric($node) && isset($this->nodes[$node])) {
194      $node = $this->nodes[$node];
195    }
196    $node = node_load($node->nid, NULL, TRUE);
197    $this->_compareArrayForChanges($values, (array)$node, 'Node data [!key] is correct');
198  }
199
200  /**
201   * Checks that the output from node_load is missing certain fields
202   * @param $node Either a node object, or the index of an acquired node (only the nid field is used)
203   * @param $fields Array containing a list of field names
204   */
205  function assertNodeMissingFields($node, $fields) {
206    if (is_numeric($node) && isset($this->nodes[$node])) {
207      $node = $this->nodes[$node];
208    }
209    $node = (array)node_load($node->nid, NULL, TRUE);
210    foreach ($fields as $field) {
211      $this->assertFalse(isset($node[$field]), t('Node should be lacking field !key', array('!key' => $field)));
212    }
213  }
214
215  /**
216   * Creates random values for a text field
217   * @return An array containing a value key and a format key
218   */
219  function createRandomTextFieldData() {
220    return array(
221      'value' => '!SimpleTest! test value' . $this->randomName(60),
222      'format' => 2,
223    );
224  }
225
226  // Login/user helper functions
227
228  /**
229   * Creates a user / role with certain permissions and then logs in as that user
230   * @param $permissions Array containing list of permissions. If not given, defaults to
231   *  access content, administer content types, administer nodes and administer filters.
232   */
233  function loginWithPermissions($permissions = NULL) {
234    if (!isset($permissions)) {
235      $permissions = array(
236        'access content',
237        'administer content types',
238        'administer nodes',
239        'administer filters',
240      );
241    }
242    $user = $this->drupalCreateUser($permissions);
243    $this->drupalLogin($user);
244  }
245
246  // Creation helper functions
247
248  /**
249   * Creates a number of content types with predictable names (simpletest_t1 ... simpletest_tN)
250   * These content types can later be accessed via $this->content_types[0 ... N-1]
251   * @param $count Number of content types to create
252   */
253  function acquireContentTypes($count) {
254    $this->content_types = array();
255    for ($i = 0; $i < $count; $i++) {
256      $name = 'simpletest_t'. ($i + 1);
257      $this->content_types[$i] = $this->drupalCreateContentType(array(
258        'name' => $name,
259        'type' => $name,
260      ));
261    }
262    content_clear_type_cache();
263  }
264
265  /**
266   * Creates a number of nodes of each acquired content type.
267   * Remember to call acquireContentTypes() before calling this, else the content types won't exist.
268   * @param $count Number of nodes to create per acquired content type (defaults to 1)
269   */
270  function acquireNodes($count = 1) {
271    $this->nodes = array();
272    foreach ($this->content_types as $content_type) {
273      for ($i = 0; $i < $count; $i++) {
274        $this->nodes[] = $this->drupalCreateNode(array('type' => $content_type->type));
275      }
276    }
277  }
278
279  /**
280   * Creates a field instance with a predictable name. Also makes all future calls to functions
281   * which take an optional field use this one as the default.
282   * @param $settings Array to be passed to content_field_instance_create. If the field_name
283   *  or type_name keys are missing, then they will be added. The default field name is
284   *  simpletest_fN, where N is 1 for the first created field, and increments. The default
285   *  type name is type name of the $content_type argument.
286   * @param $content_type Either a content type object, or the index of an acquired content type
287   * @return The newly created field instance.
288   */
289  function createField($settings, $content_type = 0) {
290    if (is_numeric($content_type) && isset($this->content_types[$content_type])) {
291      $content_type = $this->content_types[$content_type];
292    }
293    $defaults = array(
294      'field_name' => 'simpletest_f'. $this->next_field_n++,
295      'type_name' => $content_type->type,
296    );
297    $settings = $settings + $defaults;
298    $this->last_field = content_field_instance_create($settings);
299    return $this->last_field;
300  }
301
302  /**
303   * Creates a textfield instance. Identical to createField() except it ensures that the text module
304   * is enabled, and adds default settings of type (text) and widget_type (text_textfield) if they
305   * are not given in $settings.
306   * @sa createField()
307   */
308  function createFieldText($settings, $content_type = 0) {
309    $defaults = array(
310      'type' => 'text',
311      'widget_type' => 'text_textfield',
312    );
313    $settings = $settings + $defaults;
314    return $this->createField($settings, $content_type);
315  }
316
317  // Field manipulation helper functions
318
319  /**
320   * Updates a field instance. Also makes all future calls to functions which take an optional
321   * field use the updated one as the default.
322   * @param $settings New settings for the field instance. If the field_name or type_name keys
323   *  are missing, then they will be taken from $field.
324   * @param $field The field instance to update (defaults to the last worked upon field)
325   * @return The updated field instance.
326   */
327  function updateField($settings, $field = NULL) {
328    if (!isset($field)) {
329      $field = $this->last_field;
330    }
331    $defaults = array(
332      'field_name' => $field['field_name'],
333      'type_name'  => $field['type_name'] ,
334    );
335    $settings = $settings + $defaults;
336    $this->last_field = content_field_instance_update($settings);
337    return $this->last_field;
338  }
339
340  /**
341   * Makes a copy of a field instance on a different content type, effectively sharing the field with a new
342   * content type. Also makes all future calls to functions which take an optional field use the shared one
343   * as the default.
344   * @param $new_content_type Either a content type object, or the index of an acquired content type
345   * @param $field The field instance to share (defaults to the last worked upon field)
346   * @return The shared (newly created) field instance.
347   */
348  function shareField($new_content_type, $field = NULL) {
349    if (!isset($field)) {
350      $field = $this->last_field;
351    }
352    if (is_numeric($new_content_type) && isset($this->content_types[$new_content_type])) {
353      $new_content_type = $this->content_types[$new_content_type];
354    }
355    $field['type_name'] = $new_content_type->type;
356    $this->last_field = content_field_instance_create($field);
357    return $this->last_field;
358  }
359
360  /**
361   * Deletes an instance of a field.
362   * @param $content_type Either a content type object, or the index of an acquired content type (used only
363   *  to get field instance type name).
364   * @param $field The field instance to delete (defaults to the last worked upon field, used only to get
365   *  field instance field name).
366   */
367  function deleteField($content_type, $field = NULL) {
368    if (!isset($field)) {
369      $field = $this->last_field;
370    }
371    if (is_numeric($content_type) && isset($this->content_types[$content_type])) {
372      $content_type = $this->content_types[$content_type];
373    }
374    content_field_instance_delete($field['field_name'], $content_type->type);
375  }
376}
377
378class ContentCrudBasicTest extends ContentCrudTestCase {
379  function getInfo() {
380    return array(
381      'name' => t('CRUD - Basic API tests'),
382      'description' => t('Tests the field CRUD (create, read, update, delete) API. <strong>Requires <a href="@schema_link">Schema module</a>.</strong>', array('@schema_link' => 'http://www.drupal.org/project/schema')),
383      'group' => t('CCK'),
384    );
385  }
386
387  function setUp() {
388    parent::setUp();
389    $this->acquireContentTypes(1);
390  }
391
392  function testBasic() {
393    // Create a field with both field and instance settings.
394    $field = $this->createFieldText(array('widget_type' => 'text_textarea', 'text_processing' => 1, 'rows' => 5), 0);
395
396
397    // Check that collapse and expand are inverse.
398    $fields = content_field_instance_read(array('field_name' => $field['field_name'], 'type_name' => $this->content_types[0]->type));
399    $field1 = array_pop($fields);
400
401    $field2 = content_field_instance_collapse($field1);
402    $field3 = content_field_instance_expand($field2);
403    $field4 = content_field_instance_collapse($field3);
404
405    $this->assertIdentical($field1, $field3, 'collapse then expand is identity');
406    $this->assertIdentical($field2, $field4, 'expand then collapse is identity');
407
408
409    // Check that collapse and expand are both final
410    // (e.g. do not further alter the data when called multiple times).
411    $fields = content_field_instance_read(array('field_name' => $field['field_name'], 'type_name' => $this->content_types[0]->type));
412    $field1 = array_pop($fields);
413
414    $field2 = content_field_instance_collapse($field1);
415    $field3 = content_field_instance_collapse($field2);
416    $this->assertIdentical($field2, $field3, 'collapse is final');
417
418    $field2 = content_field_instance_expand($field1);
419    $field3 = content_field_instance_expand($field2);
420    $this->assertIdentical($field2, $field3, 'expand is final');
421
422
423    // Check that updating a field as is leaves it unchanged.
424    $fields = content_field_instance_read(array('field_name' => $field['field_name'], 'type_name' => $this->content_types[0]->type));
425    $field1 = array_pop($fields);
426    $field2 = content_field_instance_update($field1);
427    $fields = content_field_instance_read(array('field_name' => $field['field_name'], 'type_name' => $this->content_types[0]->type));
428    $field3 = array_pop($fields);
429
430    $this->assertIdentical($field1, $field3, 'read, update, read is identity');
431  }
432}
433
434class ContentCrudSingleToMultipleTest extends ContentCrudTestCase {
435  function getInfo() {
436    return array(
437      'name' => t('CRUD - Single to multiple'),
438      'description' => t('Tests the field CRUD (create, read, update, delete) API by creating a single value field and changing it to a multivalue field, sharing it between several content types. <strong>Requires <a href="@schema_link">Schema module</a>.</strong>', array('@schema_link' => 'http://www.drupal.org/project/schema')),
439      'group' => t('CCK'),
440    );
441  }
442
443  function setUp() {
444    parent::setUp();
445    $this->loginWithPermissions();
446    $this->acquireContentTypes(3);
447    $this->acquireNodes();
448  }
449
450  function testSingleToMultiple() {
451    // Create a simple text field
452    $this->createFieldText(array('text_processing' => 1));
453    $target_schema = array(
454      'per_type' => array(
455        'simpletest_t1' => array('simpletest_f1' => array('value', 'format'))
456      ),
457      'per_field' => array(),
458    );
459    $this->assertSchemaMatchesTables($target_schema);
460    $node0values = $this->assertNodeSaveValues(0, array(
461      'simpletest_f1' => array(
462        0 => $this->createRandomTextFieldData(),
463      )
464    ));
465
466    // Change the text field to allow multiple values
467    $this->updateField(array('multiple' => 1));
468    $target_schema = array(
469      'per_type' => array(
470        'simpletest_t1' => array(),
471      ),
472      'per_field' => array(
473        'simpletest_f1' => array('delta', 'simpletest_f1' => array('value', 'format')),
474      ),
475    );
476    $this->assertSchemaMatchesTables($target_schema);
477    $this->assertNodeValues(0, $node0values);
478
479    // Share the text field with 2 additional types t2 and t3.
480    for ($share_with_content_type = 1; $share_with_content_type <= 2; $share_with_content_type++) {
481      $this->shareField($share_with_content_type);
482      // There should be a new 'empty' per-type table for each content type that has fields.
483      $target_schema['per_type']['simpletest_t'. ($share_with_content_type + 1)] = array();
484      $this->assertSchemaMatchesTables($target_schema);
485      // The acquired node index will match the content type index as exactly one node is acquired per content type
486      $this->assertNodeSaveValues($share_with_content_type, array(
487        'simpletest_f1' => array(
488          0 => $this->createRandomTextFieldData(),
489        )
490      ));
491    }
492
493    // Delete the text field from all content types
494    for ($delete_from_content_type = 2; $delete_from_content_type >= 0; $delete_from_content_type--) {
495      $this->deleteField($delete_from_content_type);
496      // Content types that don't have fields any more shouldn't have any per-type table.
497      $target_schema['per_type']['simpletest_t'. ($delete_from_content_type + 1)] = NULL;
498      // After removing the last instance, there should be no table for the field either.
499      if ($delete_from_content_type == 0) {
500        $target_schema['per_field']['simpletest_f1'] = NULL;
501      }
502      $this->assertSchemaMatchesTables($target_schema);
503      // The acquired node index will match the content type index as exactly one node is acquired per content type
504      $this->assertNodeMissingFields($this->nodes[$delete_from_content_type], array('simpletest_f1'));
505    }
506  }
507}
508
509class ContentCrudMultipleToSingleTest extends ContentCrudTestCase {
510  function getInfo() {
511    return array(
512      'name' => t('CRUD - Multiple to single'),
513      'description' => t('Tests the field CRUD (create, read, update, delete) API by creating a multivalue field and changing it to a single value field, sharing it between several content types. <strong>Requires <a href="@schema_link">Schema module</a>.</strong>', array('@schema_link' => 'http://www.drupal.org/project/schema')),
514      'group' => t('CCK'),
515    );
516  }
517
518  function setUp() {
519    parent::setUp();
520    $this->loginWithPermissions();
521    $this->acquireContentTypes(3);
522    $this->acquireNodes();
523  }
524
525  function testMultipleToSingle() {
526    // Create a multivalue text field
527    $this->createFieldText(array('text_processing' => 1, 'multiple' => 1));
528    $this->assertSchemaMatchesTables(array(
529      'per_type' => array(
530        'simpletest_t1' => array(),
531      ),
532      'per_field' => array(
533        'simpletest_f1' => array('delta', 'simpletest_f1' => array('value', 'format')),
534      ),
535    ));
536    $this->assertNodeSaveValues(0, array(
537      'simpletest_f1' => array(
538        0 => $this->createRandomTextFieldData(),
539        1 => $this->createRandomTextFieldData(),
540        2 => $this->createRandomTextFieldData(),
541      )
542    ));
543
544    // Change to a simple text field
545    $this->updateField(array('multiple' => 0));
546    $this->assertSchemaMatchesTables(array(
547      'per_type' => array(
548        'simpletest_t1' => array('simpletest_f1' => array('value', 'format')),
549      ),
550      'per_field' => array(
551        'simpletest_f1' => NULL,
552      ),
553    ));
554    $node0values = $this->assertNodeSaveValues(0, array(
555      'simpletest_f1' => array(
556        0 => $this->createRandomTextFieldData(),
557      )
558    ));
559
560    // Share the text field with other content type
561    $this->shareField(1);
562    $this->assertSchemaMatchesTables(array(
563      'per_type' => array(
564        'simpletest_t1' => array(),
565        'simpletest_t2' => array(),
566      ),
567      'per_field' => array(
568        'simpletest_f1' => array('simpletest_f1' => array('value', 'format')),
569      ),
570    ));
571    $node1values = $this->assertNodeSaveValues(1, array(
572      'simpletest_f1' => array(
573        0 => $this->createRandomTextFieldData(),
574      )
575    ));
576    $this->assertNodeValues(0, $node0values);
577
578    // Share the text field with a 3rd type
579    $this->shareField(2);
580    $this->assertSchemaMatchesTables(array(
581      'per_type' => array(
582        'simpletest_t1' => array(),
583        'simpletest_t2' => array(),
584        'simpletest_t3' => array(),
585      ),
586      'per_field' => array(
587        'simpletest_f1' => array('simpletest_f1' => array('value', 'format')),
588      ),
589    ));
590    $this->assertNodeSaveValues(2, array(
591      'simpletest_f1' => array(
592        0 => $this->createRandomTextFieldData(),
593      )
594    ));
595    $this->assertNodeValues(1, $node1values);
596    $this->assertNodeValues(0, $node0values);
597
598    // Remove text field from 3rd type
599    $this->deleteField(2);
600    $this->assertSchemaMatchesTables(array(
601      'per_type' => array(
602        'simpletest_t1' => array(),
603        'simpletest_t2' => array(),
604        'simpletest_t3' => NULL,
605      ),
606      'per_field' => array(
607        'simpletest_f1' => array('simpletest_f1' => array('value', 'format')),
608      ),
609    ));
610    $this->assertNodeMissingFields($this->nodes[2], array('simpletest_f1'));
611
612    // Remove text field from 2nd type (field isn't shared anymore)
613    $this->deleteField(1);
614    $this->assertSchemaMatchesTables(array(
615      'per_type' => array(
616        'simpletest_t1' => array('simpletest_f1' => array('value', 'format')),
617        'simpletest_t2' => NULL,
618        'simpletest_t3' => NULL,
619      ),
620      'per_field' => array(
621        'simpletest_f1' => NULL,
622      ),
623    ));
624    $this->assertNodeMissingFields(1, array('simpletest_f1'));
625    $this->assertNodeValues(0, $node0values);
626
627    // Remove text field from original type
628    $this->deleteField(0);
629    $this->assertSchemaMatchesTables(array(
630      'per_type' => array(
631        'simpletest_t1' => NULL,
632        'simpletest_t2' => NULL,
633        'simpletest_t3' => NULL,
634      ),
635      'per_field' => array(
636        'simpletest_f1' => NULL,
637      ),
638    ));
639    $this->assertNodeMissingFields(0, array('simpletest_f1'));
640  }
641}
642
643class ContentUICrud extends ContentCrudTestCase {
644  function getInfo() {
645    return array(
646      'name' => t('Admin UI'),
647      'description' => t('Tests the CRUD (create, read, update, delete) operations for content fields via the UI. <strong>Requires <a href="@schema_link">Schema module</a>.</strong>', array('@schema_link' => 'http://www.drupal.org/project/schema')),
648      'group' => t('CCK'),
649    );
650  }
651
652  function setUp() {
653    parent::setUp('fieldgroup');
654    $this->loginWithPermissions();
655  }
656
657  function testAddFieldUI() {
658    // Add a content type with a random name (to avoid schema module problems).
659    $type1 = 'simpletest'. mt_rand();
660    $type1_name = $this->randomName(10);
661    $edit = array(
662      'type' => $type1,
663      'name' => $type1_name,
664    );
665    $this->drupalPost('admin/content/types/add', $edit, 'Save content type');
666    $admin_type1_url = 'admin/content/node-type/'. $type1;
667
668    // Create a text field via the UI.
669    $field_name = strtolower($this->randomName(10));
670    $field_label = $this->randomName(10);
671    $edit = array(
672      '_add_new_field[label]' => $field_label,
673      '_add_new_field[field_name]' => $field_name,
674      '_add_new_field[type]' => 'text',
675      '_add_new_field[widget_type]' => 'text_textfield',
676    );
677    $this->drupalPost($admin_type1_url .'/fields', $edit, 'Save');
678    $this->assertRaw('These settings apply only to the <em>'. $field_label .'</em> field', 'Field settings page displayed');
679    $this->assertRaw('Size of textfield', 'Field and widget types correct.');
680    $this->assertNoRaw('Change basic information', 'No basic information displayed');
681    $field_name = 'field_'. $field_name;
682
683    $edit = array();
684    // POST to the page without reloading.
685    $this->drupalPost(NULL, $edit, 'Save field settings');
686    $this->assertRaw('Added field <em>'. $field_label .'</em>.', 'Field settings saved');
687    $field_type1_url = $admin_type1_url .'/fields/'. $field_name;
688    $this->assertRaw($field_type1_url, 'Field displayed on overview.');
689
690    // Check the schema - the values should be in the per-type table.
691    $this->assertSchemaMatchesTables(array(
692      'per_type' => array(
693        $type1 => array($field_name => array('value')),
694      ),
695    ));
696
697
698    // Add a second content type.
699    $type2 = 'simpletest'. mt_rand();
700    $type2_name = $this->randomName(10);
701    $edit = array(
702      'type' => $type2,
703      'name' => $type2_name,
704    );
705    $this->drupalPost('admin/content/types/add', $edit, 'Save content type');
706    $admin_type2_url = 'admin/content/node-type/'. $type2;
707
708    // Add the same field to the second content type.
709    $edit = array(
710      '_add_existing_field[label]' => $field_label,
711      '_add_existing_field[field_name]' => $field_name,
712      '_add_existing_field[widget_type]' => 'text_textarea',
713    );
714    $this->drupalPost($admin_type2_url .'/fields', $edit, 'Save');
715    $this->assertRaw('These settings apply only to the <em>'. $field_label .'</em> field', 'Field settings page displayed');
716    $this->assertRaw('Rows', 'Field and widget types correct.');
717    $this->assertNoRaw('Change basic information', 'No basic information displayed');
718
719    $edit = array();
720    $this->drupalPost(NULL, $edit, 'Save field settings');
721    $this->assertRaw('Added field <em>'. $field_label .'</em>.', 'Field settings saved');
722    $field_type2_url = $admin_type2_url .'/fields/'. $field_name;
723    $this->assertRaw($field_type2_url, 'Field displayed on overview.');
724
725    // Check that a separate table is created for the shared field, and
726    // that it's values are no longer in the per-type tables.
727    $this->assertSchemaMatchesTables(array(
728      'per_field' => array(
729        $field_name => array($field_name => array('value')),
730      ),
731      'per_type' => array(
732        $type1 => array(),
733        $type2 => array(),
734      ),
735    ));
736
737
738    // Chancge the basic settings for this field.
739    $edit = array();
740    $this->drupalPost($field_type2_url, $edit, 'Change basic information');
741    $this->assertRaw('Edit basic information', 'Basic information form displayed');
742
743    $field_label2 = $this->randomName(10);
744    $edit = array(
745      'label' => $field_label2,
746      'widget_type' => 'text_textfield',
747    );
748    $this->drupalPost(NULL, $edit, 'Continue');
749    $this->assertRaw('These settings apply only to the <em>'. $field_label2 .'</em> field', 'Label changed');
750    $this->assertRaw('Size of textfield', 'Widget changed');
751
752    $edit = array();
753    // POST to the page without reloading.
754    $this->drupalPost(NULL, $edit, 'Save field settings');
755    $this->assertRaw('Saved field <em>'. $field_label2 .'</em>.', 'Field settings saved');
756
757
758    // Add a group to the second content type.
759    $group1_name = strtolower($this->randomName(10));
760    $group1_label = $this->randomName(10);
761    $edit = array(
762      '_add_new_group[label]' => $group1_label,
763      '_add_new_group[group_name]' => $group1_name,
764    );
765    $this->drupalPost($admin_type2_url .'/fields', $edit, 'Save');
766    $group1_name = 'group_'. $group1_name;
767    $this->assertRaw($admin_type2_url .'/groups/'. $group1_name, 'Group created');
768
769
770    // Remove the field from the second type.
771    $edit = array();
772    $this->drupalPost($field_type2_url .'/remove', $edit, 'Remove');
773    $this->assertRaw('Removed field <em>'. $field_label2 .'</em> from <em>'. $type2_name .'</em>', 'Field removed');
774    $this->assertNoRaw($field_type2_url, 'Field not displayed on overview.');
775
776    // Check the schema - the values should be in the per-type table.
777    $this->assertSchemaMatchesTables(array(
778      'per_type' => array(
779        $type1 => array($field_name => array('value')),
780      ),
781    ));
782
783    // Add a new field, an existing field, and a group in the same submit.
784    $field2_label = $this->randomName(10);
785    $field2_name = strtolower($this->randomName(10));
786    $group2_label = $this->randomName(10);
787    $group2_name = strtolower($this->randomName(10));
788    $edit = array(
789      '_add_new_field[label]' => $field2_label,
790      '_add_new_field[field_name]' => $field2_name,
791      '_add_new_field[type]' => 'text',
792      '_add_new_field[widget_type]' => 'text_textfield',
793      '_add_new_field[parent]' => $group1_name,
794      '_add_existing_field[label]' => $field_label,
795      '_add_existing_field[field_name]' => $field_name,
796      '_add_existing_field[widget_type]' => 'text_textarea',
797      '_add_existing_field[parent]' => '_add_new_group',
798      '_add_new_group[label]' => $group2_label,
799      '_add_new_group[group_name]' => $group2_name,
800    );
801    $this->drupalPost($admin_type2_url .'/fields', $edit, 'Save');
802    $this->assertRaw('These settings apply only to the <em>'. $field2_label .'</em> field', 'Field settings page for new field displayed');
803    // Submit new field settings
804    $edit = array();
805    $this->drupalPost(NULL, $edit, 'Save field settings');
806    $this->assertRaw('Added field <em>'. $field2_label .'</em>.', 'Field settings for new field saved');
807    $this->assertRaw('These settings apply only to the <em>'. $field_label .'</em> field', 'Field settings page for existing field displayed');
808    // Submit existing field settings
809    $edit = array();
810    $this->drupalPost(NULL, $edit, 'Save field settings');
811    $this->assertRaw('Added field <em>'. $field_label .'</em>.', 'Field settings for existing field saved');
812    $field2_name = 'field_'. $field2_name;
813    $field2_type2_url = $admin_type2_url .'/fields/'. $field2_name;
814    $this->assertRaw($field2_type2_url, 'New field displayed in overview');
815    $this->assertRaw($field_type2_url, 'Existing field displayed in overview');
816    $group2_name = 'group_'. $group2_name;
817    $this->assertRaw($admin_type2_url .'/groups/'. $group2_name, 'New group displayed in overview');
818
819    // Check Parenting
820    $groups = fieldgroup_groups($type2, FALSE, TRUE);
821    $this->assertTrue(isset($groups[$group1_name]['fields'][$field2_name]), 'New field in correct group');
822    $this->assertTrue(isset($groups[$group2_name]['fields'][$field_name]), 'Existing field in correct group');
823    $this->assertFieldByXPath('//select[@id="edit-'. strtr($field2_name, '_', '-') .'-parent"]//option[@selected]', $group1_name, 'Parenting for new field correct in overview');
824    $this->assertFieldByXPath('//select[@id="edit-'. strtr($field_name, '_', '-') .'-parent"]//option[@selected]', $group2_name, 'Parenting for existing field correct in overview');
825
826    // Check the schema : field1 is shared, field2 is in the per-type table.
827    $this->assertSchemaMatchesTables(array(
828      'per_field' => array(
829        $field_name => array($field_name => array('value')),
830      ),
831      'per_type' => array(
832        $type1 => array(),
833        $type2 => array($field2_name => array('value')),
834      ),
835    ));
836
837    // TODO : test validation failures...
838    // TODO : test ordering and extra fields...
839  }
840
841  function testFieldContentUI() {
842    // Create a content type with a field
843    $type1 = 'simpletest'. mt_rand();
844    $type1_obj = $this->drupalCreateContentType(array('type' => $type1));
845    $admin_type1_url = 'admin/content/node-type/'. $type1;
846    $field_name  = strtolower($this->randomName(10));
847    $field_url = 'field_'. $field_name;
848    $field = $this->createFieldText(array('text_processing' => 1, 'multiple' => 0, 'field_name' => $field_url), $type1_obj);
849
850    // Save a node with content in the text field
851    $edit = array();
852    $edit['title'] = $this->randomName(20);
853    $edit['body'] = $this->randomName(20);
854    $value = $this->randomName(20);
855    $edit[$field_url.'[0][value]'] = $value;
856    $this->drupalPost('node/add/'. $type1, $edit, 'Save');
857    $node = node_load(array('title' => $edit['title']));
858    $this->drupalGet('node/'. $node->nid);
859    $this->assertText($value, 'Textfield value saved and displayed');
860
861    // Alter the field to have unlimited values
862    $edit = array();
863    $edit['multiple']  = '1';
864    $this->drupalPost($admin_type1_url .'/fields/'. $field_url, $edit, 'Save field settings');
865
866    // Save a node with content in multiple text fields
867    $edit = array();
868    $edit['title'] = $this->randomName(20);
869    $edit['body'] = $this->randomName(20);
870    // Add more textfields (non-JS).
871    $this->drupalPost('node/add/'. $type1, $edit, "Add another item");
872    $this->drupalPost(NULL, $edit, "Add another item");
873    $value1 = $this->randomName(20);
874    $value2 = $this->randomName(20);
875    $value3 = $this->randomName(20);
876    $edit[$field_url.'[0][value]'] = $value1;
877    $edit[$field_url.'[1][value]'] = $value2;
878    $edit[$field_url.'[2][value]'] = $value3;
879
880    // This will fail if we don't have at least 3 textfields.
881    $this->drupalPost(NULL, $edit, 'Save');
882    $node = node_load(array('title' => $edit['title']));
883    $this->drupalGet('node/'. $node->nid);
884    $this->assertText($value3, '3rd textfield value saved and displayed');
885  }
886}
887
888class ContentOptionWidgetTest extends ContentCrudTestCase {
889  function getInfo() {
890    return array(
891      'name' => t('Option widgets'),
892      'description' => t('Tests the optionwidgets.'),
893      'group' => t('CCK'),
894    );
895  }
896
897  function setUp() {
898    parent::setUp('optionwidgets');
899    $this->loginWithPermissions();
900    $this->acquireContentTypes(1);
901  }
902
903  // TODO: test a number field with optionwidgets stores 0 correctly ?
904  // TODO: test the case where aliases and values overlap ? (http://drupal.org/node/281749)
905  // TODO: test noderef select widget...
906
907  /**
908   * On/Off Checkbox, not required:
909   * - Create a node with the value checked.
910   * - FAILS: Edit the node and uncheck the value.
911   *
912   * On/Off Checkbox, required:
913   * - TODO: what behavior do we want ?
914   */
915  function testOnOffCheckbox() {
916    $type = $this->content_types[0];
917    $type_url = str_replace('_', '-', $type->type);
918
919    // Create the field.
920    $on_text = $this->randomName(5);
921    $on_value = $this->randomName(5);
922    $off_text = $on_text. '_off';
923    $off_value = $on_value. '_off';
924
925    $settings = array(
926      'type' => 'text',
927      'widget_type' => 'optionwidgets_onoff',
928      'allowed_values' => "$off_value|$off_text\r\n$on_value|$on_text",
929    );
930    $field = $this->createField($settings, 0);
931    $field_name = $field['field_name'];
932
933    // Create a node with the checkbox on.
934    $edit = array(
935      'title' => $this->randomName(20),
936      'body' => $this->randomName(20),
937      $field_name.'[value]' => $on_value,
938    );
939    $this->drupalPost('node/add/'. $type_url, $edit, 'Save');
940    $node = node_load(array('title' => $edit['title']));
941    $this->assertEqual($node->{$field_name}[0]['value'], $on_value, 'Checkbox: checked (saved)');
942    $this->drupalGet('node/'. $node->nid);
943    $this->assertText($on_text, 'Checkbox: checked (displayed)');
944
945    // Edit the node and uncheck the box.
946    $edit = array(
947      $field_name.'[value]' => FALSE,
948    );
949    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
950    $node = node_load($node->nid, NULL, TRUE);
951    $this->assertEqual($node->{$field_name}[0]['value'], $off_value, 'Checkbox: unchecked (saved)');
952    $this->drupalGet('node/'. $node->nid);
953    $this->assertText($off_text, 'Checkbox: unchecked (displayed)');
954  }
955
956  /**
957   * Single select, not required:
958   * - TODO: check there's a 'none' choice in the form.
959   * - Create a node with one value selected.
960   * - Edit the node and unselect the value (selecting '- None -').
961   *
962   * Single select, required:
963   * - TODO: check there's no 'none' choice in the form.
964   *
965   * Multiple select, not required:
966   * - TODO: check there's a 'none' choice in the form.
967   * - Edit the node and select multiple values.
968   * - Edit the node and unselect one value.
969   * - Edit the node and unselect the values (selecting '- None -').
970   * - Edit the node and unselect the values (selecting nothing).
971   *
972   * Multiple select, required:
973   * - TODO: check there's no 'none' choice in the form.
974   * - Check the form doesn't submit when nothing is selected.
975   */
976  function testSelect() {
977    $type = $this->content_types[0];
978    $type_url = str_replace('_', '-', $type->type);
979
980    // Create the field - start with 'single'.
981    $value1 = $this->randomName(5);
982    $value1_alias = $value1 .'_alias';
983    $value2 = $this->randomName(5);
984    $value2_alias = $value2 .'_alias';
985
986    $settings = array(
987      'type' => 'text',
988      'widget_type' => 'optionwidgets_select',
989      'allowed_values' => "$value1|$value1_alias\r\n$value2|$value2_alias",
990    );
991    $field = $this->createField($settings, 0);
992    $field_name = $field['field_name'];
993
994    // Create a node with one value selected
995    $edit = array(
996      'title' => $this->randomName(20),
997      'body' => $this->randomName(20),
998    );
999    $edit[$field_name.'[value]'] = $value1;
1000    $this->drupalPost('node/add/'. $type_url, $edit, 'Save');
1001    $node = node_load(array('title' => $edit['title']));
1002    $this->assertEqual($node->{$field_name}[0]['value'], $value1, 'Select: selected (saved)');
1003    $this->drupalGet('node/'. $node->nid);
1004    $this->assertText($value1_alias, 'Select: selected (displayed)');
1005
1006    // Edit the node and unselect the value (selecting '- None -').
1007    $edit = array(
1008      $field_name.'[value]' => '',
1009    );
1010    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1011    $node = node_load($node->nid, NULL, TRUE);
1012    $this->assertIdentical($node->{$field_name}[0]['value'], NULL, 'Select: unselected (saved)');
1013    $this->drupalGet('node/'. $node->nid);
1014    $this->assertNoText($value1_alias, 'Select: unselected (displayed)');
1015
1016    // Change to a multiple field
1017    $field = $this->updateField(array('multiple' => '1', 'required' => '0'));
1018
1019    // Edit the node and select multiple values.
1020    $edit = array(
1021      $field_name.'[value][]' => array($value1 => $value1, $value2 => $value2),
1022    );
1023    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1024    $node = node_load($node->nid, NULL, TRUE);
1025    $this->assertEqual($node->{$field_name}[0]['value'], $value1, 'Multiple Select: selected 1 (saved)');
1026    $this->assertEqual($node->{$field_name}[1]['value'], $value2, 'Multiple Select: selected 2 (saved)');
1027    $this->drupalGet('node/'. $node->nid);
1028    $this->assertText($value1_alias, 'Multiple Select: selected 1 (displayed)');
1029    $this->assertText($value2_alias, 'Multiple Select: selected 2 (displayed)');
1030
1031    // Edit the node and unselect one value.
1032    $edit = array(
1033      $field_name.'[value][]' => array($value1 => $value1),
1034    );
1035    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1036    $node = node_load($node->nid, NULL, TRUE);
1037    $this->assertEqual($node->{$field_name}[0]['value'], $value1, 'Multiple Select: selected 1 (saved)');
1038    $this->assertTrue(!isset($node->{$field_name}[1]), 'Multiple Select: unselected 2 (saved)');
1039    $this->drupalGet('node/'. $node->nid);
1040    $this->assertText($value1_alias, 'Multiple Select: selected 1 (displayed)');
1041    $this->assertNoText($value2_alias, 'Multiple Select: unselected 2 (displayed)');
1042
1043    // Edit the node and unselect the values (selecting '- None -').
1044    $edit = array(
1045      $field_name.'[value][]' => array('' => ''),
1046    );
1047    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1048    $node = node_load($node->nid, NULL, TRUE);
1049    $this->assertIdentical($node->{$field_name}[0]['value'], NULL, 'Multiple Select: unselected 1 ("-none-" selected) (saved)');
1050    $this->assertTrue(!isset($node->{$field_name}[1]), 'Multiple Select: unselected 2 ("-none-" selected) (saved)');
1051    $this->drupalGet('node/'. $node->nid);
1052    $this->assertNoText($value1_alias, 'Multiple Select: unselected 1 ("-none-" selected) (displayed)');
1053    $this->assertNoText($value2_alias, 'Multiple Select: unselected 2 ("-none-" selected) (displayed)');
1054
1055    // Edit the node and unselect the values (selecting nothing).
1056    // We first need to put values back in (no test needed).
1057    $edit = array();
1058    $edit[$field_name.'[value][]'] = array($value1 => FALSE, $value2 => FALSE);
1059    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1060    $edit = array();
1061    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1062    $node = node_load($node->nid, NULL, TRUE);
1063    $this->assertIdentical($node->{$field_name}[0]['value'], NULL, 'Multiple Select: unselected 1 (no selection) (saved)');
1064    $this->assertTrue(!isset($node->{$field_name}[1]), 'Multiple Select: unselected 2 (no selection) (saved)');
1065    $this->drupalGet('node/'. $node->nid);
1066    $this->assertNoText($value1_alias, 'Multiple Select: unselected 1 (no selection) (displayed)');
1067    $this->assertNoText($value2_alias, 'Multiple Select: unselected 2 (no selection) (displayed)');
1068
1069    // Change the field to 'required'.
1070    $field = $this->updateField(array('required' => '1'));
1071
1072    // Check the form doesn't submit when nothing is selected.
1073    $edit = array();
1074    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1075    $this->assertRaw(t('!name field is required.', array('!name' => t($field['widget']['label']))), 'Multiple Select: "required" property is respected');
1076
1077    $edit = array(
1078      'title' => $this->randomName(20),
1079      'body' => $this->randomName(20),
1080    );
1081    $this->drupalPost('node/add/'. $type_url, $edit, 'Save');
1082    $this->assertRaw(t('!name field is required.', array('!name' => t($field['widget']['label']))), 'Multiple Select: "required" property is respected');
1083
1084  }
1085
1086  /**
1087   * Single (radios), not required:
1088   * - TODO: check there's a 'none' choice in the form.
1089   * - Create a node with one value selected.
1090   * - Edit the node and unselect the value (selecting '- None -').
1091   *
1092   * Single (radios), required:
1093   * - TODO: check there's no 'none' choice in the form.
1094   * - Check the form doesn't submit when nothing is selected.
1095   */
1096  function testRadios() {
1097    $type = $this->content_types[0];
1098    $type_url = str_replace('_', '-', $type->type);
1099
1100    // Create the field - 'single' (radios).
1101    $value1 = $this->randomName(5);
1102    $value1_alias = $value1 .'_alias';
1103    $value2 = $this->randomName(5);
1104    $value2_alias = $value2 .'_alias';
1105    $settings = array(
1106      'type' => 'text',
1107      'widget_type' => 'optionwidgets_buttons',
1108      'allowed_values' => "$value1|$value1_alias\r\n$value2|$value2_alias",
1109    );
1110    $field = $this->createField($settings, 0);
1111    $field_name = $field['field_name'];
1112
1113    // Create a node with one value selected
1114    $edit = array();
1115    $edit['title'] = $this->randomName(20);
1116    $edit['body'] = $this->randomName(20);
1117    $edit[$field_name.'[value]'] = $value1;
1118    $this->drupalPost('node/add/'. $type_url, $edit, 'Save');
1119    $node = node_load(array('title' => $edit['title']));
1120    $this->assertEqual($node->{$field_name}[0]['value'], $value1, 'Radios: checked (saved)');
1121    $this->drupalGet('node/'. $node->nid);
1122    $this->assertText($value1_alias, 'Radios: checked (displayed)');
1123
1124    // Edit the node and unselect the value (selecting '- None -').
1125    $edit = array();
1126    $edit[$field_name.'[value]'] = '';
1127    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1128    $node = node_load($node->nid, NULL, TRUE);
1129    $this->assertIdentical($node->{$field_name}[0]['value'], NULL, 'Radios: unchecked (saved)');
1130    $this->drupalGet('node/'. $node->nid);
1131    $this->assertNoText($value1_alias, 'Radios: unchecked (displayed)');
1132
1133    // Change field to required.
1134    $field = $this->updateField(array('required' => '1'));
1135
1136    // Check the form doesn't submit when nothing is selected.
1137    // Doing this on the pre-filled node doesn't take, so we test that on a new node.
1138    $edit = array();
1139    $edit['title'] = $this->randomName(20);
1140    $edit['body'] = $this->randomName(20);
1141    $this->drupalPost('node/add/'. $type_url, $edit, 'Save');
1142    $this->assertRaw(t('!name field is required.', array('!name' => t($field['widget']['label']))), 'Radios: "required" property is respected');
1143  }
1144
1145  /**
1146   * Multiple (checkboxes), not required:
1147   * - TODO: check there's no 'none' choice in the form.
1148   * - Create a node with two values.
1149   * - Edit the node and select only one value.
1150   * - Edit the node and unselect the values (selecting nothing).
1151   *
1152   * Multiple (checkboxes), required:
1153   * - TODO: check there's no 'none' choice in the form.
1154   * - Check the form doesn't submit when nothing is selected.
1155   */
1156  function testChecboxes() {
1157    $type = $this->content_types[0];
1158    $type_url = str_replace('_', '-', $type->type);
1159
1160    // Create the field -  'multiple' (checkboxes).
1161    $value1 = $this->randomName(5);
1162    $value1_alias = $value1 .'_alias';
1163    $value2 = $this->randomName(5);
1164    $value2_alias = $value2 .'_alias';
1165    $settings = array(
1166      'type' => 'text',
1167      'multiple' => '1',
1168      'widget_type' => 'optionwidgets_buttons',
1169      'allowed_values' => "$value1|$value1_alias\r\n$value2|$value2_alias",
1170    );
1171    $field = $this->createField($settings, 0);
1172    $field_name = $field['field_name'];
1173
1174    // Create a node with two values selected
1175    $edit = array(
1176      'title' => $this->randomName(20),
1177      'body' => $this->randomName(20),
1178      $field_name.'[value]['. $value1 .']' => $value1,
1179      $field_name.'[value]['. $value2 .']' => $value2,
1180    );
1181    $this->drupalPost('node/add/'. $type_url, $edit, 'Save');
1182    $node = node_load(array('title' => $edit['title']));
1183    $this->assertEqual($node->{$field_name}[0]['value'], $value1, 'Checkboxes: selected 1 (saved)');
1184    $this->assertEqual($node->{$field_name}[1]['value'], $value2, 'Checkboxes: selected 2 (saved)');
1185    $this->drupalGet('node/'. $node->nid);
1186    $this->assertText($value1_alias, 'Checkboxes: selected 1 (displayed)');
1187    $this->assertText($value2_alias, 'Checkboxes: selected 2 (displayed)');
1188
1189    // Edit the node and unselect the values (selecting nothing -
1190    // there is no 'none' choice for checkboxes).
1191    $edit = array(
1192      $field_name.'[value]['. $value1 .']' => $value1,
1193      $field_name.'[value]['. $value2 .']' => FALSE,
1194    );
1195    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1196    $node = node_load($node->nid, NULL, TRUE);
1197    $this->assertEqual($node->{$field_name}[0]['value'], $value1, 'Checkboxes: selected 1 (saved)');
1198    $this->assertTrue(!isset($node->{$field_name}[1]), 'Checkboxes: unselected 2 (saved)');
1199    $this->drupalGet('node/'. $node->nid);
1200    $this->assertText($value1_alias, 'Checkboxes: selected 1 (displayed)');
1201    $this->assertNoText($value2_alias, 'Checkboxes: unselected 2 (displayed)');
1202
1203    // Edit the node and unselect the values (selecting nothing -
1204    // there is no 'none' choice for checkboxes).
1205    $edit = array(
1206      $field_name.'[value]['. $value1 .']' => FALSE,
1207      $field_name.'[value]['. $value2 .']' => FALSE,
1208    );
1209    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1210    $node = node_load($node->nid, NULL, TRUE);
1211    $this->assertIdentical($node->{$field_name}[0]['value'], NULL, 'Checkboxes: unselected 1 (no selection) (saved)');
1212    $this->assertTrue(!isset($node->{$field_name}[1]), 'Checkboxes: unselected 2 (no selection) (saved)');
1213    $this->drupalGet('node/'. $node->nid);
1214    $this->assertNoText($value1_alias, 'Checkboxes: unselected 1 (no selection) (displayed)');
1215    $this->assertNoText($value2_alias, 'Checkboxes: unselected 2 (no selection) (displayed)');
1216
1217    // Change field to required.
1218    $field = $this->updateField(array('required' => '1'));
1219
1220    // Check the form doesn't submit when nothing is selected.
1221    $edit = array(
1222      $field_name.'[value]['. $value1 .']' => FALSE,
1223      $field_name.'[value]['. $value2 .']' => FALSE,
1224    );
1225    $this->drupalPost('node/'. $node->nid .'/edit', $edit, 'Save');
1226    $this->assertRaw(t('!name field is required.', array('!name' => t($field['widget']['label']))), 'Checkboxes: "required" property is respected');
1227
1228    $edit = array();
1229    $edit['title'] = $this->randomName(20);
1230    $edit['body'] = $this->randomName(20);
1231    $this->drupalPost('node/add/'. $type_url, $edit, 'Save');
1232    $this->assertRaw(t('!name field is required.', array('!name' => t($field['widget']['label']))), 'Checkboxes: "required" property is respected');
1233  }
1234
1235}
1236
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.