book.test 13.1 KB
Newer Older
1
2
<?php

3
4
5
6
7
/**
 * @file
 * Tests for book.module.
 */

8
9
class BookTestCase extends DrupalWebTestCase {
  protected $book;
10
  // $book_author is a user with permission to create and edit books.
11
  protected $book_author;
12
  // $web_user is a user with permission to view a book
13
14
  // and access the printer-friendly version.
  protected $web_user;
15
16
17
  // $admin_user is a user with permission to create and edit books and to administer blocks.
  protected $admin_user;

18
  public static function getInfo() {
19
    return array(
20
21
22
      'name' => 'Book functionality',
      'description' => 'Create a book, add pages, and test book interface.',
      'group' => 'Book',
23
24
25
26
    );
  }

  function setUp() {
27
28
29
30
    parent::setUp(array('book', 'node_access_test'));

    // node_access_test requires a node_access_rebuild().
    node_access_rebuild();
31

32
33
    // Create users.
    $this->book_author = $this->drupalCreateUser(array('create new books', 'create book content', 'edit own book content', 'add content to books'));
34
35
    $this->web_user = $this->drupalCreateUser(array('access printer-friendly version', 'node test view'));
    $this->admin_user = $this->drupalCreateUser(array('create new books', 'create book content', 'edit own book content', 'add content to books', 'administer blocks', 'administer permissions'));
36
  }
37

38
  /**
39
   * Create a new book with a page hierarchy.
40
   */
41
  function createBook() {
42
    // Create new book.
43
    $this->drupalLogin($this->book_author);
44
45
46
47
48

    $this->book = $this->createBookNode('new');
    $book = $this->book;

    /*
49
     * Add page hierarchy to book.
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
     * Book
     *  |- Node 0
     *   |- Node 1
     *   |- Node 2
     *  |- Node 3
     *  |- Node 4
     */
    $nodes = array();
    $nodes[] = $this->createBookNode($book->nid); // Node 0.
    $nodes[] = $this->createBookNode($book->nid, $nodes[0]->book['mlid']); // Node 1.
    $nodes[] = $this->createBookNode($book->nid, $nodes[0]->book['mlid']); // Node 2.
    $nodes[] = $this->createBookNode($book->nid); // Node 3.
    $nodes[] = $this->createBookNode($book->nid); // Node 4.

    $this->drupalLogout();
65

66
67
68
69
70
71
72
73
74
75
    return $nodes;
  }

  /**
   * Test book functionality through node interfaces.
   */
  function testBook() {
    // Create new book.
    $nodes = $this->createBook();
    $book = $this->book;
76

77
    $this->drupalLogin($this->web_user);
78

79
80
81
82
83
84
85
86
    // Check that book pages display along with the correct outlines and
    // previous/next links.
    $this->checkBookNode($book, array($nodes[0], $nodes[3], $nodes[4]), FALSE, FALSE, $nodes[0], array());
    $this->checkBookNode($nodes[0], array($nodes[1], $nodes[2]), $book, $book, $nodes[1], array($book));
    $this->checkBookNode($nodes[1], NULL, $nodes[0], $nodes[0], $nodes[2], array($book, $nodes[0]));
    $this->checkBookNode($nodes[2], NULL, $nodes[1], $nodes[0], $nodes[3], array($book, $nodes[0]));
    $this->checkBookNode($nodes[3], NULL, $nodes[2], $book, $nodes[4], array($book));
    $this->checkBookNode($nodes[4], NULL, $nodes[3], $book, FALSE, array($book));
87
88
89
90

    $this->drupalLogout();

    // Create a second book, and move an existing book page into it.
91
    $this->drupalLogin($this->book_author);
92
93
94
95
96
97
    $other_book = $this->createBookNode('new');
    $node = $this->createBookNode($book->nid);
    $edit = array('book[bid]' => $other_book->nid);
    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));

    $this->drupalLogout();
98
    $this->drupalLogin($this->web_user);
99
100
101
102
103

    // Check that the nodes in the second book are displayed correctly.
    // First we must set $this->book to the second book, so that the
    // correct regex will be generated for testing the outline.
    $this->book = $other_book;
104
105
    $this->checkBookNode($other_book, array($node), FALSE, FALSE, $node, array());
    $this->checkBookNode($node, NULL, $other_book, $other_book, FALSE, array($other_book));
106
107
108
  }

  /**
109
   * Check the outline of sub-pages; previous, up, and next; and printer friendly version.
110
   *
111
   * @param $node
112
   *   Node to check.
113
   * @param $nodes
114
   *   Nodes that should be in outline.
115
   * @param $previous
116
   *   Previous link node.
117
   * @param $up
118
   *   Up link node.
119
   * @param $next
120
   *   Next link node.
121
122
   * @param $breadcrumb
   *   The nodes that should be displayed in the breadcrumb.
123
   */
