2013-07-30 01:19:04 +08:00
from __future__ import unicode_literals
2011-10-14 02:51:33 +08:00
2015-02-23 08:53:57 +08:00
import datetime
2014-10-21 05:29:28 +08:00
import warnings
2015-01-28 20:35:27 +08:00
from django . contrib . admin import ModelAdmin , TabularInline
2010-09-27 23:11:03 +08:00
from django . contrib . admin . helpers import InlineAdminForm
2015-01-28 20:35:27 +08:00
from django . contrib . admin . tests import AdminSeleniumWebDriverTestCase
from django . contrib . auth . models import Permission , User
2010-09-27 23:11:03 +08:00
from django . contrib . contenttypes . models import ContentType
2015-02-07 06:25:15 +08:00
from django . core . urlresolvers import reverse
2015-01-28 20:35:27 +08:00
from django . test import RequestFactory , TestCase , override_settings
2014-10-21 05:29:28 +08:00
from django . utils . encoding import force_text
2010-12-04 15:28:12 +08:00
2014-03-06 04:19:40 +08:00
from . admin import InnerInline , site as admin_site
2015-01-28 20:35:27 +08:00
from . models import (
Author , BinaryTree , Book , Chapter , Child , ChildModel1 , ChildModel2 ,
Fashionista , FootNote , Holder , Holder2 , Holder3 , Holder4 , Inner , Inner2 ,
Inner3 , Inner4Stacked , Inner4Tabular , Novel , OutfitItem , Parent ,
ParentModelWithCustomPk , Person , Poll , Profile , ProfileCollection ,
Question , Sighting , SomeChildModel , SomeParentModel , Teacher ,
)
2014-07-25 20:07:04 +08:00
INLINE_CHANGELINK_HTML = ' class= " inlinechangelink " >Change</a> '
2010-09-27 23:11:03 +08:00
2010-03-27 07:38:05 +08:00
2015-02-23 08:53:57 +08:00
class TestDataMixin ( object ) :
@classmethod
def setUpTestData ( cls ) :
# password = "secret"
User . objects . create (
pk = 100 , username = ' super ' , first_name = ' Super ' , last_name = ' User ' , email = ' super@example.com ' ,
password = ' sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158 ' , is_active = True , is_superuser = True ,
is_staff = True , last_login = datetime . datetime ( 2007 , 5 , 30 , 13 , 20 , 10 ) ,
date_joined = datetime . datetime ( 2007 , 5 , 30 , 13 , 20 , 10 )
)
2015-01-22 00:55:57 +08:00
@override_settings ( PASSWORD_HASHERS = [ ' django.contrib.auth.hashers.SHA1PasswordHasher ' ] ,
2014-04-05 14:04:46 +08:00
ROOT_URLCONF = " admin_inlines.urls " )
2015-02-23 08:53:57 +08:00
class TestInline ( TestDataMixin , TestCase ) :
2010-02-24 01:14:50 +08:00
def setUp ( self ) :
holder = Holder ( dummy = 13 )
holder . save ( )
Inner ( dummy = 42 , holder = holder ) . save ( )
result = self . client . login ( username = ' super ' , password = ' secret ' )
2010-12-04 15:28:12 +08:00
self . assertEqual ( result , True )
2014-03-06 04:19:40 +08:00
self . factory = RequestFactory ( )
2010-02-24 01:14:50 +08:00
def test_can_delete ( self ) :
"""
can_delete should be passed to inlineformset factory .
"""
2015-02-07 06:25:15 +08:00
holder = Holder . objects . get ( dummy = 13 )
response = self . client . get (
reverse ( ' admin:admin_inlines_holder_change ' , args = ( holder . id , ) )
)
2012-02-01 04:36:11 +08:00
inner_formset = response . context [ ' inline_admin_formsets ' ] [ 0 ] . formset
2010-02-24 01:14:50 +08:00
expected = InnerInline . can_delete
actual = inner_formset . can_delete
self . assertEqual ( expected , actual , ' can_delete must be equal ' )
2010-03-27 07:38:05 +08:00
def test_readonly_stacked_inline_label ( self ) :
""" Bug #13174. """
holder = Holder . objects . create ( dummy = 42 )
2013-09-08 23:05:16 +08:00
Inner . objects . create ( holder = holder , dummy = 42 , readonly = ' ' )
2015-02-07 06:25:15 +08:00
response = self . client . get (
reverse ( ' admin:admin_inlines_holder_change ' , args = ( holder . id , ) )
)
2010-03-27 07:38:05 +08:00
self . assertContains ( response , ' <label>Inner readonly label:</label> ' )
2010-04-27 20:35:49 +08:00
def test_many_to_many_inlines ( self ) :
" Autogenerated many-to-many inlines are displayed correctly (#13407) "
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_author_add ' ) )
2010-04-27 20:35:49 +08:00
# The heading for the m2m inline block uses the right text
self . assertContains ( response , ' <h2>Author-book relationships</h2> ' )
# The "add another" label is correct
2015-03-07 01:45:53 +08:00
self . assertContains ( response , ' Add another Author \\ u002Dbook relationship ' )
2010-04-27 20:35:49 +08:00
# The '+' is dropped from the autogenerated form prefix (Author_books+)
self . assertContains ( response , ' id= " id_Author_books-TOTAL_FORMS " ' )
2010-04-27 23:05:38 +08:00
def test_inline_primary ( self ) :
person = Person . objects . create ( firstname = ' Imelda ' )
item = OutfitItem . objects . create ( name = ' Shoes ' )
2014-03-02 22:25:53 +08:00
# Imelda likes shoes, but can't carry her own bags.
2010-04-27 23:05:38 +08:00
data = {
' shoppingweakness_set-TOTAL_FORMS ' : 1 ,
' shoppingweakness_set-INITIAL_FORMS ' : 0 ,
' shoppingweakness_set-MAX_NUM_FORMS ' : 0 ,
2012-06-08 00:08:47 +08:00
' _save ' : ' Save ' ,
2010-04-27 23:05:38 +08:00
' person ' : person . id ,
' max_weight ' : 0 ,
' shoppingweakness_set-0-item ' : item . id ,
}
2015-02-07 06:25:15 +08:00
response = self . client . post ( reverse ( ' admin:admin_inlines_fashionista_add ' ) , data )
2010-04-27 23:05:38 +08:00
self . assertEqual ( response . status_code , 302 )
self . assertEqual ( len ( Fashionista . objects . filter ( person__firstname = ' Imelda ' ) ) , 1 )
2010-03-27 07:38:05 +08:00
2011-02-22 11:07:57 +08:00
def test_tabular_non_field_errors ( self ) :
"""
Ensure that non_field_errors are displayed correctly , including the
right value for colspan . Refs #13510.
"""
data = {
' title_set-TOTAL_FORMS ' : 1 ,
' title_set-INITIAL_FORMS ' : 0 ,
' title_set-MAX_NUM_FORMS ' : 0 ,
2012-06-08 00:08:47 +08:00
' _save ' : ' Save ' ,
2011-02-22 11:07:57 +08:00
' title_set-0-title1 ' : ' a title ' ,
' title_set-0-title2 ' : ' a different title ' ,
}
2015-02-07 06:25:15 +08:00
response = self . client . post ( reverse ( ' admin:admin_inlines_titlecollection_add ' ) , data )
2014-03-02 22:25:53 +08:00
# Here colspan is "4": two fields (title1 and title2), one hidden field and the delete checkbox.
2014-04-15 11:58:51 +08:00
self . assertContains ( response , ' <tr><td colspan= " 4 " ><ul class= " errorlist nonfield " ><li>The two titles must be the same</li></ul></td></tr> ' )
2011-02-22 11:07:57 +08:00
2011-02-26 09:44:41 +08:00
def test_no_parent_callable_lookup ( self ) :
""" Admin inline `readonly_field` shouldn ' t invoke parent ModelAdmin callable """
# Identically named callable isn't present in the parent ModelAdmin,
# rendering of the add view shouldn't explode
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_novel_add ' ) )
2011-02-26 09:44:41 +08:00
self . assertEqual ( response . status_code , 200 )
# View should have the child inlines section
self . assertContains ( response , ' <div class= " inline-group " id= " chapter_set-group " > ' )
def test_callable_lookup ( self ) :
""" Admin inline should invoke local callable when its name is listed in readonly_fields """
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_poll_add ' ) )
2011-02-26 09:44:41 +08:00
self . assertEqual ( response . status_code , 200 )
# Add parent object view should have the child inlines section
self . assertContains ( response , ' <div class= " inline-group " id= " question_set-group " > ' )
2014-03-02 22:25:53 +08:00
# The right callable should be used for the inline readonly_fields
2011-02-26 09:44:41 +08:00
# column cells
self . assertContains ( response , ' <p>Callable in QuestionInline</p> ' )
2011-08-17 22:12:25 +08:00
def test_help_text ( self ) :
"""
Ensure that the inlines ' model field help texts are displayed when
using both the stacked and tabular layouts .
Ref #8190.
"""
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_holder4_add ' ) )
2011-08-17 22:12:25 +08:00
self . assertContains ( response , ' <p class= " help " >Awesome stacked help text is awesome.</p> ' , 4 )
2011-08-26 12:36:31 +08:00
self . assertContains ( response , ' <img src= " /static/admin/img/icon-unknown.gif " class= " help help-tooltip " width= " 10 " height= " 10 " alt= " (Awesome tabular help text is awesome.) " title= " Awesome tabular help text is awesome. " /> ' , 1 )
2013-02-24 01:24:32 +08:00
# ReadOnly fields
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_capofamiglia_add ' ) )
2013-02-24 01:24:32 +08:00
self . assertContains ( response , ' <img src= " /static/admin/img/icon-unknown.gif " class= " help help-tooltip " width= " 10 " height= " 10 " alt= " (Help text for ReadOnlyInline) " title= " Help text for ReadOnlyInline " /> ' , 1 )
2013-10-08 00:30:02 +08:00
def test_inline_hidden_field_no_column ( self ) :
""" #18263 -- Make sure hidden fields don ' t get a column in tabular inlines """
parent = SomeParentModel . objects . create ( name = ' a ' )
SomeChildModel . objects . create ( name = ' b ' , position = ' 0 ' , parent = parent )
SomeChildModel . objects . create ( name = ' c ' , position = ' 1 ' , parent = parent )
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_someparentmodel_change ' , args = ( parent . pk , ) ) )
2013-10-08 00:30:02 +08:00
self . assertNotContains ( response , ' <td class= " field-position " > ' )
self . assertContains ( response , (
' <input id= " id_somechildmodel_set-1-position " '
' name= " somechildmodel_set-1-position " type= " hidden " value= " 1 " /> ' ) )
2011-08-17 22:12:25 +08:00
2011-09-21 22:00:58 +08:00
def test_non_related_name_inline ( self ) :
"""
Ensure that multiple inlines with related_name = ' + ' have correct form
prefixes . Bug #16838.
"""
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_capofamiglia_add ' ) )
2011-09-21 22:00:58 +08:00
self . assertContains ( response ,
2012-09-28 15:25:08 +08:00
' <input type= " hidden " name= " -1-0-id " id= " id_-1-0-id " /> ' , html = True )
2011-09-21 22:00:58 +08:00
self . assertContains ( response ,
2012-09-28 15:25:08 +08:00
' <input type= " hidden " name= " -1-0-capo_famiglia " id= " id_-1-0-capo_famiglia " /> ' , html = True )
2011-09-21 22:00:58 +08:00
self . assertContains ( response ,
' <input id= " id_-1-0-name " type= " text " class= " vTextField " '
2012-02-01 04:36:11 +08:00
' name= " -1-0-name " maxlength= " 100 " /> ' , html = True )
2011-09-21 22:00:58 +08:00
self . assertContains ( response ,
2012-09-28 15:25:08 +08:00
' <input type= " hidden " name= " -2-0-id " id= " id_-2-0-id " /> ' , html = True )
2011-09-21 22:00:58 +08:00
self . assertContains ( response ,
2012-09-28 15:25:08 +08:00
' <input type= " hidden " name= " -2-0-capo_famiglia " id= " id_-2-0-capo_famiglia " /> ' , html = True )
2011-09-21 22:00:58 +08:00
self . assertContains ( response ,
' <input id= " id_-2-0-name " type= " text " class= " vTextField " '
2012-02-01 04:36:11 +08:00
' name= " -2-0-name " maxlength= " 100 " /> ' , html = True )
2011-09-21 22:00:58 +08:00
2012-09-27 21:55:27 +08:00
@override_settings ( USE_L10N = True , USE_THOUSAND_SEPARATOR = True )
def test_localize_pk_shortcut ( self ) :
"""
Ensure that the " View on Site " link is correct for locales that use
thousand separators
"""
holder = Holder . objects . create ( pk = 123456789 , dummy = 42 )
inner = Inner . objects . create ( pk = 987654321 , holder = holder , dummy = 42 , readonly = ' ' )
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_holder_change ' , args = ( holder . id , ) ) )
2013-10-11 19:25:14 +08:00
inner_shortcut = ' r/ %s / %s / ' % ( ContentType . objects . get_for_model ( inner ) . pk , inner . pk )
2012-09-27 21:55:27 +08:00
self . assertContains ( response , inner_shortcut )
2012-06-08 01:52:13 +08:00
def test_custom_pk_shortcut ( self ) :
"""
Ensure that the " View on Site " link is correct for models with a
custom primary key field . Bug #18433.
"""
parent = ParentModelWithCustomPk . objects . create ( my_own_pk = " foo " , name = " Foo " )
child1 = ChildModel1 . objects . create ( my_own_pk = " bar " , name = " Bar " , parent = parent )
child2 = ChildModel2 . objects . create ( my_own_pk = " baz " , name = " Baz " , parent = parent )
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_parentmodelwithcustompk_change ' , args = ( ' foo ' , ) ) )
2013-10-11 19:25:14 +08:00
child1_shortcut = ' r/ %s / %s / ' % ( ContentType . objects . get_for_model ( child1 ) . pk , child1 . pk )
child2_shortcut = ' r/ %s / %s / ' % ( ContentType . objects . get_for_model ( child2 ) . pk , child2 . pk )
2012-06-08 01:52:13 +08:00
self . assertContains ( response , child1_shortcut )
self . assertContains ( response , child2_shortcut )
2012-12-29 06:16:13 +08:00
def test_create_inlines_on_inherited_model ( self ) :
"""
Ensure that an object can be created with inlines when it inherits
another class . Bug #19524.
"""
data = {
' name ' : ' Martian ' ,
' sighting_set-TOTAL_FORMS ' : 1 ,
' sighting_set-INITIAL_FORMS ' : 0 ,
' sighting_set-MAX_NUM_FORMS ' : 0 ,
' sighting_set-0-place ' : ' Zone 51 ' ,
' _save ' : ' Save ' ,
}
2015-02-07 06:25:15 +08:00
response = self . client . post ( reverse ( ' admin:admin_inlines_extraterrestrial_add ' ) , data )
2012-12-29 06:16:13 +08:00
self . assertEqual ( response . status_code , 302 )
self . assertEqual ( Sighting . objects . filter ( et__name = ' Martian ' ) . count ( ) , 1 )
2013-05-31 01:48:10 +08:00
def test_custom_get_extra_form ( self ) :
bt_head = BinaryTree . objects . create ( name = " Tree Head " )
2013-09-08 23:05:16 +08:00
BinaryTree . objects . create ( name = " First Child " , parent = bt_head )
2013-05-31 01:48:10 +08:00
2013-06-02 06:16:57 +08:00
# The maximum number of forms should respect 'get_max_num' on the
# ModelAdmin
max_forms_input = ' <input id= " id_binarytree_set-MAX_NUM_FORMS " name= " binarytree_set-MAX_NUM_FORMS " type= " hidden " value= " %d " /> '
2013-05-31 01:48:10 +08:00
# The total number of forms will remain the same in either case
total_forms_hidden = ' <input id= " id_binarytree_set-TOTAL_FORMS " name= " binarytree_set-TOTAL_FORMS " type= " hidden " value= " 2 " /> '
2013-06-02 06:16:57 +08:00
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_binarytree_add ' ) )
2013-06-02 06:16:57 +08:00
self . assertContains ( response , max_forms_input % 3 )
2013-05-31 01:48:10 +08:00
self . assertContains ( response , total_forms_hidden )
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_binarytree_change ' , args = ( bt_head . id , ) ) )
2013-06-02 06:16:57 +08:00
self . assertContains ( response , max_forms_input % 2 )
2013-05-31 01:48:10 +08:00
self . assertContains ( response , total_forms_hidden )
2014-03-06 04:19:40 +08:00
def test_min_num ( self ) :
"""
Ensure that min_num and extra determine number of forms .
"""
class MinNumInline ( TabularInline ) :
model = BinaryTree
min_num = 2
extra = 3
modeladmin = ModelAdmin ( BinaryTree , admin_site )
modeladmin . inlines = [ MinNumInline ]
min_forms = ' <input id= " id_binarytree_set-MIN_NUM_FORMS " name= " binarytree_set-MIN_NUM_FORMS " type= " hidden " value= " 2 " /> '
total_forms = ' <input id= " id_binarytree_set-TOTAL_FORMS " name= " binarytree_set-TOTAL_FORMS " type= " hidden " value= " 5 " /> '
2015-02-07 06:25:15 +08:00
request = self . factory . get ( reverse ( ' admin:admin_inlines_binarytree_add ' ) )
2014-03-06 04:19:40 +08:00
request . user = User ( username = ' super ' , is_superuser = True )
response = modeladmin . changeform_view ( request )
self . assertContains ( response , min_forms )
self . assertContains ( response , total_forms )
def test_custom_min_num ( self ) :
"""
Ensure that get_min_num is called and used correctly .
"""
bt_head = BinaryTree . objects . create ( name = " Tree Head " )
BinaryTree . objects . create ( name = " First Child " , parent = bt_head )
class MinNumInline ( TabularInline ) :
model = BinaryTree
extra = 3
def get_min_num ( self , request , obj = None , * * kwargs ) :
if obj :
return 5
return 2
modeladmin = ModelAdmin ( BinaryTree , admin_site )
modeladmin . inlines = [ MinNumInline ]
min_forms = ' <input id= " id_binarytree_set-MIN_NUM_FORMS " name= " binarytree_set-MIN_NUM_FORMS " type= " hidden " value= " %d " /> '
total_forms = ' <input id= " id_binarytree_set-TOTAL_FORMS " name= " binarytree_set-TOTAL_FORMS " type= " hidden " value= " %d " /> '
2015-02-07 06:25:15 +08:00
request = self . factory . get ( reverse ( ' admin:admin_inlines_binarytree_add ' ) )
2014-03-06 04:19:40 +08:00
request . user = User ( username = ' super ' , is_superuser = True )
response = modeladmin . changeform_view ( request )
self . assertContains ( response , min_forms % 2 )
self . assertContains ( response , total_forms % 5 )
2015-02-07 06:25:15 +08:00
request = self . factory . get ( reverse ( ' admin:admin_inlines_binarytree_change ' , args = ( bt_head . id , ) ) )
2014-03-06 04:19:40 +08:00
request . user = User ( username = ' super ' , is_superuser = True )
response = modeladmin . changeform_view ( request , object_id = str ( bt_head . id ) )
self . assertContains ( response , min_forms % 5 )
2014-05-16 11:12:32 +08:00
self . assertContains ( response , total_forms % 8 )
2014-03-06 04:19:40 +08:00
2013-07-20 03:55:16 +08:00
def test_inline_nonauto_noneditable_pk ( self ) :
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_author_add ' ) )
2013-07-20 03:55:16 +08:00
self . assertContains ( response ,
' <input id= " id_nonautopkbook_set-0-rand_pk " name= " nonautopkbook_set-0-rand_pk " type= " hidden " /> ' ,
html = True )
self . assertContains ( response ,
' <input id= " id_nonautopkbook_set-2-0-rand_pk " name= " nonautopkbook_set-2-0-rand_pk " type= " hidden " /> ' ,
html = True )
def test_inline_editable_pk ( self ) :
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_author_add ' ) )
2013-07-20 03:55:16 +08:00
self . assertContains ( response ,
' <input class= " vIntegerField " id= " id_editablepkbook_set-0-manual_pk " name= " editablepkbook_set-0-manual_pk " type= " text " /> ' ,
html = True , count = 1 )
self . assertContains ( response ,
' <input class= " vIntegerField " id= " id_editablepkbook_set-2-0-manual_pk " name= " editablepkbook_set-2-0-manual_pk " type= " text " /> ' ,
html = True , count = 1 )
2014-02-09 20:32:35 +08:00
def test_stacked_inline_edit_form_contains_has_original_class ( self ) :
holder = Holder . objects . create ( dummy = 1 )
holder . inner_set . create ( dummy = 1 )
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_holder_change ' , args = ( holder . pk , ) ) )
2014-02-09 20:32:35 +08:00
self . assertContains (
response ,
' <div class= " inline-related has_original " id= " inner_set-0 " > ' ,
count = 1
)
self . assertContains (
response ,
' <div class= " inline-related " id= " inner_set-1 " > ' ,
count = 1
)
2014-07-25 20:07:04 +08:00
def test_inlines_show_change_link_registered ( self ) :
" Inlines `show_change_link` for registered models when enabled. "
holder = Holder4 . objects . create ( dummy = 1 )
item1 = Inner4Stacked . objects . create ( dummy = 1 , holder = holder )
item2 = Inner4Tabular . objects . create ( dummy = 1 , holder = holder )
items = (
( ' inner4stacked ' , item1 . pk ) ,
( ' inner4tabular ' , item2 . pk ) ,
)
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_holder4_change ' , args = ( holder . pk , ) ) )
2014-07-25 20:07:04 +08:00
self . assertTrue ( response . context [ ' inline_admin_formset ' ] . opts . has_registered_model )
for model , pk in items :
2015-02-07 06:25:15 +08:00
url = reverse ( ' admin:admin_inlines_ %s _change ' % model , args = ( pk , ) )
2014-07-25 20:07:04 +08:00
self . assertContains ( response , ' <a href= " %s " %s ' % ( url , INLINE_CHANGELINK_HTML ) )
def test_inlines_show_change_link_unregistered ( self ) :
" Inlines `show_change_link` disabled for unregistered models. "
parent = ParentModelWithCustomPk . objects . create ( my_own_pk = " foo " , name = " Foo " )
ChildModel1 . objects . create ( my_own_pk = " bar " , name = " Bar " , parent = parent )
ChildModel2 . objects . create ( my_own_pk = " baz " , name = " Baz " , parent = parent )
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_parentmodelwithcustompk_change ' , args = ( ' foo ' , ) ) )
2014-07-25 20:07:04 +08:00
self . assertFalse ( response . context [ ' inline_admin_formset ' ] . opts . has_registered_model )
self . assertNotContains ( response , INLINE_CHANGELINK_HTML )
def test_tabular_inline_show_change_link_false_registered ( self ) :
" Inlines `show_change_link` disabled by default. "
poll = Poll . objects . create ( name = " New poll " )
Question . objects . create ( poll = poll )
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_poll_change ' , args = ( poll . pk , ) ) )
2014-07-25 20:07:04 +08:00
self . assertTrue ( response . context [ ' inline_admin_formset ' ] . opts . has_registered_model )
self . assertNotContains ( response , INLINE_CHANGELINK_HTML )
2012-06-08 01:52:13 +08:00
2015-01-22 00:55:57 +08:00
@override_settings ( PASSWORD_HASHERS = [ ' django.contrib.auth.hashers.SHA1PasswordHasher ' ] ,
2014-04-05 14:04:46 +08:00
ROOT_URLCONF = " admin_inlines.urls " )
2015-02-23 08:53:57 +08:00
class TestInlineMedia ( TestDataMixin , TestCase ) :
2010-03-21 09:54:00 +08:00
def setUp ( self ) :
result = self . client . login ( username = ' super ' , password = ' secret ' )
2010-12-04 15:28:12 +08:00
self . assertEqual ( result , True )
2010-03-21 09:54:00 +08:00
def test_inline_media_only_base ( self ) :
holder = Holder ( dummy = 13 )
holder . save ( )
Inner ( dummy = 42 , holder = holder ) . save ( )
2015-02-07 06:25:15 +08:00
change_url = reverse ( ' admin:admin_inlines_holder_change ' , args = ( holder . id , ) )
2010-03-21 09:54:00 +08:00
response = self . client . get ( change_url )
self . assertContains ( response , ' my_awesome_admin_scripts.js ' )
def test_inline_media_only_inline ( self ) :
holder = Holder3 ( dummy = 13 )
holder . save ( )
Inner3 ( dummy = 42 , holder = holder ) . save ( )
2015-02-07 06:25:15 +08:00
change_url = reverse ( ' admin:admin_inlines_holder3_change ' , args = ( holder . id , ) )
2010-03-21 09:54:00 +08:00
response = self . client . get ( change_url )
self . assertContains ( response , ' my_awesome_inline_scripts.js ' )
def test_all_inline_media ( self ) :
holder = Holder2 ( dummy = 13 )
holder . save ( )
Inner2 ( dummy = 42 , holder = holder ) . save ( )
2015-02-07 06:25:15 +08:00
change_url = reverse ( ' admin:admin_inlines_holder2_change ' , args = ( holder . id , ) )
2010-03-21 09:54:00 +08:00
response = self . client . get ( change_url )
self . assertContains ( response , ' my_awesome_admin_scripts.js ' )
2010-03-27 07:38:05 +08:00
self . assertContains ( response , ' my_awesome_inline_scripts.js ' )
2010-09-27 23:11:03 +08:00
2013-11-03 12:36:09 +08:00
2014-04-05 14:04:46 +08:00
@override_settings ( ROOT_URLCONF = " admin_inlines.urls " )
2010-09-27 23:11:03 +08:00
class TestInlineAdminForm ( TestCase ) :
def test_immutable_content_type ( self ) :
""" Regression for #9362
The problem depends only on InlineAdminForm and its " original "
argument , so we can safely set the other arguments to None / { } . We just
need to check that the content_type argument of Child isn ' t altered by
the internals of the inline form . """
sally = Teacher . objects . create ( name = ' Sally ' )
john = Parent . objects . create ( name = ' John ' )
joe = Child . objects . create ( name = ' Joe ' , teacher = sally , parent = john )
iaf = InlineAdminForm ( None , None , { } , { } , joe )
parent_ct = ContentType . objects . get_for_model ( Parent )
self . assertEqual ( iaf . original . content_type , parent_ct )
2011-10-07 08:41:25 +08:00
2014-10-21 05:29:28 +08:00
def test_original_content_type_id_deprecated ( self ) :
"""
#23444 -- Verify a warning is raised when accessing
` original_content_type_id ` attribute of ` InlineAdminForm ` object .
"""
iaf = InlineAdminForm ( None , None , { } , { } , None )
poll = Poll . objects . create ( name = " poll " )
iaf2 = InlineAdminForm ( None , None , { } , { } , poll )
poll_ct = ContentType . objects . get_for_model ( Poll )
with warnings . catch_warnings ( record = True ) as recorded :
2014-11-27 05:21:29 +08:00
warnings . filterwarnings ( ' always ' )
2014-10-21 05:29:28 +08:00
with self . assertRaises ( AttributeError ) :
iaf . original_content_type_id
msg = force_text ( recorded . pop ( ) . message )
self . assertEqual (
msg ,
' InlineAdminForm.original_content_type_id is deprecated and will be '
' removed in Django 2.0. If you were using this attribute to construct '
' the " view on site " URL, use the `absolute_url` attribute instead. '
)
self . assertEqual ( iaf2 . original_content_type_id , poll_ct . id )
2013-02-24 02:44:54 +08:00
2015-01-22 00:55:57 +08:00
@override_settings ( PASSWORD_HASHERS = [ ' django.contrib.auth.hashers.SHA1PasswordHasher ' ] ,
2014-04-05 14:04:46 +08:00
ROOT_URLCONF = " admin_inlines.urls " )
2015-02-23 08:53:57 +08:00
class TestInlineProtectedOnDelete ( TestDataMixin , TestCase ) :
2013-02-24 02:44:54 +08:00
def setUp ( self ) :
result = self . client . login ( username = ' super ' , password = ' secret ' )
self . assertEqual ( result , True )
def test_deleting_inline_with_protected_delete_does_not_validate ( self ) :
lotr = Novel . objects . create ( name = ' Lord of the rings ' )
chapter = Chapter . objects . create ( novel = lotr , name = ' Many Meetings ' )
foot_note = FootNote . objects . create ( chapter = chapter , note = ' yadda yadda ' )
2015-02-07 06:25:15 +08:00
change_url = reverse ( ' admin:admin_inlines_novel_change ' , args = ( lotr . id , ) )
2013-02-24 02:44:54 +08:00
response = self . client . get ( change_url )
data = {
' name ' : lotr . name ,
' chapter_set-TOTAL_FORMS ' : 1 ,
' chapter_set-INITIAL_FORMS ' : 1 ,
' chapter_set-MAX_NUM_FORMS ' : 1000 ,
' _save ' : ' Save ' ,
' chapter_set-0-id ' : chapter . id ,
' chapter_set-0-name ' : chapter . name ,
' chapter_set-0-novel ' : lotr . id ,
' chapter_set-0-DELETE ' : ' on '
}
response = self . client . post ( change_url , data )
self . assertEqual ( response . status_code , 200 )
self . assertContains ( response , " Deleting chapter %s would require deleting "
" the following protected related objects: foot note %s "
% ( chapter , foot_note ) )
2014-04-05 14:04:46 +08:00
@override_settings ( ROOT_URLCONF = " admin_inlines.urls " )
2011-10-07 08:41:25 +08:00
class TestInlinePermissions ( TestCase ) :
"""
Make sure the admin respects permissions for objects that are edited
inline . Refs #8060.
"""
def setUp ( self ) :
self . user = User ( username = ' admin ' )
self . user . is_staff = True
self . user . is_active = True
self . user . set_password ( ' secret ' )
self . user . save ( )
self . author_ct = ContentType . objects . get_for_model ( Author )
self . holder_ct = ContentType . objects . get_for_model ( Holder2 )
self . book_ct = ContentType . objects . get_for_model ( Book )
self . inner_ct = ContentType . objects . get_for_model ( Inner2 )
# User always has permissions to add and change Authors, and Holders,
# the main (parent) models of the inlines. Permissions on the inlines
# vary per test.
permission = Permission . objects . get ( codename = ' add_author ' , content_type = self . author_ct )
self . user . user_permissions . add ( permission )
permission = Permission . objects . get ( codename = ' change_author ' , content_type = self . author_ct )
self . user . user_permissions . add ( permission )
permission = Permission . objects . get ( codename = ' add_holder2 ' , content_type = self . holder_ct )
self . user . user_permissions . add ( permission )
permission = Permission . objects . get ( codename = ' change_holder2 ' , content_type = self . holder_ct )
self . user . user_permissions . add ( permission )
2012-06-08 00:08:47 +08:00
author = Author . objects . create ( pk = 1 , name = ' The Author ' )
book = author . books . create ( name = ' The inline Book ' )
2015-02-07 06:25:15 +08:00
self . author_change_url = reverse ( ' admin:admin_inlines_author_change ' , args = ( author . id , ) )
2014-04-27 01:18:45 +08:00
# Get the ID of the automatically created intermediate model for the Author-Book m2m
2011-10-17 10:11:12 +08:00
author_book_auto_m2m_intermediate = Author . books . through . objects . get ( author = author , book = book )
self . author_book_auto_m2m_intermediate_id = author_book_auto_m2m_intermediate . pk
2011-10-07 08:41:25 +08:00
holder = Holder2 . objects . create ( dummy = 13 )
2011-10-12 05:55:45 +08:00
inner2 = Inner2 . objects . create ( dummy = 42 , holder = holder )
2015-02-07 06:25:15 +08:00
self . holder_change_url = reverse ( ' admin:admin_inlines_holder2_change ' , args = ( holder . id , ) )
2011-10-12 05:55:45 +08:00
self . inner2_id = inner2 . id
2011-10-07 08:41:25 +08:00
self . assertEqual (
self . client . login ( username = ' admin ' , password = ' secret ' ) ,
True )
def test_inline_add_m2m_noperm ( self ) :
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_author_add ' ) )
2011-10-07 08:41:25 +08:00
# No change permission on books, so no inline
self . assertNotContains ( response , ' <h2>Author-book relationships</h2> ' )
2015-03-07 01:45:53 +08:00
self . assertNotContains ( response , ' Add another Author \\ u002DBook Relationship ' )
2011-10-07 08:41:25 +08:00
self . assertNotContains ( response , ' id= " id_Author_books-TOTAL_FORMS " ' )
def test_inline_add_fk_noperm ( self ) :
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_holder2_add ' ) )
2011-10-07 08:41:25 +08:00
# No permissions on Inner2s, so no inline
self . assertNotContains ( response , ' <h2>Inner2s</h2> ' )
self . assertNotContains ( response , ' Add another Inner2 ' )
self . assertNotContains ( response , ' id= " id_inner2_set-TOTAL_FORMS " ' )
def test_inline_change_m2m_noperm ( self ) :
response = self . client . get ( self . author_change_url )
# No change permission on books, so no inline
self . assertNotContains ( response , ' <h2>Author-book relationships</h2> ' )
2015-03-07 01:45:53 +08:00
self . assertNotContains ( response , ' Add another Author \\ u002DBook Relationship ' )
2011-10-07 08:41:25 +08:00
self . assertNotContains ( response , ' id= " id_Author_books-TOTAL_FORMS " ' )
def test_inline_change_fk_noperm ( self ) :
response = self . client . get ( self . holder_change_url )
# No permissions on Inner2s, so no inline
self . assertNotContains ( response , ' <h2>Inner2s</h2> ' )
self . assertNotContains ( response , ' Add another Inner2 ' )
self . assertNotContains ( response , ' id= " id_inner2_set-TOTAL_FORMS " ' )
def test_inline_add_m2m_add_perm ( self ) :
permission = Permission . objects . get ( codename = ' add_book ' , content_type = self . book_ct )
self . user . user_permissions . add ( permission )
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_author_add ' ) )
2011-10-07 08:41:25 +08:00
# No change permission on Books, so no inline
self . assertNotContains ( response , ' <h2>Author-book relationships</h2> ' )
2015-03-07 01:45:53 +08:00
self . assertNotContains ( response , ' Add another Author \\ u002DBook Relationship ' )
2011-10-07 08:41:25 +08:00
self . assertNotContains ( response , ' id= " id_Author_books-TOTAL_FORMS " ' )
def test_inline_add_fk_add_perm ( self ) :
permission = Permission . objects . get ( codename = ' add_inner2 ' , content_type = self . inner_ct )
self . user . user_permissions . add ( permission )
2015-02-07 06:25:15 +08:00
response = self . client . get ( reverse ( ' admin:admin_inlines_holder2_add ' ) )
2011-10-07 08:41:25 +08:00
# Add permission on inner2s, so we get the inline
self . assertContains ( response , ' <h2>Inner2s</h2> ' )
self . assertContains ( response , ' Add another Inner2 ' )
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-TOTAL_FORMS " '
' value= " 3 " name= " inner2_set-TOTAL_FORMS " /> ' , html = True )
2011-10-07 08:41:25 +08:00
def test_inline_change_m2m_add_perm ( self ) :
permission = Permission . objects . get ( codename = ' add_book ' , content_type = self . book_ct )
self . user . user_permissions . add ( permission )
response = self . client . get ( self . author_change_url )
# No change permission on books, so no inline
self . assertNotContains ( response , ' <h2>Author-book relationships</h2> ' )
2015-03-07 01:45:53 +08:00
self . assertNotContains ( response , ' Add another Author \\ u002DBook Relationship ' )
2011-10-07 08:41:25 +08:00
self . assertNotContains ( response , ' id= " id_Author_books-TOTAL_FORMS " ' )
self . assertNotContains ( response , ' id= " id_Author_books-0-DELETE " ' )
def test_inline_change_m2m_change_perm ( self ) :
permission = Permission . objects . get ( codename = ' change_book ' , content_type = self . book_ct )
self . user . user_permissions . add ( permission )
response = self . client . get ( self . author_change_url )
# We have change perm on books, so we can add/change/delete inlines
self . assertContains ( response , ' <h2>Author-book relationships</h2> ' )
2015-03-07 01:45:53 +08:00
self . assertContains ( response , ' Add another Author \\ u002Dbook relationship ' )
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_Author_books-TOTAL_FORMS " '
' value= " 4 " name= " Author_books-TOTAL_FORMS " /> ' , html = True )
self . assertContains ( response , ' <input type= " hidden " id= " id_Author_books-0-id " '
' value= " %i " name= " Author_books-0-id " /> ' % self . author_book_auto_m2m_intermediate_id , html = True )
2011-10-07 08:41:25 +08:00
self . assertContains ( response , ' id= " id_Author_books-0-DELETE " ' )
def test_inline_change_fk_add_perm ( self ) :
permission = Permission . objects . get ( codename = ' add_inner2 ' , content_type = self . inner_ct )
self . user . user_permissions . add ( permission )
response = self . client . get ( self . holder_change_url )
# Add permission on inner2s, so we can add but not modify existing
self . assertContains ( response , ' <h2>Inner2s</h2> ' )
self . assertContains ( response , ' Add another Inner2 ' )
# 3 extra forms only, not the existing instance form
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-TOTAL_FORMS " '
2013-11-03 12:36:09 +08:00
' value= " 3 " name= " inner2_set-TOTAL_FORMS " /> ' , html = True )
2012-09-28 15:25:08 +08:00
self . assertNotContains ( response , ' <input type= " hidden " id= " id_inner2_set-0-id " '
2013-11-03 12:36:09 +08:00
' value= " %i " name= " inner2_set-0-id " /> ' % self . inner2_id , html = True )
2011-10-07 08:41:25 +08:00
def test_inline_change_fk_change_perm ( self ) :
permission = Permission . objects . get ( codename = ' change_inner2 ' , content_type = self . inner_ct )
self . user . user_permissions . add ( permission )
response = self . client . get ( self . holder_change_url )
# Change permission on inner2s, so we can change existing but not add new
self . assertContains ( response , ' <h2>Inner2s</h2> ' )
# Just the one form for existing instances
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-TOTAL_FORMS " '
2013-11-03 12:36:09 +08:00
' value= " 1 " name= " inner2_set-TOTAL_FORMS " /> ' , html = True )
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-0-id " '
2013-11-03 12:36:09 +08:00
' value= " %i " name= " inner2_set-0-id " /> ' % self . inner2_id , html = True )
2011-10-07 08:41:25 +08:00
# max-num 0 means we can't add new ones
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-MAX_NUM_FORMS " '
2013-11-03 12:36:09 +08:00
' value= " 0 " name= " inner2_set-MAX_NUM_FORMS " /> ' , html = True )
2011-10-07 08:41:25 +08:00
def test_inline_change_fk_add_change_perm ( self ) :
permission = Permission . objects . get ( codename = ' add_inner2 ' , content_type = self . inner_ct )
self . user . user_permissions . add ( permission )
permission = Permission . objects . get ( codename = ' change_inner2 ' , content_type = self . inner_ct )
self . user . user_permissions . add ( permission )
response = self . client . get ( self . holder_change_url )
# Add/change perm, so we can add new and change existing
self . assertContains ( response , ' <h2>Inner2s</h2> ' )
# One form for existing instance and three extra for new
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-TOTAL_FORMS " '
2013-11-03 12:36:09 +08:00
' value= " 4 " name= " inner2_set-TOTAL_FORMS " /> ' , html = True )
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-0-id " '
2013-11-03 12:36:09 +08:00
' value= " %i " name= " inner2_set-0-id " /> ' % self . inner2_id , html = True )
2011-10-07 08:41:25 +08:00
def test_inline_change_fk_change_del_perm ( self ) :
permission = Permission . objects . get ( codename = ' change_inner2 ' , content_type = self . inner_ct )
self . user . user_permissions . add ( permission )
permission = Permission . objects . get ( codename = ' delete_inner2 ' , content_type = self . inner_ct )
self . user . user_permissions . add ( permission )
response = self . client . get ( self . holder_change_url )
# Change/delete perm on inner2s, so we can change/delete existing
self . assertContains ( response , ' <h2>Inner2s</h2> ' )
# One form for existing instance only, no new
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-TOTAL_FORMS " '
2013-11-03 12:36:09 +08:00
' value= " 1 " name= " inner2_set-TOTAL_FORMS " /> ' , html = True )
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-0-id " '
2013-11-03 12:36:09 +08:00
' value= " %i " name= " inner2_set-0-id " /> ' % self . inner2_id , html = True )
2011-10-07 08:41:25 +08:00
self . assertContains ( response , ' id= " id_inner2_set-0-DELETE " ' )
def test_inline_change_fk_all_perms ( self ) :
permission = Permission . objects . get ( codename = ' add_inner2 ' , content_type = self . inner_ct )
self . user . user_permissions . add ( permission )
permission = Permission . objects . get ( codename = ' change_inner2 ' , content_type = self . inner_ct )
self . user . user_permissions . add ( permission )
permission = Permission . objects . get ( codename = ' delete_inner2 ' , content_type = self . inner_ct )
self . user . user_permissions . add ( permission )
response = self . client . get ( self . holder_change_url )
# All perms on inner2s, so we can add/change/delete
self . assertContains ( response , ' <h2>Inner2s</h2> ' )
# One form for existing instance only, three for new
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-TOTAL_FORMS " '
2013-11-03 12:36:09 +08:00
' value= " 4 " name= " inner2_set-TOTAL_FORMS " /> ' , html = True )
2012-09-28 15:25:08 +08:00
self . assertContains ( response , ' <input type= " hidden " id= " id_inner2_set-0-id " '
2013-11-03 12:36:09 +08:00
' value= " %i " name= " inner2_set-0-id " /> ' % self . inner2_id , html = True )
2011-10-07 08:41:25 +08:00
self . assertContains ( response , ' id= " id_inner2_set-0-DELETE " ' )
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
2012-02-22 15:14:10 +08:00
2015-01-22 00:55:57 +08:00
@override_settings ( PASSWORD_HASHERS = [ ' django.contrib.auth.hashers.SHA1PasswordHasher ' ] ,
2014-04-05 14:04:46 +08:00
ROOT_URLCONF = " admin_inlines.urls " )
2015-03-05 21:21:29 +08:00
class SeleniumFirefoxTests ( AdminSeleniumWebDriverTestCase ) :
2013-06-10 18:11:46 +08:00
available_apps = [ ' admin_inlines ' ] + AdminSeleniumWebDriverTestCase . available_apps
webdriver_class = ' selenium.webdriver.firefox.webdriver.WebDriver '
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
2015-03-05 21:21:29 +08:00
def setUp ( self ) :
# password = "secret"
User . objects . create (
pk = 100 , username = ' super ' , first_name = ' Super ' , last_name = ' User ' , email = ' super@example.com ' ,
password = ' sha1$995a3$6011485ea3834267d719b4c801409b8b1ddd0158 ' , is_active = True , is_superuser = True ,
is_staff = True , last_login = datetime . datetime ( 2007 , 5 , 30 , 13 , 20 , 10 ) ,
date_joined = datetime . datetime ( 2007 , 5 , 30 , 13 , 20 , 10 )
)
2012-09-09 03:07:33 +08:00
def test_add_stackeds ( self ) :
"""
Ensure that the " Add another XXX " link correctly adds items to the
stacked formset .
"""
self . admin_login ( username = ' super ' , password = ' secret ' )
self . selenium . get ( ' %s %s ' % ( self . live_server_url ,
2015-02-07 06:25:15 +08:00
reverse ( ' admin:admin_inlines_holder4_add ' ) ) )
2012-09-09 03:07:33 +08:00
inline_id = ' #inner4stacked_set-group '
rows_length = lambda : len ( self . selenium . find_elements_by_css_selector (
' %s .dynamic-inner4stacked_set ' % inline_id ) )
self . assertEqual ( rows_length ( ) , 3 )
add_button = self . selenium . find_element_by_link_text (
2013-10-23 22:04:02 +08:00
' Add another Inner4 stacked ' )
2012-09-09 03:07:33 +08:00
add_button . click ( )
self . assertEqual ( rows_length ( ) , 4 )
def test_delete_stackeds ( self ) :
self . admin_login ( username = ' super ' , password = ' secret ' )
self . selenium . get ( ' %s %s ' % ( self . live_server_url ,
2015-02-07 06:25:15 +08:00
reverse ( ' admin:admin_inlines_holder4_add ' ) ) )
2012-09-09 03:07:33 +08:00
inline_id = ' #inner4stacked_set-group '
rows_length = lambda : len ( self . selenium . find_elements_by_css_selector (
' %s .dynamic-inner4stacked_set ' % inline_id ) )
self . assertEqual ( rows_length ( ) , 3 )
add_button = self . selenium . find_element_by_link_text (
2013-10-23 22:04:02 +08:00
' Add another Inner4 stacked ' )
2012-09-09 03:07:33 +08:00
add_button . click ( )
add_button . click ( )
self . assertEqual ( rows_length ( ) , 5 , msg = " sanity check " )
for delete_link in self . selenium . find_elements_by_css_selector (
' %s .inline-deletelink ' % inline_id ) :
delete_link . click ( )
self . assertEqual ( rows_length ( ) , 3 )
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
def test_add_inlines ( self ) :
"""
Ensure that the " Add another XXX " link correctly adds items to the
inline form .
"""
self . admin_login ( username = ' super ' , password = ' secret ' )
self . selenium . get ( ' %s %s ' % ( self . live_server_url ,
2015-02-07 06:25:15 +08:00
reverse ( ' admin:admin_inlines_profilecollection_add ' ) ) )
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
# Check that there's only one inline to start with and that it has the
# correct ID.
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set ' ) ) , 1 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set ' ) [ 0 ] . get_attribute ( ' id ' ) ,
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' profile_set-0 ' )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set#profile_set-0 input[name=profile_set-0-first_name] ' ) ) , 1 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set#profile_set-0 input[name=profile_set-0-last_name] ' ) ) , 1 )
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
# Add an inline
self . selenium . find_element_by_link_text ( ' Add another Profile ' ) . click ( )
# Check that the inline has been added, that it has the right id, and
# that it contains the right fields.
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set ' ) ) , 2 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set ' ) [ 1 ] . get_attribute ( ' id ' ) , ' profile_set-1 ' )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set#profile_set-1 input[name=profile_set-1-first_name] ' ) ) , 1 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set#profile_set-1 input[name=profile_set-1-last_name] ' ) ) , 1 )
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
# Let's add another one to be sure
self . selenium . find_element_by_link_text ( ' Add another Profile ' ) . click ( )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set ' ) ) , 3 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set ' ) [ 2 ] . get_attribute ( ' id ' ) , ' profile_set-2 ' )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set#profile_set-2 input[name=profile_set-2-first_name] ' ) ) , 1 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
2012-03-05 16:13:09 +08:00
' .dynamic-profile_set#profile_set-2 input[name=profile_set-2-last_name] ' ) ) , 1 )
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
# Enter some data and click 'Save'
self . selenium . find_element_by_name ( ' profile_set-0-first_name ' ) . send_keys ( ' 0 first name 1 ' )
self . selenium . find_element_by_name ( ' profile_set-0-last_name ' ) . send_keys ( ' 0 last name 2 ' )
self . selenium . find_element_by_name ( ' profile_set-1-first_name ' ) . send_keys ( ' 1 first name 1 ' )
self . selenium . find_element_by_name ( ' profile_set-1-last_name ' ) . send_keys ( ' 1 last name 2 ' )
self . selenium . find_element_by_name ( ' profile_set-2-first_name ' ) . send_keys ( ' 2 first name 1 ' )
self . selenium . find_element_by_name ( ' profile_set-2-last_name ' ) . send_keys ( ' 2 last name 2 ' )
2012-03-05 16:13:09 +08:00
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
self . selenium . find_element_by_xpath ( ' //input[@value= " Save " ] ' ) . click ( )
2013-02-20 09:08:55 +08:00
self . wait_page_loaded ( )
2011-12-29 06:20:30 +08:00
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
# Check that the objects have been created in the database
self . assertEqual ( ProfileCollection . objects . all ( ) . count ( ) , 1 )
self . assertEqual ( Profile . objects . all ( ) . count ( ) , 3 )
def test_delete_inlines ( self ) :
self . admin_login ( username = ' super ' , password = ' secret ' )
self . selenium . get ( ' %s %s ' % ( self . live_server_url ,
2015-02-07 06:25:15 +08:00
reverse ( ' admin:admin_inlines_profilecollection_add ' ) ) )
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
# Add a few inlines
self . selenium . find_element_by_link_text ( ' Add another Profile ' ) . click ( )
self . selenium . find_element_by_link_text ( ' Add another Profile ' ) . click ( )
self . selenium . find_element_by_link_text ( ' Add another Profile ' ) . click ( )
self . selenium . find_element_by_link_text ( ' Add another Profile ' ) . click ( )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' #profile_set-group table tr.dynamic-profile_set ' ) ) , 5 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' form#profilecollection_form tr.dynamic-profile_set#profile_set-0 ' ) ) , 1 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' form#profilecollection_form tr.dynamic-profile_set#profile_set-1 ' ) ) , 1 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' form#profilecollection_form tr.dynamic-profile_set#profile_set-2 ' ) ) , 1 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' form#profilecollection_form tr.dynamic-profile_set#profile_set-3 ' ) ) , 1 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' form#profilecollection_form tr.dynamic-profile_set#profile_set-4 ' ) ) , 1 )
# Click on a few delete buttons
self . selenium . find_element_by_css_selector (
' form#profilecollection_form tr.dynamic-profile_set#profile_set-1 td.delete a ' ) . click ( )
self . selenium . find_element_by_css_selector (
' form#profilecollection_form tr.dynamic-profile_set#profile_set-2 td.delete a ' ) . click ( )
# Verify that they're gone and that the IDs have been re-sequenced
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' #profile_set-group table tr.dynamic-profile_set ' ) ) , 3 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' form#profilecollection_form tr.dynamic-profile_set#profile_set-0 ' ) ) , 1 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' form#profilecollection_form tr.dynamic-profile_set#profile_set-1 ' ) ) , 1 )
2012-05-03 22:39:16 +08:00
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
Fixed #2879 -- Added support for the integration with Selenium and other in-browser testing frameworks. Also added the first Selenium tests for `contrib.admin`. Many thanks to everyone for their contributions and feedback: Mikeal Rogers, Dirk Datzert, mir, Simon G., Almad, Russell Keith-Magee, Denis Golomazov, devin, robertrv, andrewbadr, Idan Gazit, voidspace, Tom Christie, hjwp2, Adam Nelson, Jannis Leidel, Anssi Kääriäinen, Preston Holmes, Bruno Renié and Jacob Kaplan-Moss.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17241 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2011-12-22 16:33:58 +08:00
' form#profilecollection_form tr.dynamic-profile_set#profile_set-2 ' ) ) , 1 )
2012-02-22 15:14:10 +08:00
2012-09-09 03:07:33 +08:00
def test_alternating_rows ( self ) :
self . admin_login ( username = ' super ' , password = ' secret ' )
self . selenium . get ( ' %s %s ' % ( self . live_server_url ,
2015-02-07 06:25:15 +08:00
reverse ( ' admin:admin_inlines_profilecollection_add ' ) ) )
2012-09-09 03:07:33 +08:00
# Add a few inlines
self . selenium . find_element_by_link_text ( ' Add another Profile ' ) . click ( )
self . selenium . find_element_by_link_text ( ' Add another Profile ' ) . click ( )
row_selector = ' form#profilecollection_form tr.dynamic-profile_set '
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
" %s .row1 " % row_selector ) ) , 2 , msg = " Expect two row1 styled rows " )
self . assertEqual ( len ( self . selenium . find_elements_by_css_selector (
" %s .row2 " % row_selector ) ) , 1 , msg = " Expect one row2 styled row " )
2012-02-22 15:14:10 +08:00
class SeleniumChromeTests ( SeleniumFirefoxTests ) :
2012-03-05 16:13:09 +08:00
webdriver_class = ' selenium.webdriver.chrome.webdriver.WebDriver '
2013-11-03 12:36:09 +08:00
2012-03-05 16:13:09 +08:00
class SeleniumIETests ( SeleniumFirefoxTests ) :
2012-05-01 02:38:44 +08:00
webdriver_class = ' selenium.webdriver.ie.webdriver.WebDriver '