Skip to content

Commit

Permalink
chore: CI updates, fix deprecation issues (#252)
Browse files Browse the repository at this point in the history
* fix(ci): bump version of nanasess/setup-chromedriver to v2.2.2

* fix(ci): use latest selenium and update deprecated methods

* fix(ci): increase speed of move_to_element actions

* fix(tests): finesse element offset targets for drag-and-drop operations

* fix: flake8 and black failures

* chore(ci): update tox envlist and gha matrix

* add setuptools to tox until jazzband/django-polymorphic#599 is released
  • Loading branch information
fdintino authored Jul 13, 2024
1 parent 0b2bc4f commit 623c5ba
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 72 deletions.
36 changes: 19 additions & 17 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,28 @@ jobs:
strategy:
fail-fast: false
matrix:
grappelli: ["0"]
python-version: ["3.8"]
django-version: ["3.2"]
grappelli: ["0", "1"]
python-version: ["3.11"]
django-version: ["4.2"]
exclude:
- python-version: "3.11"
grappelli: "1"
include:
- grappelli: "0"
name-suffix: ""
- python-version: "3.9"
django-version: "4.0"
django-version: "4.2"
grappelli: "1"
- python-version: "3.9"
django-version: "5.0"
grappelli: "0"
- python-version: "3.10"
django-version: "4.1"
- grappelli: "1"
name-suffix: " + grappelli"
python-version: "3.7"
django-version: "3.2"
- grappelli: "1"
name-suffix: " + grappelli"
python-version: "3.8"
django-version: "4.0"
django-version: "5.0"
grappelli: "1"
- python-version: "3.12"
django-version: "5.1"
grappelli: "0"

runs-on: ubuntu-latest
name: Django ${{ matrix.django-version }} (Python ${{ matrix.python-version }})${{ matrix.name-suffix }}
name: Django ${{ matrix.django-version }} (Python ${{ matrix.python-version }})${{ matrix.grappelli == '1' && ' + grappelli' || '' }}

env:
DJANGO: ${{ matrix.django-version }}
Expand All @@ -45,7 +46,8 @@ jobs:
python-version: ${{ matrix.python-version }}

- name: Setup chromedriver
uses: nanasess/setup-chromedriver@v1.0.5
# uses: nanasess/setup-chromedriver@v2.2.2
uses: nanasess/setup-chromedriver@42cc2998329f041de87dc3cfa33a930eacd57eaa

- name: Install tox
run: |
Expand Down
12 changes: 8 additions & 4 deletions nested_admin/nested.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,11 @@ def inline_formset_data(self):
"lookupAutocomplete": getattr(
self.opts, "autocomplete_lookup_fields", {}
),
"formsetFkName": self.formset.fk.name
if getattr(self.formset, "fk", None)
else "",
"formsetFkName": (
self.formset.fk.name
if getattr(self.formset, "fk", None)
else ""
),
"formsetFkModel": formset_fk_model,
"nestingLevel": getattr(self.formset, "nesting_depth", 0),
"fieldNames": {
Expand Down Expand Up @@ -538,13 +540,15 @@ def __init__(self, *args, **kwargs):
_get_formsets = ModelAdmin._get_formsets

def get_formset(self, request, obj=None, **kwargs):
FormSet = BaseFormSet = kwargs.pop("formset", self.formset)
BaseFormSet = kwargs.pop("formset", self.formset)

if self.sortable_field_name:

class FormSet(BaseFormSet):
sortable_field_name = self.sortable_field_name

else:
FormSet = BaseFormSet
kwargs["formset"] = FormSet
return super().get_formset(request, obj, **kwargs)

Expand Down
9 changes: 7 additions & 2 deletions nested_admin/polymorphic.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,15 @@ class Child(
formset = NestedBasePolymorphicInlineFormSet

def get_formset(self, request, obj=None, **kwargs):
FormSet = BaseFormSet = kwargs.pop("formset", self.formset)
BaseFormSet = kwargs.pop("formset", self.formset)

if self.sortable_field_name:

class FormSet(BaseFormSet):
sortable_field_name = self.sortable_field_name

else:
FormSet = BaseFormSet
kwargs["formset"] = FormSet
return super(PolymorphicInlineModelAdmin.Child, self).get_formset(
request, obj, **kwargs
Expand Down Expand Up @@ -186,13 +188,16 @@ class Child(
formset = NestedBaseGenericPolymorphicInlineFormSet

def get_formset(self, request, obj=None, **kwargs):
FormSet = BaseFormSet = kwargs.pop("formset", self.formset)
BaseFormSet = kwargs.pop("formset", self.formset)

if self.sortable_field_name:

class FormSet(BaseFormSet):
sortable_field_name = self.sortable_field_name

else:
FormSet = BaseFormSet

kwargs["formset"] = FormSet
return super(GenericPolymorphicInlineModelAdmin.Child, self).get_formset(
request, obj, **kwargs
Expand Down
16 changes: 8 additions & 8 deletions nested_admin/tests/admin_widgets/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def check_datetime(self, indexes):
now_link_xpath = "following-sibling::*[1]/a[1]"
date_el.clear()
time_el.clear()
self.click(date_el.find_element_by_xpath(now_link_xpath))
self.click(date_el.find_element(By.XPATH, now_link_xpath))
if self.has_grappelli:
selector = "#ui-datepicker-div .ui-state-highlight"
with self.clickable_selector(selector, timeout=1) as el:
Expand All @@ -119,7 +119,7 @@ def check_datetime(self, indexes):
"Datepicker widget did not close",
)
time.sleep(0.2)
self.click(time_el.find_element_by_xpath(now_link_xpath))
self.click(time_el.find_element(By.XPATH, now_link_xpath))
if self.has_grappelli:
selector = "#ui-timepicker .ui-state-active"
with self.clickable_selector(selector, timeout=1) as el:
Expand Down Expand Up @@ -153,7 +153,7 @@ def check_m2m(self, indexes):
def check_fk(self, indexes):
field = self.get_field("fk1", indexes)
parent = field.get_property("parentNode").get_property("parentNode")
add_related = parent.find_element_by_css_selector(".add-related")
add_related = parent.find_element(By.CSS_SELECTOR, ".add-related")
if self.has_grappelli:
# Grappelli can be very slow to initialize fk bindings, particularly
# when run on travis-ci
Expand Down Expand Up @@ -185,7 +185,7 @@ def check_gfk_related_lookup(self, indexes):
% object_id_field_id,
)

lookup_el = self.selenium.find_element_by_css_selector(related_lookup_selector)
lookup_el = self.selenium.find_element(By.CSS_SELECTOR, related_lookup_selector)
lookup_el.click()
with self.switch_to_popup_window():
with self.clickable_xpath('//tr//a[text()="Zither"]') as el:
Expand All @@ -195,7 +195,7 @@ def check_gfk_related_lookup(self, indexes):
z_pk = "%s" % WidgetsM2M.objects.get(name="Zither").pk

def element_value_populated(d):
el = d.find_element_by_css_selector("#%s" % object_id_field_id)
el = d.find_element(By.CSS_SELECTOR, "#%s" % object_id_field_id)
return el.get_attribute("value")

self.wait_until(
Expand Down Expand Up @@ -376,8 +376,8 @@ def test_autocomplete_single_init(self):
self.load_admin()
self.add_inline()
self.add_inline([1])
autocomplete_elements = self.selenium.find_elements_by_xpath(
'//*[@id="id_widgetsa_set-1-widgetsb_set-0-fk2-autocomplete"]'
autocomplete_elements = self.selenium.find_elements(
By.XPATH, '//*[@id="id_widgetsa_set-1-widgetsb_set-0-fk2-autocomplete"]'
)
self.assertNotEqual(
len(autocomplete_elements), 0, "Zero autocomplete fields initialized"
Expand Down Expand Up @@ -405,7 +405,7 @@ def test_nested_autocomplete_extra(self):
self.add_inline([0, [0]])
self.add_inline([0, 1, [0]])
select_field = self.get_field("fk3", indexes=[0, 1, [0, 0]])
select_parent = select_field.find_element_by_xpath("parent::*")
select_parent = select_field.find_element(By.XPATH, "parent::*")
select_parent.click()
select2_is_active = self.selenium.execute_script(
'return $(".select2-search__field").length > 0'
Expand Down
26 changes: 21 additions & 5 deletions nested_admin/tests/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from django.contrib.admin.sites import site as admin_site

from selenosis import AdminSelenosisTestCase
from selenium.webdriver.common.by import By
from selenium.webdriver.common.actions.pointer_input import PointerInput
from .drag_drop import DragAndDropAction
from .utils import xpath_item, is_sequence, is_integer, is_str, ElementRect

Expand All @@ -34,6 +36,20 @@ class BaseNestedAdminTestCase(AdminSelenosisTestCase):
def setUpClass(cls):
super().setUpClass()

# Increase speed of move_to_element action
PointerInput.DEFAULT_MOVE_DURATION = 1

if not hasattr(PointerInput.create_pointer_move, "_patched"):
orig_create_pointer_move = PointerInput.create_pointer_move

def create_pointer_move(self, *args, **kwargs):
kwargs["duration"] = 1
return orig_create_pointer_move(self, *args, **kwargs)

create_pointer_move._patched = True

PointerInput.create_pointer_move = create_pointer_move

root_admin = admin_site._registry[cls.root_model]

def descend_admin_inlines(admin):
Expand Down Expand Up @@ -180,7 +196,7 @@ def save_form(self):
)
)
name_attr = "_continue" if has_continue else "_save"
self.click(self.selenium.find_element_by_xpath('//*[@name="%s"]' % name_attr))
self.click(self.selenium.find_element(By.XPATH, '//*[@name="%s"]' % name_attr))
if has_continue:
self.wait_page_loaded()
self.initialize_page()
Expand Down Expand Up @@ -362,15 +378,15 @@ def get_group(self, indexes=None):
]
expr_parts += ["/*[@data-inline-model='%s']" % model_name]
expr = "/%s" % ("/".join(expr_parts))
return self.selenium.find_element_by_xpath(expr)
return self.selenium.find_element(By.XPATH, expr)

def get_item(self, indexes):
indexes = self._normalize_indexes(indexes)
model_name, item_index = indexes.pop()
indexes.append(model_name)
group = self.get_group(indexes=indexes)
return group.find_element_by_xpath(
".//*[%s][%d]" % (xpath_item(model_name), item_index + 1)
return group.find_element(
By.XPATH, ".//*[%s][%d]" % (xpath_item(model_name), item_index + 1)
)

def add_inline(self, indexes=None, name=None, slug=None):
Expand Down Expand Up @@ -442,7 +458,7 @@ def get_form_field_selector(self, attname, indexes=None):
def get_field(self, attname, indexes=None):
indexes = self._normalize_indexes(indexes)
field_selector = self.get_form_field_selector(attname, indexes=indexes)
return self.selenium.find_element_by_css_selector(field_selector)
return self.selenium.find_element(By.CSS_SELECTOR, field_selector)

def set_field(self, attname, value, indexes=None):
indexes = self._normalize_indexes(indexes)
Expand Down
33 changes: 19 additions & 14 deletions nested_admin/tests/drag_drop.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import time

from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By

from .utils import xpath_cls, xpath_item, is_integer, Position, Size, ElementRect

Expand Down Expand Up @@ -107,7 +108,7 @@ def source(self):
"*[%s]" % xpath_cls("djn-drag-handler"),
]
)
self._source = source_item.find_element_by_xpath(drag_handler_xpath)
self._source = source_item.find_element(By.XPATH, drag_handler_xpath)
return self._source

@property
Expand All @@ -127,7 +128,7 @@ def target(self):
"item_pred": xpath_item(),
"item_pos": self.to_indexes[-1][1] + 1,
}
self._target = target_inline_parent.find_element_by_xpath(target_xpath)
self._target = target_inline_parent.find_element(By.XPATH, target_xpath)
return self._target

def initialize_drag(self):
Expand All @@ -140,6 +141,10 @@ def initialize_drag(self):
document.documentElement.scrollTop += (top - 16);
} else {
el.scrollIntoView();
top = el.getBoundingClientRect().top;
if (top <= 15) {
document.documentElement.scrollTop += (top - 16);
}
}
""",
source,
Expand All @@ -148,15 +153,15 @@ def initialize_drag(self):

(
ActionChains(self.selenium)
.move_to_element_with_offset(source, 5, 5)
.move_to_element_with_offset(source, 3, 3)
.click_and_hold()
.perform()
)

time.sleep(0.05)
ActionChains(self.selenium).move_by_offset(0, -15).perform()
ActionChains(self.selenium).move_by_offset(0, -10).perform()
time.sleep(0.05)
ActionChains(self.selenium).move_by_offset(0, 15).perform()
ActionChains(self.selenium).move_by_offset(0, 10).perform()

with self.test_case.visible_selector(".ui-sortable-helper") as el:
return el
Expand Down Expand Up @@ -189,7 +194,7 @@ def _match_helper_with_target(self, helper_element, target_element):
15, min(viewport_height // 3, (2 * inline_height) // 3, abs(dy) // 2)
)

max_iter = 50
max_iter = 120
i = 0
prev_pos_diff = None
direction = None
Expand Down Expand Up @@ -220,9 +225,9 @@ def _match_helper_with_target(self, helper_element, target_element):
if flip_count > 3:
increment = 10
elif flip_count > 5:
increment = 5
increment = 2
else:
increment = max(abs(dy // 2), flip_count * flip_multiplier)
increment = min(abs(dy // 2), flip_count * flip_multiplier)
direction_flip *= -1
direction = pos_diff * direction_flip
inc = increment * direction
Expand Down Expand Up @@ -252,7 +257,7 @@ def _num_preceding_siblings(self, ctx, condition):
is extraordinarily slow. So we just grab all siblings and iterate
through the elements in python.
"""
siblings = ctx.find_element_by_xpath("parent::*").find_elements_by_xpath("*")
siblings = ctx.find_element(By.XPATH, "parent::*").find_elements(By.XPATH, "*")
count = 0
for el in siblings:
if el.id == ctx.id:
Expand All @@ -278,8 +283,8 @@ def is_djn_group(el):

@property
def current_position(self):
placeholder = self.selenium.find_element_by_css_selector(
".ui-sortable-placeholder"
placeholder = self.selenium.find_element(
By.CSS_SELECTOR, ".ui-sortable-placeholder"
)
pos = []
ctx = None
Expand All @@ -288,10 +293,10 @@ def current_position(self):
if ctx is None:
ctx = placeholder
else:
ctx = ctx.find_element_by_xpath(ancestor_xpath)
ctx = ctx.find_element(By.XPATH, ancestor_xpath)
item_index = self._num_preceding_djn_items(ctx)
ctx = ctx.find_element_by_xpath(
"ancestor::*[%s][1]" % xpath_cls("djn-group")
ctx = ctx.find_element(
By.XPATH, "ancestor::*[%s][1]" % xpath_cls("djn-group")
)
inline_index = self._num_preceding_djn_groups(ctx)
pos.insert(0, (inline_index, item_index))
Expand Down
Loading

0 comments on commit 623c5ba

Please sign in to comment.