124
  function checkBookNode($node, $nodes, $previous = FALSE, $up = FALSE, $next = FALSE, array $breadcrumb) {
125
126
    // $number does not use drupal_static as it should not be reset
    // since it uniquely identifies each call to checkBookNode().
127
128
129
130
131
    static $number = 0;
    $this->drupalGet('node/' . $node->nid);

    // Check outline structure.
    if ($nodes !== NULL) {
132
      $this->assertPattern($this->generateOutlinePattern($nodes), t('Node ' . $number . ' outline confirmed.'));
133
134
    }
    else {
135
      $this->pass(t('Node ' . $number . ' doesn\'t have outline.'));
136
137
138
139
    }

    // Check previous, up, and next links.
    if ($previous) {
140
      $this->assertRaw(l('<b>‹</b> ' . $previous->title, 'node/' . $previous->nid, array('html'=> TRUE, 'attributes' => array('rel' => array('prev'), 'title' => t('Go to previous page')))), t('Previous page link found.'));
141
    }
142

143
    if ($up) {
144
      $this->assertRaw(l('up', 'node/' . $up->nid, array('html'=> TRUE,'attributes' => array('title' => t('Go to parent page')))), t('Up page link found.'));
145
    }
146

147
    if ($next) {
148
      $this->assertRaw(l($next->title . ' <b>›</b>', 'node/' . $next->nid, array('html'=> TRUE, 'attributes' => array('rel' => array('next'), 'title' => t('Go to next page')))), t('Next page link found.'));
149
150
    }

151
152
153
154
155
156
157
158
    // Compute the expected breadcrumb.
    $expected_breadcrumb = array();
    $expected_breadcrumb[] = url('');
    foreach ($breadcrumb as $a_node) {
      $expected_breadcrumb[] = url('node/' . $a_node->nid);
    }

    // Fetch links in the current breadcrumb.
159
    $links = $this->xpath('//nav[@class="breadcrumb"]/ol/li/a');
160
161
162
163
164
165
    $got_breadcrumb = array();
    foreach ($links as $link) {
      $got_breadcrumb[] = (string) $link['href'];
    }

    // Compare expected and got breadcrumbs.
166
    $this->assertIdentical($expected_breadcrumb, $got_breadcrumb, t('The breadcrumb is correctly displayed on the page.'));
167

168
169
    // Check printer friendly version.
    $this->drupalGet('book/export/html/' . $node->nid);
170
171
    $this->assertText($node->title, t('Printer friendly title found.'));
    $this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), t('Printer friendly body found.'));
172
173
174
175
176
177
178
179
180
181
182
183

    $number++;
  }

  /**
   * Create a regular expression to check for the sub-nodes in the outline.
   *
   * @param array $nodes Nodes to check in outline.
   */
  function generateOutlinePattern($nodes) {
    $outline = '';
    foreach ($nodes as $node) {
184
      $outline .= '(node\/' . $node->nid . ')(.*?)(' . $node->title . ')(.*?)';
185
186
    }

187
    return '/<nav id="book-navigation-' . $this->book->nid . '"(.*?)<ul(.*?)' . $outline . '<\/ul>/s';
188
189
190
191
192
193
194
195
196
  }

  /**
   * Create book node.
   *
   * @param integer $book_nid Book node id or set to 'new' to create new book.
   * @param integer $parent Parent book reference id.
   */
  function createBookNode($book_nid, $parent = NULL) {
197
198
    // $number does not use drupal_static as it should not be reset
    // since it uniquely identifies each call to createBookNode().
199
200
201
    static $number = 0; // Used to ensure that when sorted nodes stay in same order.

    $edit = array();
202
    $langcode = LANGUAGE_NONE;
203
    $edit["title"] = $number . ' - SimpleTest test node ' . $this->randomName(10);
204
    $edit["body[$langcode][0][value]"] = 'SimpleTest test body ' . $this->randomName(32) . ' ' . $this->randomName(32);
205
206
207
208
209
210
211
212
213
214
215
216
217
    $edit['book[bid]'] = $book_nid;

    if ($parent !== NULL) {
      $this->drupalPost('node/add/book', $edit, t('Change book (update list of parents)'));

      $edit['book[plid]'] = $parent;
      $this->drupalPost(NULL, $edit, t('Save'));
    }
    else {
      $this->drupalPost('node/add/book', $edit, t('Save'));
    }

    // Check to make sure the book node was created.
218
    $node = $this->drupalGetNodeByTitle($edit['title']);
219
    $this->assertNotNull(($node === FALSE ? NULL : $node), t('Book node found in database.'));
220
221
222
223
    $number++;

    return $node;
  }
224

