3
(hx                 @   s  d dl mZ d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dl	Z	d dl
Z
d dlmZ d dlmZ d dlmZ d dlmZ yd dlmZ W n  ek
r   d dlmZ Y nX d dlmZ d d	lmZ d d
lmZ d dlm Z  d dl!m"Z" d dl#m$Z$m%Z% ddl&m'Z' ej(e)Z*e+e,ds,dd Z-dd Z.dd Z/dd Z0dd Z1dd Z2d(ddZ3eddG d d! d!e'eZ4G d"d# d#e5Z6d$d% Z7d&d' Z8dS ))    )absolute_importN)settings)site)User)StaticLiveServerTestCase)reverse)override_settings)six)ugettext)ActionChains)By)visibility_of_element_locatedelement_to_be_clickable   )SeleniumTestCasecmpc             C   s   | |k| |k  S )N )abr   r   H/tmp/pip-install-q3hcpn_q/django-nested-admin/nested_admin/tests/base.pyr   '   s    c             C   s   t | tjS )N)
isinstancecollectionsSequence)or   r   r   is_sequence+   s    r   c             C   s   t | tjS )N)r   r	   integer_types)r   r   r   r   
is_integer/   s    r   c             C   s   t | tjS )N)r   r	   string_types)r   r   r   r   is_str3   s    r   c             C   s   dj | jj| jjgS )N-)join_meta	app_label
model_name)mr   r   r   <lambda>7   s    r%   c             C   s   d|  S )Nz*contains(concat(" ", @class, " "), " %s ")r   )	classnamer   r   r   	xpath_cls:   s    r'   c             C   s(   d}dt d|f }| r$|d|  7 }|S )NzAnot(contains(@class, "-drag")) and not(contains(@class, "thead"))z	%s and %szdjn-itemz and contains(@class, "-%s"))r'   )r#   Zxpath_item_predicateexprr   r   r   
xpath_item>   s
    r)   znested_admin.tests.urls)ZROOT_URLCONFc                   s  e Zd ZedejkZedejkZdZdZ	e
dd Ze fddZ fdd	Zd
d ZdKddZdd ZdLddZdMddZdNddZdOddZdPddZdQddZdRddZejdSdd ZejdTd!d"ZejdUd#d$ZejdVd%d&ZejdWd'd(Zejd)d* Z dXd+d,Z!d-d. Z"d/d0 Z#dYd3d4Z$dZd5d6Z%d[d7d8Z&d\d9d:Z'd;d< Z(d]d=d>Z)d?d@ Z*dAdB Z+dCdD Z,d^dEdFZ-d_dGdHZ.d`dIdJZ/  Z0S )aBaseNestedAdminTestCase	grappellisuitNc             C   sH   ddddddddg}| j r&|jd	d
 t| jjdd	 }|j| d S )Nzdjango.contrib.authzdjango.contrib.contenttypeszdjango.contrib.messageszdjango.contrib.sessionszdjango.contrib.siteszdjango.contrib.staticfileszdjango.contrib.adminnested_adminr   r+   .)has_grappelliinserttype
__module__
rpartitionappend)selfZappsZcurrent_appr   r   r   available_appsO   s    z&BaseNestedAdminTestCase.available_appsc                sT   t t| j  dd l}tj| j } fdd  || _fdd| j| _d S )Nr   c                s:   | j g g}x*t| dd pg D ]}|d j | qW |S )NZinlinesr   )modelgetattrr4   )Zadmindatainline)descend_admin_inlinesr   r   r;   h   s    
zABaseNestedAdminTestCase.setUpClass.<locals>.descend_admin_inlinesc                s*   t | trdd t | D S t| S d S )Nc             S   s   g | ]}|qS r   r   ).0r$   r   r   r   
<listcomp>r   s    zYBaseNestedAdminTestCase.setUpClass.<locals>.recursive_map_model_names.<locals>.<listcomp>)r   listmapget_model_name)r9   )recursive_map_model_namesr   r   rA   p   s    
zEBaseNestedAdminTestCase.setUpClass.<locals>.recursive_map_model_names)	superr*   
setUpClassZnested_admin.tests.urls
admin_site	_registry
root_modelmodelsmodel_names)clsr-   Z
root_admin)	__class__)r;   rA   r   rC   a   s    
z"BaseNestedAdminTestCase.setUpClassc                sD   t t| j  | jjdd | jjd tjjdddd d| _	d S )	Ni`  i  
   rB   secretzsuper@example.com)usernamepasswordemailF)
