77import mock
88import pytest
99
10- from sampleproject .posts .models import Post , Comment
10+ from sampleproject .posts .models import Post , Comment , Tag
1111from 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
206249def 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