225
226
227
228
229
230
  /**
   * Tests book export ("printer-friendly version") functionality.
   */
  function testBookExport() {
    // Create a book.
    $nodes = $this->createBook();
231

232
233
234
235
    // Login as web user and view printer-friendly version.
    $this->drupalLogin($this->web_user);
    $this->drupalGet('node/' . $this->book->nid);
    $this->clickLink(t('Printer-friendly version'));
236

237
238
    // Make sure each part of the book is there.
    foreach ($nodes as $node) {
239
240
      $this->assertText($node->title, t('Node title found in printer friendly version.'));
      $this->assertRaw(check_markup($node->body[LANGUAGE_NONE][0]['value'], $node->body[LANGUAGE_NONE][0]['format']), t('Node body found in printer friendly version.'));
241
    }
242

243
244
    // Make sure we can't export an unsupported format.
    $this->drupalGet('book/export/foobar/' . $this->book->nid);
245
246
    $this->assertResponse('404', t('Unsupported export format returned "not found".'));

247
248
249
250
    // Make sure we get a 404 on a not existing book node.
    $this->drupalGet('book/export/html/123');
    $this->assertResponse('404', t('Not existing book node returned "not found".'));

251
252
    // Make sure an anonymous user cannot view printer-friendly version.
    $this->drupalLogout();
253

254
255
    // Load the book and verify there is no printer-friendly version link.
    $this->drupalGet('node/' . $this->book->nid);
256
    $this->assertNoLink(t('Printer-friendly version'), t('Anonymous user is not shown link to printer-friendly version.'));
257

258
259
    // Try getting the URL directly, and verify it fails.
    $this->drupalGet('book/export/html/' . $this->book->nid);
260
    $this->assertResponse('403', t('Anonymous user properly forbidden.'));
261
  }
262

263
264
265
  /**
   * Tests the functionality of the book navigation block.
   */
266
  function testBookNavigationBlock() {
267
268
269
270
271
    $this->drupalLogin($this->admin_user);

    // Set block title to confirm that the interface is available.
    $block_title = $this->randomName(16);
    $this->drupalPost('admin/structure/block/manage/book/navigation/configure', array('title' => $block_title), t('Save block'));
272
    $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));
273

274
    // Set the block to a region to confirm block is available.
275
    $edit = array();
276
    $edit['blocks[book_navigation][region]'] = 'footer';
277
    $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
278
    $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));
279

280
281
282
283
284
285
     // Give anonymous users the permission 'node test view'.
     $edit = array();
     $edit['1[node test view]'] = TRUE;
     $this->drupalPost('admin/people/permissions/1', $edit, t('Save permissions'));
     $this->assertText(t('The changes have been saved.'), t("Permission 'node test view' successfully assigned to anonymous users."));

286
287
288
289
290
291
    // Test correct display of the block.
    $nodes = $this->createBook();
    $this->drupalGet('<front>');
    $this->assertText($block_title, t('Book navigation block is displayed.'));
    $this->assertText($this->book->title, t('Link to book root (@title) is displayed.', array('@title' => $nodes[0]->title)));
    $this->assertNoText($nodes[0]->title, t('No links to individual book pages are displayed.'));
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

  /**
   * Test the book navigation block when an access module is enabled.
   */
   function testNavigationBlockOnAccessModuleEnabled() {
     $this->drupalLogin($this->admin_user);
     $edit = array();

     // Set the block title.
     $block_title = $this->randomName(16);
     $edit['title'] = $block_title;

     // Set block display to 'Show block only on book pages'.
     $edit['book_block_mode'] = 'book pages';
     $this->drupalPost('admin/structure/block/manage/book/navigation/configure', $edit, t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block configuration set.'));

     // Set the block to a region to confirm block is available.
     $edit = array();
     $edit['blocks[book_navigation][region]'] = 'footer';
     $this->drupalPost('admin/structure/block', $edit, t('Save blocks'));
     $this->assertText(t('The block settings have been updated.'), t('Block successfully move to footer region.'));

     // Give anonymous users the permission 'node test view'.
     $edit = array();
     $edit['1[node test view]'] = TRUE;
     $this->drupalPost('admin/people/permissions/1', $edit, t('Save permissions'));
     $this->assertText(t('The changes have been saved.'), t('Permission \'node test view\' successfully assigned to anonymous users.'));

     // Create a book.
     $this->createBook();

     // Test correct display of the block to registered users.
     $this->drupalLogin($this->web_user);
     $this->drupalGet('node/' . $this->book->nid);
     $this->assertText($block_title, t('Book navigation block is displayed to registered users.'));
     $this->drupalLogout();

     // Test correct display of the block to anonymous users.
     $this->drupalGet('node/' . $this->book->nid);
     $this->assertText($block_title, t('Book navigation block is displayed to anonymous users.'));
   }
335
}