###########################
How to test your extensions
###########################

************
Testing Apps
************

Resolving View Names
====================

Your apps need testing, but in your live site they aren't in ``urls.py`` as
they are attached to a CMS page.  So if you want to be able to use
:func:`~django.urls.reverse()` in your tests, or test templates that
use the :ttag:`url` template tag, you need to hook up your app to a special
test version of ``urls.py`` and tell your tests to use that.

So you could create ``myapp/tests/urls.py`` with the following code::

    from django.contrib import admin
    from django.urls import re_path, include

    urlpatterns = [
        re_path(r'^admin/', admin.site.urls),
        re_path(r'^myapp/', include('myapp.urls')),
        re_path(r'', include('cms.urls')),
    ]

And then in your tests you can plug this in with the
:func:`~django.test.override_settings` decorator::

    from django.test.utils import override_settings
    from cms.test_utils.testcases import CMSTestCase

    class MyappTests(CMSTestCase):

        @override_settings(ROOT_URLCONF='myapp.tests.urls')
        def test_myapp_page(self):
            test_url = reverse('myapp_view_name')
            # rest of test as normal

If you want to the test url conf throughout your test class, then you can use
apply the decorator to the whole class::

    from django.test.utils import override_settings
    from cms.test_utils.testcases import CMSTestCase

    @override_settings(ROOT_URLCONF='myapp.tests.urls')
    class MyappTests(CMSTestCase):

        def test_myapp_page(self):
            test_url = reverse('myapp_view_name')
            # rest of test as normal

CMSTestCase
===========

Django CMS includes ``CMSTestCase`` which has various utility methods that
might be useful for testing your CMS app and manipulating CMS pages.


***************
Testing Plugins
***************

To test plugins, you need to assign them to a placeholder. Depending on at what
level you want to test your plugin, you can either check the HTML generated by
it or the context provided to its template::


    from django.test import TestCase
    from django.test.client import RequestFactory

    from cms.api import add_plugin
    from cms.models import Placeholder
    from cms.plugin_rendering import ContentRenderer

    from myapp.cms_plugins import MyPlugin
    from myapp.models import MyappPlugin

    class MypluginTests(TestCase):
        def test_plugin_context(self):
            placeholder = Placeholder.objects.create(slot='test')
            model_instance = add_plugin(
                placeholder,
                MyPlugin,
                'en',
            )
            plugin_instance = model_instance.get_plugin_class_instance()
            context = plugin_instance.render({}, model_instance, None)
            self.assertIn('key', context)
            self.assertEqual(context['key'], 'value')

        def test_plugin_html(self):
            placeholder = Placeholder.objects.create(slot='test')
            model_instance = add_plugin(
                placeholder,
                MyPlugin,
                'en',
            )
            renderer = ContentRenderer(request=RequestFactory())
            html = renderer.render_plugin(model_instance, {})
            self.assertEqual(html, '<strong>Test</strong>')

