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