MDL-67814 core_h5p: added renderer and editor classes
[moodle.git] / h5p / tests / editor_test.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Testing the Moodle local class for managing the H5P Editor.
19  *
20  * @package    core_h5p
21  * @category   test
22  * @copyright  2020 Victor Deniz <victor@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
25 namespace core_h5p;
27 use advanced_testcase;
28 use core_h5p\local\library\autoloader;
29 use moodleform;
30 use MoodleQuickForm;
31 use page_requirements_manager;
33 /**
34  *
35  * Test class covering the editor class.
36  *
37  * @package    core_h5p
38  * @copyright  2020 Victor Deniz <victor@moodle.com>
39  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40  *
41  * @runTestsInSeparateProcesses
42  */
43 class editor_testcase extends advanced_testcase {
45     /**
46      * Test that existing content is properly set.
47      */
48     public function test_set_content() {
49         $this->resetAfterTest();
51         autoloader::register();
53         // Add H5P content.
54         // This is a valid .H5P file.
55         $filename = 'find-the-words.h5p';
56         $path = __DIR__ . '/fixtures/' . $filename;
57         $syscontext = \context_system::instance();
58         $filerecord = [
59             'contextid' => $syscontext->id,
60             'component' => \core_h5p\file_storage::COMPONENT,
61             'filearea' => 'unittest',
62             'itemid' => 0,
63             'filepath' => '/',
64             'filename' => $filename,
65         ];
66         // Load the h5p file into DB.
67         $fs = get_file_storage();
68         $file = $fs->create_file_from_pathname($filerecord, $path);
69         // Make the URL to pass to the WS.
70         $url = \moodle_url::make_pluginfile_url(
71             $syscontext->id,
72             \core_h5p\file_storage::COMPONENT,
73             'unittest',
74             0,
75             '/',
76             $filename
77         );
78         $config = new \stdClass();
80         $h5pplayer = new player($url->out(), $config);
82         // Call the method. We need the id of the new H5P content.
83         $rc = new \ReflectionClass(player::class);
84         $rcp = $rc->getProperty('h5pid');
85         $rcp->setAccessible(true);
86         $h5pid = $rcp->getValue($h5pplayer);
88         $editor = new editor();
89         $editor->set_content($h5pid);
91         // Check we get the H5P content.
92         $rc = new \ReflectionClass(editor::class);
93         $rcp = $rc->getProperty('oldcontent');
94         $rcp->setAccessible(true);
95         $oldcontent = $rcp->getValue($editor);
97         $core = (new factory)->get_core();
98         $this->assertSame($core->loadContent($h5pid), $oldcontent);
100         // Check we get the file of the H5P content.
101         $rcp = $rc->getProperty('oldfile');
102         $rcp->setAccessible(true);
103         $oldfile = $rcp->getValue($editor);
105         $this->assertSame($file->get_contenthash(), $oldfile->get_contenthash());
106     }
108     /**
109      * Tests that library and file area are properly set.
110      */
111     public function test_set_library() {
112         global $USER;
114         $library = 'H5P.Accordion 1.5';
115         $contextid = 1;
116         $filearea = 'unittest';
117         $filename = 'export.h5p';
119         // Call method.
120         $editor = new editor();
121         $editor->set_library($library, $contextid, file_storage::COMPONENT, $filearea, 0, '/', $filename);
123         // Check that the library has the right value.
124         $rc = new \ReflectionClass(editor::class);
125         $rcp = $rc->getProperty('library');
126         $rcp->setAccessible(true);
127         $actual = $rcp->getValue($editor);
129         $this->assertSame($library, $actual);
131         // Check that the file area has the right value.
132         $expected = [
133             'contextid' => $contextid,
134             'component' => file_storage::COMPONENT,
135             'filearea' => $filearea,
136             'itemid' => 0,
137             'filepath' => '/',
138             'filename' => $filename,
139             'userid' => $USER->id
140         ];
142         $rcp = $rc->getProperty('filearea');
143         $rcp->setAccessible(true);
144         $actual = $rcp->getValue($editor);
146         $this->assertEquals($expected, $actual);
147     }
149     /**
150      * Test that required assets (js and css) and form will be loaded in page.
151      */
152     public function test_add_editor_to_form() {
153         global $PAGE, $CFG;
155         // Get form data.
156         $form = new temp_form();
157         $mform = $form->getform();
159         // Call method.
160         $editor = new editor();
161         $editor->add_editor_to_form($mform);
163         // Check $PAGE has the expected css and js scripts.
164         $rc = new \ReflectionClass(page_requirements_manager::class);
165         $rcp = $rc->getProperty('cssurls');
166         $rcp2 = $rc->getProperty('jsincludes');
167         $rcp->setAccessible(true);
168         $rcp2->setAccessible(true);
169         $actualcss = array_keys($rcp->getValue($PAGE->requires));
170         $actualjs = array_keys($rcp2->getValue($PAGE->requires)['head']);
171         $cachebuster = helper::get_cache_buster();
173         $h5pcorepath = autoloader::get_h5p_core_library_url()->out();
175         $expectedcss = \H5PCore::$styles;
176         $expectedjs = \H5PCore::$scripts;
178         array_walk($expectedcss, function(&$item, $key) use ($h5pcorepath, $cachebuster) {
179             $item = $h5pcorepath . $item. $cachebuster;
181         });
183         array_walk($expectedjs, function(&$item, $key) use ($h5pcorepath, $cachebuster) {
184             $item = $h5pcorepath . $item . $cachebuster;
185         });
187         // Add translation script.
188         $language = framework::get_language();
189         $languagescript = "language/{$language}.js";
191         if (!file_exists($CFG->dirroot . autoloader::get_h5p_editor_library_base($languagescript))) {
192             $languagescript = 'language/en.js';
193         }
194         $expectedjs[] = autoloader::get_h5p_editor_library_url($languagescript . $cachebuster)->out();
196         $expectedjs[] = (new \moodle_url('/h5p/js/h5p_overrides.js' . $cachebuster))->out();
197         $expectedjs[] = autoloader::get_h5p_editor_library_url('scripts/h5peditor-editor.js' . $cachebuster)->out();
198         $expectedjs[] = autoloader::get_h5p_editor_library_url('scripts/h5peditor-init.js' . $cachebuster)->out();
200         // Sort arrays before comparison.
201         sort($actualcss);
202         sort($actualjs);
203         sort($expectedcss);
204         sort($expectedjs);
206         $this->assertSame($expectedcss, $actualcss);
207         $this->assertSame($expectedjs, $actualjs);
209         // H5P Editor expected form fields.
210         $this->assertTrue($mform->elementExists('h5pparams'));
211         $this->assertTrue($mform->elementExists('h5plibrary'));
212         $this->assertTrue($mform->elementExists('h5paction'));
213     }
215     /**
216      * Test new content creation.
217      */
218     public function test_save_content() {
219         global $DB;
221         $this->resetAfterTest();
223         // Fake form data sent during creation.
224         $data = new \stdClass();
225         $data->h5plibrary = "H5P.ArithmeticQuiz 1.1";
226         $data->h5pparams = '{"params":{"quizType":"arithmetic","arithmeticType":"addition","UI":{"score":"Score:","time":"Time: @time"},
227                 "intro":"This is a content for testing"},"metadata":{"defaultLanguage":"en","title":"Testing content"}}';
229         $title = 'libtest';
230         $library = 'H5P.ArithmeticQuiz 1.1';
231         $machinename = 'H5P.ArithmeticQuiz';
232         $contextid = 1;
233         $filearea = 'unittest';
234         $filename = 'export.h5p';
236         // Fake installed library for the H5P content.
237         $generator = $this->getDataGenerator()->get_plugin_generator('core_h5p');
239         $semantics = json_encode([['type' => 'text', 'name' => 'text', 'label' => 'Plain text', 'description' => 'Some text']]);
240         $generator->create_library_record($machinename, $title, 1, 1, 2, $semantics);
242         $editor = new editor();
243         $editor->set_library($library, $contextid, file_storage::COMPONENT, $filearea, 0, '/', $filename);
244         $newcontentid = $editor->save_content($data);
246         // Check the H5P content file was created where expected.
247         $fs = get_file_storage();
248         $out = $fs->get_file($contextid, file_storage::COMPONENT, $filearea, 0, '/', $filename);
249         $this->assertNotEmpty($out);
250     }
253 /**
254  * Form object to be used in test case.
255  */
256 class temp_form extends moodleform {
257     /**
258      * Form definition.
259      */
260     public function definition(): void {
261         // No definition required.
262     }
264     /**
265      * Returns form reference.
266      *
267      * @return MoodleQuickForm
268      */
269     public function getform() {
270         $mform = $this->_form;
271         // Set submitted flag, to simulate submission.
272         $mform->_flagSubmitted = true;
273         return $mform;
274     }