rB   r*   setUpseleniumset_window_sizeset_page_load_timeoutr   ZobjectsZcreate_superuser	logged_in)r5   )rJ   r   r   rP   x   s
    zBaseNestedAdminTestCase.setUpc          	   C   sP   y| j jd }W n   Y n0X | j jj| | j j  | j jj| j jd  d S )Nr   r   )rQ   window_handles	switch_towindowclose)r5   Zpopup_windowr   r   r   tearDown   s    
z BaseNestedAdminTestCase.tearDownrK   c             C   s4   ddl m} ddlm} | j|j|j|f| dS )zX
        Helper function that blocks until a CSS selector is found on the page.
        r   )r   )expected_conditionsN)selenium.webdriver.common.byr   Zselenium.webdriver.supportrZ   
wait_untilZpresence_of_element_locatedCSS_SELECTOR)r5   Zcss_selectortimeoutr   Zecr   r   r   wait_for   s
    z BaseNestedAdminTestCase.wait_forc             C   s4   ddl m} y| jd W n |k
r.   Y nX dS )z7
        Block until page has started to load.
        r   )TimeoutExceptionbodyN)Zselenium.common.exceptionsr`   r_   )r5   r`   r   r   r   wait_page_loaded   s
    z(BaseNestedAdminTestCase.wait_page_loadedc             C   s   | j j||d | jjd| jdf  | j  x.| j jj D ]\}}| jj||j	dd q<W |r| jjd| j|f  | j  d| _
dS )z8
        Helper function to log into the admin.
        )rM   rN   z%s%sz/static/blank.html/)namevaluepathTN)clientloginrQ   getlive_server_urlrb   cookiesitemsZ
add_cookiere   rT   )r5   rM   rN   Z	login_urlkvr   r   r   admin_login   s    z#BaseNestedAdminTestCase.admin_loginc             C   s$   ddl m} || j|j|| dS )a=  
        Helper function that blocks the execution of the tests until the
        specified callback returns a value that is not falsy. This function can
        be called, for example, after clicking a link or submitting a form.
        See the other public methods that call this function for more details.
        r   )WebDriverWaitN)Zselenium.webdriver.support.waitrp   rQ   Zuntil)r5   callbackr^   messagerp   r   r   r   r\      s    z"BaseNestedAdminTestCase.wait_untilc             C   s"   | j ttj|f|d| d d S )Nz4Timeout waiting for visible element at selector='%s')r^   rr   )r\   r   r   r]   )r5   selectorr^   r   r   r   wait_until_visible_selector   s    z3BaseNestedAdminTestCase.wait_until_visible_selectorc             C   s"   | j ttj|f|d| d d S )Nz3Timeout waiting for clickable element at xpath='%s')r^   rr   )r\   r   r   ZXPATH)r5   xpathr^   r   r   r   wait_until_clickable_xpath   s    z2BaseNestedAdminTestCase.wait_until_clickable_xpathc             C   s"   | j ttj|f|d| d d S )Nz6Timeout waiting for clickable element at selector='%s')r^   rr   )r\   r   r   r]   )r5   rs   r^   r   r   r   wait_until_clickable_selector   s    z5BaseNestedAdminTestCase.wait_until_clickable_selectorc                s    | j  fdd|d  d d S )Nc                s
   | j  S )N)find_element_by_css_selector)driver)rs   r   r   r%      s    zGBaseNestedAdminTestCase.wait_until_available_selector.<locals>.<lambda>z6Timeout waiting for available element at selector='%s')r^   rr   )r\   )r5   rs   r^   r   )rs   r   wait_until_available_selector   s    
