11"""Word cloud integration tests using mongo modulestore."""
2-
3-
4- import pytest
5-
2+ import importlib
63import json
4+ import re
75from operator import itemgetter
6+ from unittest .mock import patch
7+ from uuid import UUID
88
9+ import pytest
10+ from django .conf import settings
11+ from django .test import override_settings
12+ from xblock import plugin
13+
14+ from common .djangoapps .student .tests .factories import RequestFactoryNoCsrf
15+ from xmodule import word_cloud_block
916# noinspection PyUnresolvedReferences
10- from xmodule .tests .helpers import override_descriptor_system # pylint: disable=unused-import
17+ from xmodule .tests .helpers import override_descriptor_system , mock_render_template # pylint: disable=unused-import
1118from xmodule .x_module import STUDENT_VIEW
12-
1319from .helpers import BaseTestXmodule
1420
1521
1622@pytest .mark .usefixtures ("override_descriptor_system" )
17- class TestWordCloud (BaseTestXmodule ):
23+ class _TestWordCloudBase (BaseTestXmodule ):
1824 """Integration test for Word Cloud Block."""
25+ __test__ = False
1926 CATEGORY = "word_cloud"
2027
28+ @classmethod
29+ def setUpClass (cls ):
30+ super ().setUpClass ()
31+ plugin .PLUGIN_CACHE = {}
32+ importlib .reload (word_cloud_block )
33+
34+ def setUp (self ):
35+ super ().setUp ()
36+ self .request_factory = RequestFactoryNoCsrf ()
37+
2138 def _get_users_state (self ):
2239 """Return current state for each user:
2340
@@ -27,7 +44,18 @@ def _get_users_state(self):
2744 users_state = {}
2845
2946 for user in self .users :
30- response = self .clients [user .username ].post (self .get_url ('get_state' ))
47+ if settings .USE_EXTRACTED_WORD_CLOUD_BLOCK :
48+ # The extracted Word Cloud XBlock uses @XBlock.json_handler, which expects a different
49+ # request format and url pattern
50+ handler_url = self .get_url ('' , handler_name = 'handle_get_state' )
51+ response = self .clients [user .username ].post (
52+ handler_url ,
53+ data = json .dumps ({}),
54+ content_type = 'application/json' ,
55+ HTTP_X_REQUESTED_WITH = 'XMLHttpRequest' ,
56+ )
57+ else :
58+ response = self .clients [user .username ].post (self .get_url ('get_state' ))
3159 users_state [user .username ] = json .loads (response .content .decode ('utf-8' ))
3260
3361 return users_state
@@ -40,19 +68,29 @@ def _post_words(self, words):
4068 users_state = {}
4169
4270 for user in self .users :
43- response = self .clients [user .username ].post (
44- self .get_url ('submit' ),
45- {'student_words[]' : words },
46- HTTP_X_REQUESTED_WITH = 'XMLHttpRequest'
47- )
71+ if settings .USE_EXTRACTED_WORD_CLOUD_BLOCK :
72+ # The extracted Word Cloud XBlock uses @XBlock.json_handler, which expects a different
73+ # request format and url pattern
74+ handler_url = self .get_url ('' , handler_name = 'handle_submit_state' )
75+ response = self .clients [user .username ].post (
76+ handler_url ,
77+ data = json .dumps ({'student_words' : words }),
78+ content_type = 'application/json' ,
79+ HTTP_X_REQUESTED_WITH = 'XMLHttpRequest' ,
80+ )
81+ else :
82+ response = self .clients [user .username ].post (
83+ self .get_url ('submit' ),
84+ {'student_words[]' : words },
85+ HTTP_X_REQUESTED_WITH = 'XMLHttpRequest'
86+ )
4887 users_state [user .username ] = json .loads (response .content .decode ('utf-8' ))
4988
5089 return users_state
5190
5291 def _check_response (self , response_contents , correct_jsons ):
5392 """Utility function that compares correct and real responses."""
5493 for username , content in response_contents .items ():
55-
5694 # Used in debugger for comparing objects.
5795 # self.maxDiff = None
5896
@@ -120,7 +158,6 @@ def test_post_words(self):
120158
121159 correct_state = {}
122160 for index , user in enumerate (self .users ):
123-
124161 correct_state [user .username ] = {
125162 'status' : 'success' ,
126163 'submitted' : True ,
@@ -202,6 +239,14 @@ def test_handle_ajax_incorrect_dispatch(self):
202239 for user in self .users
203240 }
204241
242+ if settings .USE_EXTRACTED_WORD_CLOUD_BLOCK :
243+ # The extracted Word Cloud XBlock uses @XBlock.json_handler to handle AJAX requests,
244+ # which automatically returns a 404 for unknown requests, so there's no need to test
245+ # the incorrect dispatch case in this scenario.
246+ for username , response in responses .items ():
247+ self .assertEqual (response .status_code , 404 )
248+ return
249+
205250 status_codes = {response .status_code for response in responses .values ()}
206251 assert status_codes .pop () == 200
207252
@@ -214,19 +259,44 @@ def test_handle_ajax_incorrect_dispatch(self):
214259 }
215260 )
216261
217- def test_word_cloud_constructor (self ):
262+ @patch ('xblock.utils.resources.ResourceLoader.render_django_template' , side_effect = mock_render_template )
263+ def test_word_cloud_constructor (self , mock_render_django_template ):
218264 """
219265 Make sure that all parameters extracted correctly from xml.
220266 """
221267 fragment = self .runtime .render (self .block , STUDENT_VIEW )
222268 expected_context = {
223- 'ajax_url' : self .block .ajax_url ,
224269 'display_name' : self .block .display_name ,
225270 'instructions' : self .block .instructions ,
226- 'element_class' : self .block .location .block_type ,
227- 'element_id' : self .block .location .html_id (),
271+ 'element_class' : self .block .scope_ids .block_type ,
228272 'num_inputs' : 5 , # default value
229273 'submitted' : False , # default value,
230274 }
231275
232- assert fragment .content == self .runtime .render_template ('word_cloud.html' , expected_context )
276+ if settings .USE_EXTRACTED_WORD_CLOUD_BLOCK :
277+ # If `USE_EXTRACTED_WORD_CLOUD_BLOCK` is enabled, the `expected_context` will be different
278+ # because in the extracted Word Cloud XBlock, the expected context:
279+ # - contains `range_num_inputs`
280+ # - uses `UUID` for `element_id` instead of `html_id()`
281+ # - does not include `ajax_url` since it uses the `@XBlock.json_handler` decorator for AJAX requests
282+ expected_context ['range_num_inputs' ] = range (5 )
283+ uuid_str = re .search (r"UUID\('([a-f0-9\-]+)'\)" , fragment .content ).group (1 )
284+ expected_context ['element_id' ] = UUID (uuid_str )
285+ mock_render_django_template .assert_called_once ()
286+ # Remove i18n service
287+ fragment_content_clean = re .sub (r"\{.*?}" , "{}" , fragment .content )
288+ assert fragment_content_clean == self .runtime .render_template ('templates/word_cloud.html' , expected_context )
289+ else :
290+ expected_context ['ajax_url' ] = self .block .ajax_url
291+ expected_context ['element_id' ] = self .block .location .html_id ()
292+ assert fragment .content == self .runtime .render_template ('word_cloud.html' , expected_context )
293+
294+
295+ @override_settings (USE_EXTRACTED_WORD_CLOUD_BLOCK = True )
296+ class TestWordCloudExtracted (_TestWordCloudBase ):
297+ __test__ = True
298+
299+
300+ @override_settings (USE_EXTRACTED_WORD_CLOUD_BLOCK = False )
301+ class TestWordCloudBuiltIn (_TestWordCloudBase ):
302+ __test__ = True
0 commit comments