-
Notifications
You must be signed in to change notification settings - Fork 65
/
Copy pathtest_inline_admin.py
194 lines (150 loc) · 6.84 KB
/
test_inline_admin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
import pytest
from django.urls import reverse
from django_webtest import DjangoTestApp, WebTestMixin
from ..models import Article, Author
@pytest.fixture(scope='function')
def app(request):
"""WebTest's TestApp.
Patch and unpatch settings before and after each test.
WebTestMixin, when used in a unittest.TestCase, automatically calls
_patch_settings() and _unpatchsettings.
"""
wtm = WebTestMixin()
wtm._patch_settings()
request.addfinalizer(wtm._unpatch_settings)
return DjangoTestApp()
@pytest.fixture()
def admin_client(app, admin_user):
app.set_user(admin_user)
return app
@pytest.fixture
def author():
author, __ = Author.objects.get_or_create(
name='Author',
)
return author
@pytest.fixture
def article(author):
return Article.objects.create(
author=author,
body='Body lorem ipson dolor',
title='Lorem ipson dolor',
)
def test_actions_available(admin_client, author):
"""Test weather the action column is rendered."""
url = reverse('admin:blog_author_change', args=(author.pk,))
changeview = admin_client.get(url)
path = ('.//div[@id="article_set-group"]//table'
'//thead//th[starts-with(text(), "Actions")]')
assert len(changeview.lxml.xpath(path)) == 1
url = reverse('admin:blog_author_add')
addview = admin_client.get(url)
assert len(addview.lxml.xpath(path)) == 1
def test_no_actions_on_None(admin_client, author):
"""If `inline_actions=None` no actions should be visible"""
from ..admin import ArticleInline
url = reverse('admin:blog_article_changelist')
# save
old_inlinec_actions = ArticleInline.inline_actions
ArticleInline.inline_actions = None
url = reverse('admin:blog_author_change', args=(author.pk,))
changeview = admin_client.get(url)
path = ('.//div[@id="article_set-group"]//table'
'//thead//th[starts-with(text(), "Actions")]')
assert len(changeview.lxml.xpath(path)) == 0
url = reverse('admin:blog_author_add')
addview = admin_client.get(url)
assert len(addview.lxml.xpath(path)) == 0
# restore
ArticleInline.inline_actions = old_inlinec_actions
def test_actions_methods_called(admin_client, mocker, article):
"""Test is all required methods are called."""
from inline_actions.admin import InlineActionsMixin
mocker.spy(InlineActionsMixin, 'render_inline_actions')
mocker.spy(InlineActionsMixin, 'get_inline_actions')
author = article.author
url = reverse('admin:blog_author_change', args=(author.pk,))
admin_client.get(url)
assert InlineActionsMixin.render_inline_actions.call_count > 0
assert InlineActionsMixin.get_inline_actions.call_count > 0
@pytest.mark.parametrize("action", ['view_action', 'publish', 'delete_action'])
def test_actions_rendered(admin_client, article, action):
"""Test wether all action buttons are rendered."""
author = article.author
url = reverse('admin:blog_author_change', args=(author.pk,))
changeview = admin_client.get(url)
input_name = '_action__inline__{}__blog__article__{}'.format(action, article.pk)
assert input_name in dict(changeview.form.fields)
def test_publish_action(admin_client, mocker, article):
"""Test dynamically added actions using `get_actions()`"""
from ..admin import UnPublishActionsMixin
mocker.spy(UnPublishActionsMixin, 'get_inline_actions')
mocker.spy(UnPublishActionsMixin, 'publish')
mocker.spy(UnPublishActionsMixin, 'unpublish')
author = article.author
assert article.status == Article.DRAFT
author_url = reverse('admin:blog_author_change', args=(author.pk,))
publish_input_name = '_action__inline__publish__blog__article__{}'.format(
article.pk)
unpublish_input_name = '_action__inline__unpublish__blog__article__{}'.format(
article.pk)
# open changeform
changeview = admin_client.get(author_url)
assert UnPublishActionsMixin.get_inline_actions.call_count > 0
assert publish_input_name in dict(changeview.form.fields)
# execute and test publish action
changeview = changeview.form.submit(name=publish_input_name).follow()
# not available in django 1.7
# article.refresh_from_db()
article = Article.objects.get(pk=article.pk)
assert publish_input_name not in dict(changeview.form.fields)
assert unpublish_input_name in dict(changeview.form.fields)
assert UnPublishActionsMixin.publish.call_count == 1
assert article.status == Article.PUBLISHED
# execute and test unpublish action
changeview = changeview.form.submit(name=unpublish_input_name).follow()
# article.refresh_from_db()
article = Article.objects.get(pk=article.pk)
assert publish_input_name in dict(changeview.form.fields)
assert unpublish_input_name not in dict(changeview.form.fields)
assert UnPublishActionsMixin.unpublish.call_count == 1
assert article.status == Article.DRAFT
def test_view_action(admin_client, mocker, article):
"""Test view action."""
from inline_actions.actions import ViewAction
mocker.spy(ViewAction, 'view_action')
author = article.author
author_url = reverse('admin:blog_author_change', args=(author.pk,))
changeview = admin_client.get(author_url)
# execute and test view action
input_name = '_action__inline__view_action__blog__article__{}'.format(article.pk)
response = changeview.form.submit(name=input_name).follow()
assert ViewAction.view_action.call_count == 1
article_url = reverse('admin:blog_article_change', args=(article.pk,))
assert response.request.path == article_url
def test_delete_action_without_permission(admin_client, mocker, article):
"""Delete action should not be visible without permission."""
from ..admin import ArticleInline
mocker.patch.object(ArticleInline, 'has_delete_permission',
return_value=False)
author = article.author
# mock delete_permission
author_url = reverse('admin:blog_author_change', args=(author.pk,))
changeview = admin_client.get(author_url)
input_name = '_action__inline__delete_action__blog__article__{}'.format(article.pk)
assert input_name not in dict(changeview.form.fields)
def test_delete_action(admin_client, mocker, article):
"""Test delete action."""
from inline_actions.actions import DeleteAction
mocker.spy(DeleteAction, 'delete_action')
author = article.author
# mock delete_permission
author_url = reverse('admin:blog_author_change', args=(author.pk,))
changeview = admin_client.get(author_url)
# execute and test delete action
input_name = '_action__inline__delete_action__blog__article__{}'.format(article.pk)
response = changeview.form.submit(name=input_name).follow()
assert DeleteAction.delete_action.call_count == 1
assert response.request.path == author_url
with pytest.raises(Article.DoesNotExist):
Article.objects.get(pk=article.pk)