z5BaseNestedAdminTestCase.wait_until_available_selectorc                s    | j  fdd|d  d d S )Nc                s
   | j  S )N)find_element_by_xpath)ry   )ru   r   r   r%      s    zDBaseNestedAdminTestCase.wait_until_available_xpath.<locals>.<lambda>z3Timeout waiting for available element at xpath='%s')r^   rr   )r\   )r5   ru   r^   r   )ru   r   wait_until_available_xpath   s    
z2BaseNestedAdminTestCase.wait_until_available_xpathc             c   s   | j || | jj|V  d S )N)rt   rQ   rx   )r5   rs   r^   r   r   r   visible_selector   s    z(BaseNestedAdminTestCase.visible_selectorc             c   s   | j || | jj|V  d S )N)rw   rQ   rx   )r5   rs   r^   r   r   r   clickable_selector   s    z*BaseNestedAdminTestCase.clickable_selectorc             c   s   | j || | jj|V  d S )N)rv   rQ   r{   )r5   ru   r^   r   r   r   clickable_xpath   s    z'BaseNestedAdminTestCase.clickable_xpathc             c   s   | j || | jj|V  d S )N)rz   rQ   rx   )r5   rs   r^   r   r   r   available_selector   s    z*BaseNestedAdminTestCase.available_selectorc             c   s   | j || | jj|V  d S )N)r|   rQ   r{   )r5   ru   r^   r   r   r   available_xpath   s    z'BaseNestedAdminTestCase.available_xpathc             c   sv   | j dd  | jjj| jjd  d V  z.y| j dd  W n   | j   Y nX W d | jjj| jjd  X d S )Nc             S   s   t | jdkS )N   )lenrU   )dr   r   r   r%      s    z@BaseNestedAdminTestCase.switch_to_popup_window.<locals>.<lambda>r   c             S   s   t | jdkS )Nr   )r   rU   )r   r   r   r   r%      s    r   )r\   rQ   rV   rW   rU   rX   )r5   r   r   r   switch_to_popup_window   s    z.BaseNestedAdminTestCase.switch_to_popup_windowc             C   s   | j jj| j jjj f}|r2td| |jgd}ntd| }| jsT| jdd| n| j	j
d| j|f  | j  | j	jdd | j	jd	 | j	jd
 | j  d S )Nzadmin:%s_%s_change)argszadmin:%s_%s_addrB   rL   z%s%si`  i  rK   zwindow.$ = django.jQuery)rF   r!   r"   Zobject_namelowerr   pkrT   ro   rQ   ri   rj   rb   rR   rS   execute_script"make_header_footer_position_static)r5   objinfourlr   r   r   
load_admin   s    z"BaseNestedAdminTestCase.load_adminc             C   s   dd | j jdD }t|dkr:tjdtj|dd  t| j jd}|rRd	nd
}| j j	d| j
  |r| j  | j jdd | j jd | j jd | j  d S )Nc             S   s   g | ]}d |d kr|qS )Zfaviconrr   r   )r<   er   r   r   r=     s    z5BaseNestedAdminTestCase.save_form.<locals>.<listcomp>browserr   zFound browser errors: %s   )indentz0return django.jQuery("[name=_continue]").length;Z	_continueZ_savez//*[@name="%s"]i`  i  rK   zwindow.$ = django.jQuery)rQ   Zget_logr   loggererrorjsondumpsboolr   r{   clickrb   rR   rS   r   )r5   Zbrowser_errorsZhas_continueZ	name_attrr   r   r   	save_form  s    z!BaseNestedAdminTestCase.save_formc             C   s   | j jd dS )zBMake grappelli header and footer element styles 'position: static'z$('footer').attr('class', 'grp-module grp-submit-row');$('#content-inner').css('bottom', '0');$('#grp-header').css('position', 'static');$('#grp-content').css('top', '0');N)rQ   r   )r5   r   r   r   r   !  s    z:BaseNestedAdminTestCase.make_header_footer_position_staticFTc                s  g }t | j\}}t |pg }|r&tnt |rxt|r |d ry&t fdd|dd D rf|S W q   Y qX n,yt fdd|D r|S W n   Y nX d}|rt|rt|d rt|d dkr|j d }q|jd n|s|S x\t	|D ]N\}}	t|dkrt
