1<?php 2 3namespace dokuwiki\plugin\struct\test\action; 4 5use dokuwiki\ChangeLog\PageChangeLog; 6use dokuwiki\plugin\struct\meta; 7use dokuwiki\plugin\struct\test\mock\action_plugin_struct_edit; 8use dokuwiki\plugin\struct\test\mock\Assignments; 9use dokuwiki\plugin\struct\test\StructTest; 10use DOMWrap\Document; 11 12/** 13 * @group plugin_struct 14 * @group plugins 15 * 16 * @covers action_plugin_struct_revert 17 * @covers action_plugin_struct_edit 18 */ 19class EditTest extends StructTest 20{ 21 22 public function setUp(): void 23 { 24 parent::setUp(); 25 26 $this->loadSchemaJSON('schema1'); 27 $this->loadSchemaJSON('schema2', 'schema2int'); 28 $this->saveData( 29 'page01', 30 'schema1', 31 [ 32 'first' => 'first data', 33 'second' => ['second data', 'more data', 'even more'], 34 'third' => 'third data', 35 'fourth' => 'fourth data' 36 ], 37 time() 38 ); 39 } 40 41 /** 42 * Check if a field has the correct value 43 * 44 * @param Document $pq 45 * @param string $schema 46 * @param string $name 47 * @param string $value 48 */ 49 protected function checkField(Document $pq, $schema, $name, $value) 50 { 51 $this->assertEquals( 52 1, 53 $pq->find("span.label:contains('$name')")->count(), 54 "Field $schema.$name not found" 55 ); 56 $this->assertEquals( 57 $value, 58 $pq->find("input[name='struct_schema_data[$schema][$name]']")->attr('value'), 59 "Field $schema.$name has wrong value" 60 ); 61 } 62 63 public function test_createForm_storedData() 64 { 65 $edit = new action_plugin_struct_edit(); 66 global $ID; 67 $ID = 'page01'; 68 $test_html = $edit->createForm('schema1'); 69 70 $doc = new Document(); 71 $doc->html($test_html); 72 $this->assertEquals('schema1', $doc->find('legend')->text()); 73 $this->checkField($doc, 'schema1', 'first', 'first data'); 74 $this->checkField($doc, 'schema1', 'second', 'second data, more data, even more'); 75 $this->checkField($doc, 'schema1', 'third', 'third data'); 76 $this->checkField($doc, 'schema1', 'fourth', 'fourth data'); 77 } 78 79 public function test_createForm_emptyData() 80 { 81 $edit = new action_plugin_struct_edit(); 82 global $ID; 83 $ID = 'page02'; 84 $test_html = $edit->createForm('schema1'); 85 86 $doc = new Document(); 87 $doc->html($test_html); 88 $this->assertEquals('schema1', $doc->find('legend')->text()); 89 $this->checkField($doc, 'schema1', 'first', ''); 90 $this->checkField($doc, 'schema1', 'second', ''); 91 $this->checkField($doc, 'schema1', 'third', ''); 92 $this->checkField($doc, 'schema1', 'fourth', ''); 93 } 94 95 public function test_createForm_postData() 96 { 97 global $INPUT, $ID; 98 $ID = 'page01'; 99 $structdata = [ 100 'schema1' => [ 101 'first' => 'first post data', 102 'second' => ['second post data', 'more post data', 'even more post data'], 103 'third' => 'third post data', 104 'fourth' => 'fourth post data' 105 ] 106 ]; 107 $INPUT->set(action_plugin_struct_edit::getVAR(), $structdata); 108 109 $edit = new action_plugin_struct_edit(); 110 $test_html = $edit->createForm('schema1'); 111 112 $doc = new Document(); 113 $doc->html($test_html); 114 $this->assertEquals('schema1', $doc->find('legend')->text()); 115 $this->checkField($doc, 'schema1', 'first', 'first post data'); 116 $this->checkField($doc, 'schema1', 'second', 'second post data, more post data, even more post data'); 117 $this->checkField($doc, 'schema1', 'third', 'third post data'); 118 $this->checkField($doc, 'schema1', 'fourth', 'fourth post data'); 119 } 120 121 public function test_edit_page_wo_schema() 122 { 123 $page = 'test_edit_page_wo_schema'; 124 125 $request = new \TestRequest(); 126 $response = $request->get(['id' => $page, 'do' => 'edit'], '/doku.php'); 127 $structElement = $response->queryHTML('.struct_entry_form'); 128 129 $this->assertCount(1, $structElement); 130 $this->assertEquals('', $structElement->html()); 131 } 132 133 public function test_edit_page_with_schema() 134 { 135 $page = 'test_edit_page_with_schema'; 136 $assignment = Assignments::getInstance(); 137 $schema = 'schema2'; 138 $assignment->addPattern($page, $schema); 139 140 $request = new \TestRequest(); 141 $response = $request->get(['id' => $page, 'do' => 'edit'], '/doku.php'); 142 $test_html = trim($response->queryHTML('.struct_entry_form')->html()); 143 144 $doc = new Document(); 145 $doc->html($test_html); 146 $this->assertEquals('schema2', $doc->find('legend')->text()); 147 $this->checkField($doc, 'schema2', 'afirst', ''); 148 $this->checkField($doc, 'schema2', 'asecond', ''); 149 $this->checkField($doc, 'schema2', 'athird', ''); 150 $this->checkField($doc, 'schema2', 'afourth', ''); 151 } 152 153 public function test_preview_page_invaliddata() 154 { 155 $page = 'test_preview_page_invaliddata'; 156 $assignment = Assignments::getInstance(); 157 $schema = 'schema2'; 158 $assignment->addPattern($page, $schema); 159 160 $request = new \TestRequest(); 161 $structData = [ 162 $schema => [ 163 'afirst' => 'foo', 164 'asecond' => 'bar, baz', 165 'athird' => 'foobar', 166 'afourth' => 'Eve' 167 ] 168 ]; 169 $request->setPost('struct_schema_data', $structData); 170 $response = $request->post(['id' => $page, 'do' => 'preview']); 171 $expected_errormsg = sprintf($this->getLang('validation_prefix') . $this->getLang('Validation Exception Decimal needed'), 'afourth'); 172 $actual_errormsg = $response->queryHTML('.error')->html(); 173 $test_html = trim($response->queryHTML('.struct_entry_form')->html()); 174 175 $this->assertEquals($expected_errormsg, $actual_errormsg, 'If there is invalid data, then there should be an error message.'); 176 177 $doc = new Document(); 178 $doc->html($test_html); 179 $this->assertEquals('schema2', $doc->find('legend')->text()); 180 $this->checkField($doc, 'schema2', 'afirst', 'foo'); 181 $this->checkField($doc, 'schema2', 'asecond', 'bar, baz'); 182 $this->checkField($doc, 'schema2', 'athird', 'foobar'); 183 $this->checkField($doc, 'schema2', 'afourth', 'Eve'); 184 } 185 186 public function test_preview_page_validdata() 187 { 188 $page = 'test_preview_page_validdata'; 189 $assignment = Assignments::getInstance(); 190 $schema = 'schema2'; 191 $assignment->addPattern($page, $schema); 192 193 $request = new \TestRequest(); 194 $structData = [ 195 $schema => [ 196 'afirst' => 'foo', 197 'asecond' => 'bar, baz', 198 'athird' => 'foobar', 199 'afourth' => '42' 200 ] 201 ]; 202 $request->setPost('struct_schema_data', $structData); 203 $response = $request->post(['id' => $page, 'do' => 'preview']); 204 $actual_errormsg = $response->queryHTML('.error')->get(0); 205 $this->assertNull($actual_errormsg, "If all data is valid, then there should be no error message."); 206 207 $test_html = trim($response->queryHTML('.struct_entry_form')->html()); 208 209 $doc = new Document(); 210 $doc->html($test_html); 211 $this->assertEquals('schema2', $doc->find('legend')->text()); 212 $this->checkField($doc, 'schema2', 'afirst', 'foo'); 213 $this->checkField($doc, 'schema2', 'asecond', 'bar, baz'); 214 $this->checkField($doc, 'schema2', 'athird', 'foobar'); 215 $this->checkField($doc, 'schema2', 'afourth', '42'); 216 } 217 218 public function test_fail_saving_empty_page() 219 { 220 $page = 'test_fail_saving_empty_page'; 221 $assignment = Assignments::getInstance(); 222 $schema = 'schema2'; 223 $assignment->addPattern($page, $schema); 224 225 $request = new \TestRequest(); 226 $structData = [ 227 $schema => [ 228 'afirst' => 'foo', 229 'asecond' => 'bar, baz', 230 'athird' => 'foobar', 231 'afourth' => '42' 232 ] 233 ]; 234 $request->setPost('struct_schema_data', $structData); 235 $request->setPost('summary', 'only struct data saved'); 236 $response = $request->post(['id' => $page, 'do' => 'save'], '/doku.php'); 237 $expected_errormsg = $this->getLang('emptypage'); 238 $actual_errormsg = $response->queryHTML('.error')->html(); 239 $pagelog = new PageChangelog($page); 240 $revisions = $pagelog->getRevisions(-1, 200); 241 242 $this->assertCount(0, $revisions); 243 $this->assertEquals($expected_errormsg, $actual_errormsg, "An empty page should not be saved."); 244 } 245 246 public function test_fail_saveing_page_with_invaliddata() 247 { 248 $page = 'test_fail_saveing_page_with_invaliddata'; 249 $assignment = Assignments::getInstance(); 250 $schema = 'schema2'; 251 $assignment->addPattern($page, $schema); 252 253 $wikitext = 'teststring'; 254 $request = new \TestRequest(); 255 $structData = [ 256 $schema => [ 257 'afirst' => 'foo', 258 'asecond' => 'bar, baz', 259 'athird' => 'foobar', 260 'afourth' => 'Eve' 261 ] 262 ]; 263 $request->setPost('struct_schema_data', $structData); 264 $request->setPost('wikitext', $wikitext); 265 $request->setPost('summary', 'content and struct data saved'); 266 $response = $request->post(['id' => $page, 'do' => 'save']); 267 $actual_wikitext = trim($response->queryHTML('#wiki__text')->html()); 268 $expected_wikitext = $wikitext; 269 270 $actual_errormsg = $response->queryHTML('.error')->html(); 271 $expected_errormsg = sprintf($this->getLang('validation_prefix') . $this->getLang('Validation Exception Decimal needed'), 'afourth'); 272 273 $test_html = trim($response->queryHTML('.struct_entry_form')->html()); 274 275 $pagelog = new PageChangelog($page); 276 $revisions = $pagelog->getRevisions(-1, 200); 277 278 // assert 279 $this->assertCount(0, $revisions); 280 $this->assertEquals($expected_errormsg, $actual_errormsg, 'If there is invalid data, then there should be an error message.'); 281 $this->assertEquals($expected_wikitext, $actual_wikitext); 282 283 $doc = new Document(); 284 $doc->html($test_html); 285 $this->assertEquals('schema2', $doc->find('legend')->text()); 286 $this->checkField($doc, 'schema2', 'afirst', 'foo'); 287 $this->checkField($doc, 'schema2', 'asecond', 'bar, baz'); 288 $this->checkField($doc, 'schema2', 'athird', 'foobar'); 289 $this->checkField($doc, 'schema2', 'afourth', 'Eve'); 290 291 // todo: assert that no struct data has been saved 292 } 293 294 public function test_save_page() 295 { 296 $page = 'test_save_page'; 297 $assignment = Assignments::getInstance(); 298 $schema = 'schema2'; 299 $assignment->addPattern($page, $schema); 300 301 $request = new \TestRequest(); 302 $structData = [ 303 $schema => [ 304 'afirst' => 'foo', 305 'asecond' => 'bar, baz', 306 'athird' => 'foobar', 307 'afourth' => '42' 308 ] 309 ]; 310 $request->setPost('struct_schema_data', $structData); 311 $request->setPost('wikitext', 'teststring'); 312 $request->setPost('summary', 'content and struct data saved'); 313 $request->post(['id' => $page, 'do' => 'save']); 314 315 $pagelog = new PageChangelog($page); 316 $revisions = $pagelog->getRevisions(-1, 200); 317 $revinfo = $pagelog->getRevisionInfo($revisions[0]); 318 $schemaData = meta\AccessTable::getPageAccess($schema, $page, $revisions[0]); 319 $actual_struct_data = $schemaData->getDataArray(); 320 $expected_struct_data = [ 321 'afirst' => 'foo', 322 'asecond' => ['bar', 'baz'], 323 'athird' => 'foobar', 324 'afourth' => 42 325 ]; 326 327 $this->assertCount(1, $revisions); 328 $this->assertEquals('content and struct data saved', $revinfo['sum']); 329 $this->assertEquals(DOKU_CHANGE_TYPE_CREATE, $revinfo['type']); 330 $this->assertEquals($expected_struct_data, $actual_struct_data); 331 // todo: assert that pagerevision and struct data have the same timestamp 332 } 333 334 /** 335 * @group slow 336 */ 337 public function test_save_page_without_new_text() 338 { 339 $page = 'test_save_page_without_new_text'; 340 $assignment = Assignments::getInstance(); 341 $schema = 'schema2'; 342 $assignment->addPattern($page, $schema); 343 $wikitext = 'teststring'; 344 345 // first save; 346 $request = new \TestRequest(); 347 $structData = [ 348 $schema => [ 349 'afirst' => 'foo', 350 'asecond' => 'bar, baz', 351 'athird' => 'foobar', 352 'afourth' => '42' 353 ] 354 ]; 355 $request->setPost('struct_schema_data', $structData); 356 $request->setPost('wikitext', $wikitext); 357 $request->setPost('summary', 'content and struct data saved'); 358 $request->post(['id' => $page, 'do' => 'save']); 359 360 $this->waitForTick(true); 361 362 // second save - only struct data 363 $request = new \TestRequest(); 364 $structData = [ 365 $schema => [ 366 'afirst' => 'foo2', 367 'asecond' => 'bar2, baz2', 368 'athird' => 'foobar2', 369 'afourth' => '43' 370 ] 371 ]; 372 $request->setPost('struct_schema_data', $structData); 373 $request->setPost('wikitext', $wikitext); 374 $request->setPost('summary', '2nd revision'); 375 $request->post(['id' => $page, 'do' => 'save']); 376 377 // assert 378 $pagelog = new PageChangelog($page); 379 $revisions = $pagelog->getRevisions(-1, 200); 380 $revinfo = $pagelog->getRevisionInfo($revisions[0]); 381 $schemaData = meta\AccessTable::getPageAccess($schema, $page, $revisions[0]); 382 $actual_struct_data = $schemaData->getDataArray(); 383 $expected_struct_data = [ 384 'afirst' => 'foo2', 385 'asecond' => ['bar2', 'baz2'], 386 'athird' => 'foobar2', 387 'afourth' => 43 388 ]; 389 390 $this->assertCount(2, $revisions, 'there should be 2 (two) revisions'); 391 $this->assertEquals('2nd revision', $revinfo['sum']); 392 $this->assertEquals(DOKU_CHANGE_TYPE_EDIT, $revinfo['type']); 393 $this->assertEquals($expected_struct_data, $actual_struct_data); 394 // todo: assert that pagerevisions and struct entries have the same timestamps 395 } 396 397 /** 398 * @group slow 399 */ 400 public function test_delete_page() 401 { 402 $page = 'test_delete_page'; 403 $assignment = Assignments::getInstance(); 404 $schema = 'schema2'; 405 $assignment->addPattern($page, $schema); 406 $wikitext = 'teststring'; 407 408 // first save; 409 $request = new \TestRequest(); 410 $structData = [ 411 $schema => [ 412 'afirst' => 'foo', 413 'asecond' => 'bar, baz', 414 'athird' => 'foobar', 415 'afourth' => '42' 416 ] 417 ]; 418 $request->setPost('struct_schema_data', $structData); 419 $request->setPost('wikitext', $wikitext); 420 $request->setPost('summary', 'content and struct data saved'); 421 $request->post(['id' => $page, 'do' => 'save']); 422 423 $this->waitForTick(true); 424 425 // delete 426 $request = new \TestRequest(); 427 $structData = [ 428 $schema => [ 429 'afirst' => 'foo2', 430 'asecond' => 'bar2, baz2', 431 'athird' => 'foobar2', 432 'afourth' => '43' 433 ] 434 ]; 435 $request->setPost('struct_schema_data', $structData); 436 $request->setPost('wikitext', ''); 437 $request->setPost('summary', 'delete page'); 438 $request->post(['id' => $page, 'do' => 'save']); 439 440 // assert 441 $pagelog = new PageChangelog($page); 442 $revisions = $pagelog->getRevisions(-1, 200); 443 $revinfo = $pagelog->getRevisionInfo($revisions[0]); 444 $schemaData = meta\AccessTable::getPageAccess($schema, $page, $revisions[0]); 445 $actual_struct_data = $schemaData->getDataArray(); 446 $expected_struct_data = [ 447 'afirst' => '', 448 'asecond' => [], 449 'athird' => '', 450 'afourth' => '' 451 ]; 452 453 $this->assertCount(2, $revisions, 'there should be 2 (two) revisions'); 454 $this->assertEquals('delete page', $revinfo['sum']); 455 $this->assertEquals(DOKU_CHANGE_TYPE_DELETE, $revinfo['type']); 456 $this->assertEquals($expected_struct_data, $actual_struct_data); 457 // todo: timestamps? 458 } 459 460 /** 461 * @group slow 462 */ 463 public function test_revert_page() 464 { 465 $page = 'test_revert_page'; 466 $assignment = Assignments::getInstance(); 467 $schema = 'schema2'; 468 $assignment->addPattern($page, $schema); 469 $wikitext = 'teststring'; 470 471 global $conf; 472 $conf['useacl'] = 1; 473 $conf['superuser'] = 'admin'; 474 $_SERVER['REMOTE_USER'] = 'admin'; //now it's testing as admin 475 global $default_server_vars; 476 $default_server_vars['REMOTE_USER'] = 'admin'; //Hack until Issue #1099 is fixed 477 global $USERINFO; 478 $USERINFO['name'] = 'admin'; 479 $USERINFO['mail'] = 'admin@example.com'; 480 $USERINFO['grps'] = ['admin', 'user']; 481 482 // first save; 483 $request = new \TestRequest(); 484 $structData = [ 485 $schema => [ 486 'afirst' => 'foo', 487 'asecond' => 'bar, baz', 488 'athird' => 'foobar', 489 'afourth' => '42' 490 ] 491 ]; 492 $request->setPost('struct_schema_data', $structData); 493 $request->setPost('wikitext', $wikitext); 494 $request->setPost('summary', 'content and struct data saved'); 495 $request->post(['id' => $page, 'do' => 'save', 'sectok' => getSecurityToken()]); 496 497 $this->waitForTick(true); 498 499 // second save 500 $request = new \TestRequest(); 501 $structData = [ 502 $schema => [ 503 'afirst' => 'foo2', 504 'asecond' => 'bar2, baz2', 505 'athird' => 'foobar2', 506 'afourth' => '43' 507 ] 508 ]; 509 $request->setPost('struct_schema_data', $structData); 510 $request->setPost('wikitext', $wikitext . $wikitext); 511 $request->setPost('summary', 'delete page'); 512 $request->post(['id' => $page, 'do' => 'save', 'sectok' => getSecurityToken()]); 513 514 $this->waitForTick(true); 515 516 // revert to first save 517 $actpagelog = new PageChangelog($page); 518 $actrevisions = $actpagelog->getRevisions(0, 200); 519 520 $actrevinfo = $actpagelog->getRevisionInfo($actrevisions[0]); 521 $request = new \TestRequest(); 522 $request->setPost('summary', 'revert page'); 523 $request->post(['id' => $page, 'do' => 'revert', 'rev' => $actrevinfo['date'], 'sectok' => getSecurityToken()]); 524 525 // assert 526 $pagelog = new PageChangelog($page); 527 $revisions = $pagelog->getRevisions(-1, 200); 528 $revinfo = $pagelog->getRevisionInfo($revisions[0]); 529 $schemaData = meta\AccessTable::getPageAccess($schema, $page, $revisions[0]); 530 $actual_struct_data = $schemaData->getDataArray(); 531 $expected_struct_data = [ 532 'afirst' => 'foo', 533 'asecond' => ['bar', 'baz'], 534 'athird' => 'foobar', 535 'afourth' => '42' 536 ]; 537 538 $this->assertCount(3, $revisions, 'there should be 3 (three) revisions'); 539 $this->assertStringContainsString('restored', $revinfo['sum']); 540 $this->assertEquals(DOKU_CHANGE_TYPE_REVERT, $revinfo['type']); 541 $this->assertEquals($expected_struct_data, $actual_struct_data); 542 // todo: timestamps? 543 } 544 545} 546