Skip to content

Commit afaae0d

Browse files
committed
clone view: add tests for m2m fields
1 parent 84e7b60 commit afaae0d

File tree

3 files changed

+59
-2
lines changed

3 files changed

+59
-2
lines changed

sampleproject/posts/admin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from modelclone import ClonableModelAdmin
44

5-
from .models import Post, Comment
5+
from .models import Post, Comment, Tag
66

77

88
class CommentInline(admin.StackedInline):
@@ -17,3 +17,4 @@ class PostAdmin(ClonableModelAdmin):
1717

1818

1919
admin.site.register(Post, PostAdmin)
20+
admin.site.register(Tag)

sampleproject/posts/models.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
class Post(models.Model):
44
title = models.CharField(max_length=256)
55
content = models.TextField(blank=True)
6+
tags = models.ManyToManyField('Tag', blank=True)
67

78
def __unicode__(self):
89
return u'Post: {0}'.format(self.title)
@@ -15,3 +16,9 @@ class Comment(models.Model):
1516

1617
def __unicode__(self):
1718
return u'Comment on {0} by {1}'.format(self.post, self.author)
19+
20+
class Tag(models.Model):
21+
name = models.CharField(max_length=50)
22+
23+
def __unicode__(self):
24+
return self.name

tests/test_admin.py

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import mock
88
import pytest
99

10-
from sampleproject.posts.models import Post, Comment
10+
from sampleproject.posts.models import Post, Comment, Tag
1111
from modelclone import ClonableModelAdmin
1212

1313

@@ -19,6 +19,8 @@ def setUp(self):
1919
password='admin',
2020
email='admin@sampleproject.com'
2121
)
22+
self.tag1 = Tag.objects.create(name='django')
23+
self.tag2 = Tag.objects.create(name='sports')
2224

2325
self.post = Post.objects.create(
2426
title = 'How to learn windsurf',
@@ -40,10 +42,17 @@ def setUp(self):
4042
post = self.post_with_comments
4143
)
4244

45+
self.post_with_tags = Post.objects.create(
46+
title = 'Django resable apps',
47+
)
48+
self.post_with_tags.tags.add(self.tag1)
49+
4350
self.post_url = '/admin/posts/post/{0}/clone/'.format(
4451
self.post.id)
4552
self.post_with_comments_url = '/admin/posts/post/{0}/clone/'.format(
4653
self.post_with_comments.id)
54+
self.post_with_tags_url = '/admin/posts/post/{0}/clone/'.format(
55+
self.post_with_tags.id)
4756

4857
def test_clone_view_is_wrapped_as_admin_view(self):
4958
model = mock.Mock()
@@ -201,6 +210,40 @@ def test_clone_should_ignore_initial_data_of_inline_form_if_delete_is_checked(se
201210
assert 1 == cloned_post.comment_set.count()
202211

203212

213+
def test_clone_with_m2m_fields_should_prefill_m2m_fields(self):
214+
response = self.app.get(self.post_with_tags_url, user='admin')
215+
216+
tag1_option = select_element(response, 'select[name=tags] option[value="{id}"]'
217+
.format(id=self.tag1.id))
218+
tag2_option = select_element(response, 'select[name=tags] option[value="{id}"]'
219+
.format(id=self.tag2.id))
220+
221+
assert tag1_option.get('selected')
222+
assert not tag2_option.get('selected')
223+
224+
225+
def test_clone_with_m2m_fields_should_keep_modified_m2m_field_values_after_validation_error(self):
226+
response = self.app.get(self.post_with_tags_url, user='admin')
227+
228+
# original post has tag1 selected and tag2 disabled. will disable tag1
229+
# and select tag2.
230+
#
231+
# with a blank title the page will return a validation error, should keep
232+
# my selected options
233+
response.form.set('title', '')
234+
response.form.set('tags', [self.tag2.id])
235+
response = response.form.submit()
236+
237+
assert 'Please correct the error below' in response.content
238+
239+
tag1_option = select_element(response, 'select[name=tags] option[value="{id}"]'
240+
.format(id=self.tag1.id))
241+
tag2_option = select_element(response, 'select[name=tags] option[value="{id}"]'
242+
.format(id=self.tag2.id))
243+
244+
assert not tag1_option.get('selected')
245+
assert tag2_option.get('selected')
246+
204247
# asserts
205248

206249
def assert_input(response, name, value=None):
@@ -270,3 +313,9 @@ def assert_management_form_inputs(response, total, initial, max_num):
270313
assert_input(response, name='comment_set-TOTAL_FORMS', value=total)
271314
assert_input(response, name='comment_set-INITIAL_FORMS', value=initial)
272315
assert_input(response, name='comment_set-MAX_NUM_FORMS', value=max_num)
316+
317+
def select_element(response, selector):
318+
elements = response.lxml.cssselect(selector)
319+
assert len(elements) == 1, "Expected 1 element for selector '{0}', found {1}".format(
320+
selector, len(elements))
321+
return elements[0]

0 commit comments

Comments
 (0)