d|	dkrr|s6t
dt|dkrLt
d	|rf|j|d d  n
|jd P t|	 rt|	 rt
d
t|	j t|	rt|dkrt
d| d|	g}	t|	 rt|	dkrt
d|t|	f tdd |	D st
d| |	\}
}||
 \}}|r>|j||g n|j|
|g  qW |dk	r|rv|j|| d  n
|j| |S )aZ
  
        To allow for the case where there are multiple inlines defined on a
        given ModelAdmin or InlineModelAdmin, we need indexes to be a list of
        lists (or at any rate an iterable of iterables, but lets call the
        outermost iterable a list, and the elements themselves tuples).
        The elements of the top-level list should be seen as directions for
        how to descend the hierarchy of the inlines (an empty list thus
        referring to the root model, which is not an inline). Descending down
        the hierarchy, each element is a 2-tuple (a, b) where ``a``
        is the index on the ModelAdmin.inlines attribute, and b is a 0-indexed
        number corresponding to the actual item in that inline currently on
        the page.

        Some operations, such as ``add_inline`` and ``get_num_inlines`` (along
        with the helper method ``get_group``) refer not to a specific item
        within an inline, but to the group of inlines as a whole (at least
        at the last step of descending the hierarchy: for instance when
        clicking add on a nested inline; the add button is at the group-level,
        but the parents of that group are all specific inline items). In the
        case of such operations that operate at the group level, the last item
        is a 1-tuple to indicate which group of the available inlines at that
        level is the target.

        In the trivial case, there is only one inline at every level. Most of
        the unit tests are trivial in this sense. It would be very burdensome,
        not to mention difficult to parse, if the operation::

            self.add_inline(indexes=[1, 3, 2])

        had to be written out as::

            self.add_inline(indexes=[(0, 1), (0, 3), (0, 2), (0, ))])

        The first example above is hard enough to follow without adding a
        number of zeros to each element (and at the end!) to accommodate the
        possibility of there being multiple inline classes when we already now
        that there is only one.

        To ease the burden of writing test cases, it is possible to use an
        integer at a given level of the indexes if there is only one possible
        inline at that level. It is similarly alright to omit the terminal
        1-tuple of (0, ) to ``add_inline`` and ``get_num_inlines`` if there
        is only one possible inline group that can be added to.

        The purposes of this function is to normalize the indexes parameter
        so that it can be converted from the shorter notation to a fully
        qualified one of 2-tuples (and the occasional terminal 1-tuple).
        r   c                s    g | ]\}} |ot |qS r   )r   )r<   r   r   )inline_type_checkr   r   r=   d  s    z>BaseNestedAdminTestCase._normalize_indexes.<locals>.<listcomp>Nc                s    g | ]\}} |ot |qS r   )r   )r<   r   r   )r   r   r   r=   j  s    r   z'Indexes depth greater than inline depthz Unexpected None found in indexeszdTerminal index to inline class omitted in group-level operation, but parent has more than one inlinez%Unexpected type %s in list of indexeszRindexes[%d] using shorthand integer value, but more than one inline to choose fromr   z*Expected indexes[%d] to have len 2, got %dc             S   s   g | ]}t |qS r   )r   )r<   ir   r   r   r=     s    z#indexes[%d] must have only integersr   r   r   )r>   rH   r   r   r   allr   popr4   	enumerate
ValueErrorr1   __name__)r5   indexesis_groupnamed_modelsZnorm_indexesZroot_model_nameZinline_model_namesZgroup_indexlevelZlevel_indexesinline_indexZinline_itemZinline_model_namer   )r   r   _normalize_indexes)  sz    1$





z*BaseNestedAdminTestCase._normalize_indexesc             C   s   t | ||d}|j|d d S )N)from_indexes
to_indexes)screenshot_hack)DragAndDropActionmove_to_target)r5   r   r   r   actionr   r   r   drag_and_drop_item  s    z*BaseNestedAdminTestCase.drag_and_drop_itemc             C   sH   | j |dd}|d }| j|d}|jd}d||f }| jjd| S )	NT)r   r   )r   idz#%s .djn-dynamic-form-%szreturn $('%s').lengthr   )r   	get_groupget_attributerQ   r   )r5   r   r#   groupZgroup_idrs   r   r   r   get_num_inlines  s    
z'BaseNestedAdminTestCase.get_num_inlinesc             C   sn   | j |dd}|j }g }x*|D ]"\}}|dt||d f g7 }q W |d| g7 }ddj| }| jj|S )NT)r   z
/*[%s][%d]r   z/*[@data-inline-model='%s']z/%src   )r   r   r)   r    rQ   r{   )r5   r   r#   Z
expr_partsZparent_modelZparent_item_indexr(   r   r   r   r     s    z!BaseNestedAdminTestCase.get_groupc             C   sF   | j |}|j \}}|j| | j|d}|jdt||d f S )N)r   z.//*[%s][%d]r   )r   r   r4   r   r{   r)   )r5   r   r#   
item_indexr   r   r   r   get_item  s
    

z BaseNestedAdminTestCase.get_itemc             C   s   | j |dd}| j|}|d	 }d| j|jd|f }| j|}|j  W d Q R X ||g|d
< |d k	rz| jd||d |d k	r| jd||d d S )NT)r   r   z0#%s .djn-add-item a.djn-add-handler.djn-model-%sr   rd   )r   slugr   r   )r   r   r   r   r~   r   	set_field)r5   r   rd   r   Z	new_indexr#   Zadd_selectorelr   r   r   
add_inline  s    
z"BaseNestedAdminTestCase.add_inlinec          	   C   sP   | j |}|d d }d| j|jd|f }| j|}|j  W d Q R X d S )Nr   r   z$#%s .djn-remove-handler.djn-model-%sr   r   )r   r   r   r~   r   )r5   r   r#   Zremove_selectorr   r   r   r   remove_inline  s    
z%BaseNestedAdminTestCase.remove_inlinec          
   C   sp   | j |}|d d }| j|jd}d||f }| j|}|j  W d Q R X | jrld||f }| j| d S )Nr   r   r   z$#%s .djn-delete-handler.djn-model-%sz2#%s.grp-predelete .grp-delete-handler.djn-model-%sr   )r   r   r   r~   r   r/   rw   )r5   r   r#   item_iddelete_selectorr   undelete_selectorr   r   r   delete_inline  s    


z%BaseNestedAdminTestCase.delete_inlinec          
   C   sp   | j |}|d d }| j|jd}d||f }| j|}|j  W d Q R X | jrld||f }| j| d S )Nr   r   r   z$#%s .djn-delete-handler.djn-model-%sz8#%s:not(.grp-predelete) .grp-delete-handler.djn-model-%sr   )r   r   r   r~   r   r/   rw   )r5   r   r#   r   r   r   r   r   r   r   undelete_inline  s    

z'BaseNestedAdminTestCase.undelete_inlinec             C   s4   | j |}|sd| S | j|djd}d||f S )Nz#id_%s)r   r   z	#id_%s-%s)r   r   r   )r5   attnamer   Zfield_prefixr   r   r   get_form_field_selector  s
    
z/BaseNestedAdminTestCase.get_form_field_selectorc             C   s$   | j |}| j||d}| jj|S )N)r   )r   r   rQ   rx   )r5   r   r   field_selectorr   r   r   	get_field  s    
z!BaseNestedAdminTestCase.get_fieldc          	   C   sD   | j |}| j||d}| j|}|j  |j| W d Q R X d S )N)r   )r   r   r~   clearZ	send_keys)r5   r   re   r   r   r   r   r   r   r     s
    
z!BaseNestedAdminTestCase.set_field)rK   )N)rK   N)rK   )rK   )rK   )rK   )rK   )rK   )rK   )rK   )rK   )rK   )N)FT)F)N)N)NNN)N)N)N)1r   r2   __qualname__r   r   INSTALLED_APPSr/   has_suitrF   Znested_modelspropertyr6   classmethodrC   rP   rY   r_   rb   ro   r\   rt   rv   rw   rz   r|   
contextlibcontextmanagerr}   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   __classcell__r   r   )rJ   r   r*   F   sV   










|






r*   c               @   s   e Zd Zdd Zedd Zedd Zdd Zd	d
 Zdd Z	dd Z
dd Zdd Zdd Zedd Zdd ZdddZdS )r   c             C   sr  || _ |j| _t|t|kr&d| _nd| _| j j|dd| _| j j|| jdd| _| j j|| jdd}t|d
 s|d d |d< | j j|| _	t| jd r| jd dg| jd< dd | jD | _| j j
d }x&| jd d D ]\}}|| d }qW t|| _| jd d | jd d krV| jd d | jd d k rV| jd d  d7  < | j jt|t|d	 d S )NTF)r   )r   r   r   r   c             S   s   g | ]}t |qS r   )tuple)r<   r   r   r   r   r=     s    z.DragAndDropAction.__init__.<locals>.<listcomp>z+Depth of source and target must be the samer   r   r   r   r   r   r   r   r   r   r   r   )	test_caserQ   r   Ztarget_is_emptyr   r   r   r   r   target_num_itemsrG   target_num_inlinesZassertEqual)r5   r   r   r   Znum_inlines_indexesZinline_modelsr   r   r   r   r   __init__  s2    
zDragAndDropAction.__init__c             C   s   t | ds| jj| jd}|jdkr*d}nd| jjrfdjdtd dtd dtd	 d
td g}n(djdtd dtd dtd g}|j|| _	| j	S )N_source)r   divh3rc   z*[%s]zdjn-trzdjn-tdZtoolsz/*[%s]zdjn-drag-handlerzis-sortable)
hasattrr   r   r   tag_namer/   r    r'   r{   r   )r5   Zsource_itemZdrag_handler_xpathr   r   r   source*  s     






zDragAndDropAction.sourcec             C   s   t | dst| jdkr0| jj| jd d	 }n| j}dtd| jd
 d d tdf }| j| jd d kr|dt | jd d d d 7 }|j	|| _
| j
S )N_targetr   z.//*[%s][%d]//*[%s]z	djn-groupr   z	djn-itemsz/*[%(item_pred)s][%(item_pos)d])Z	item_predZitem_posr   r   r   r   )r   r   r   r   r   rQ   r'   r   r)   r{   r   )r5   Ztarget_inline_parentZtarget_xpathr   r   r   target@  s    
"zDragAndDropAction.targetc          	   C   s   | j }| jjr.| jjdkr.|jdkr.|jd}t| jj|ddj	 j
  tjd t| jjddj
  tjd t| jjddj
  | jjd}|S Q R X d S )	NZchromer   r   r   g?   z.ui-sortable-helperi)r   r   r   r   r   rx   r   rQ   Zmove_to_element_with_offsetZclick_and_holdperformtimesleepmove_by_offsetr}   )r5   r   r   r   r   r   initialize_dragQ  s    



z!DragAndDropAction.initialize_dragc             C   sb   |dk rdnd}x*t d||D ]}t| jjd|j  qW ||kr^t| jjd|| j  d S )Nr   r   i)ranger   rQ   r   r   )r5   Zx_offsety_offset	incrementoffsetr   r   r   r   `  s
    z DragAndDropAction.move_by_offsetc             C   s   t | jj j  d S )N)r   rQ   releaser   )r5   r   r   r   r   g  s    zDragAndDropAction.releasec             C   s~  d}d}|j d }| jdd t| j}td| jd	 d   k oL| jd kn  o| jd
 d | jd kot|d d | jd d dk}x|j	d }|j	d | }	|r|	dkr|	|j d 7 }	n|	|j d | 7 }	t
|	dk rP ||krP tt|	d }
| jd|
 |dkrR||j	d krR| j  tjd | j }tjd | jd|
 | j}t||}|dkrnP |d7 }qW |S )N   r   heightr   yg?g?r   r   r   r   r   r   )sizer   r   r   r   r   r   r   current_positionlocationabsintroundr   r   r   r   )r5   helperr   limitcounthelper_heightdesired_posZtarget_bottomZhelper_yr   Zscaled_offsetcurr_pospos_diffr   r   r   _match_helper_with_targetj  sB    

*"




z+DragAndDropAction._match_helper_with_targetc             C   sD   |j djd}d}x*|D ]"}|j|jkr,P ||r|d7 }qW |S )aS  
        For an unknown reason, evaluating XPath expressions of the form

            preceding-sibling::*[not(contains(@attr, 'value'))]

        Where 'value' is contained in at least one of the preceding siblings,
        is extraordinarily slow. So we just grab all siblings and iterate
        through the elements in python.
        z	parent::**r   r   )r{   Zfind_elements_by_xpathr   )r5   ctx	conditionZsiblingsr   r   r   r   r   _num_preceding_siblings  s    

z)DragAndDropAction._num_preceding_siblingsc             C   s   dd }| j ||dS )Nc             S   s0   t tjd| jd}|dh@ o.|dddh@  S )Nz\s+classzdjn-itemzdjn-no-dragz	djn-theadzdjn-item-dragging)setresplitr   )r   classesr   r   r   is_djn_item  s    
z?DragAndDropAction._num_preceding_djn_items.<locals>.is_djn_item)r   )r   )r5   r   r   r   r   r   _num_preceding_djn_items  s    z*DragAndDropAction._num_preceding_djn_itemsc             C   s   dd }| j ||dS )Nc             S   s   dt jd| jdkS )Nz	djn-groupz\s+r   )r   r   r   )r   r   r   r   is_djn_group  s    zADragAndDropAction._num_preceding_djn_groups.<locals>.is_djn_group)r   )r   )r5   r   r  r   r   r   _num_preceding_djn_groups  s    z+DragAndDropAction._num_preceding_djn_groupsc             C   s   | j jd}g }d }dtd }xftdt| jD ]R}|d krD|}n
|j|}| j|}|jdtd }| j|}|j	d||f q2W t
|S )Nz.ui-sortable-placeholderzancestor::*[%s][1]zdjn-itemr   z	djn-group)rQ   rx   r'   r   r   r   r{   r   r  r0   r   )r5   placeholderposr   Zancestor_xpathr   r   r   r   r   r   r     s    


z"DragAndDropAction.current_positionc       
      C   s   d}d}|j d }| jdkr4tdtt|d }ntt|d }t| j}x@||krZP | j}t||}	|	dkrtP | j	d|	|  |d7 }qPW d S )N   r   r   r   g      C@g      $@)
r   r   maxr   r   r   r   r   r   r   )
r5   r   r   r   r   r   Zdyr   r   r   r   r   r   _finesse_position  s     



z#DragAndDropAction._finesse_positionFc             C   sN   | j }| j }|r*d| jjkr*| jjd | j||}| j|| | j  d S )NZ	phantomjsz	/dev/null)	r   r   r   r   rQ   Zsave_screenshotr   r  r   )r5   r   r   r   r   r   r   r     s    z DragAndDropAction.move_to_targetN)F)r   r2   r   r   r   r   r   r   r   r   r   r   r   r  r   r  r   r   r   r   r   r     s   #(r   c             C   s   dt jkrtj| S | S )Nr+   )r   r   unittestexpectedFailure)funcr   r   r   expected_failure_if_grappelli  s    

r  c             C   s   dt jkrtj| S | S )Nr,   )r   r   r  r	  )r
  r   r   r   expected_failure_if_suit  s    

r  )N)9
__future__r   r   r   copyr   loggingr   r   r  ZdjangoZdjango.confr   Zdjango.contrib.admin.sitesr   rD   Zdjango.contrib.auth.modelsr   Z"django.contrib.staticfiles.testingr   Zdjango.urlsr   ImportErrorZdjango.core.urlresolversZdjango.test.utilsr   Zdjango.utilsr	   Zdjango.utils.translationr
   _Z'selenium.webdriver.common.action_chainsr   r[   r   Z.selenium.webdriver.support.expected_conditionsr   r   rQ   r   	getLoggerr   r   r   __builtins__r   r   r   r   r@   r'   r)   r*   objectr   r  r  r   r   r   r   <module>   sT   


   A `