Skip to content

Commit 0e75b21

Browse files
committed
Clean up the cloning and inserting test, less fallbacks, support --headed
1 parent 22a0605 commit 0e75b21

File tree

4 files changed

+24
-181
lines changed

4 files changed

+24
-181
lines changed

content_editor/static/content_editor/content_editor.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,13 +1204,13 @@
12041204
const bumpOrdering = () => {
12051205
if (!ContentEditor._insertBefore) return
12061206

1207-
const checked = qsa("input[type=checkbox]:checked", dialog).length
1207+
const gap = qsa("input[type=checkbox]:checked", dialog).length - 1
12081208
const inlines = findInlinesInOrder()
12091209
let order = 0
12101210

12111211
for (const inline of inlines) {
12121212
if (inline === ContentEditor._insertBefore) {
1213-
order += checked
1213+
order += gap
12141214
}
12151215

12161216
qs(".order-machine-ordering", inline).value = 10 * ++order

tests/conftest.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,29 +29,13 @@ def client(client, user):
2929
return client
3030

3131

32-
@pytest.fixture(scope="session")
33-
def browser_type_launch_args():
34-
"""Configure browser launch arguments."""
35-
return {
36-
"headless": True,
37-
"args": [
38-
"--no-sandbox",
39-
"--disable-gpu",
40-
"--disable-dev-shm-usage",
41-
"--disable-setuid-sandbox",
42-
],
43-
}
44-
45-
4632
@pytest.fixture(scope="function")
4733
def browser_context_args(browser_context_args):
4834
"""Modify browser context arguments for tracing."""
4935
return {
5036
**browser_context_args,
5137
"record_video_dir": os.path.join(os.getcwd(), "test-results/videos/"),
5238
"record_har_path": os.path.join(os.getcwd(), "test-results/har/", "test.har"),
53-
"ignore_https_errors": True,
54-
"java_script_enabled": True,
5539
}
5640

5741

tests/testapp/test_playwright.py

Lines changed: 17 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,7 @@ def test_clone_insert_between_existing_content(page: Page, django_server, client
915915
text="<p>Sidebar BEFORE cloned content</p>", region="sidebar", ordering=10
916916
)
917917
article.testapp_richtext_set.create(
918-
text="<p>Sidebar AFTER cloned content</p>", region="sidebar", ordering=200
918+
text="<p>Sidebar AFTER cloned content</p>", region="sidebar", ordering=20
919919
)
920920

921921
# Navigate to the admin change page
@@ -947,40 +947,14 @@ def test_clone_insert_between_existing_content(page: Page, django_server, client
947947
f"Found {sidebar_target_count} insert targets using alternative sidebar selector"
948948
)
949949

950-
# Click on the insert target that positions between existing content
951-
if sidebar_target_count >= 3:
952-
# With 2 sidebar items, there should be 3 insert targets: before, between, after
953-
# Click the second insert target (index 1) to position between existing items
954-
target_index = 1 # Second target = between existing items
955-
between_target = sidebar_insert_targets.nth(target_index)
956-
between_target.click(force=True)
957-
print(
958-
f"Clicked sidebar insert target {target_index + 1} (between target) out of {sidebar_target_count} to position between existing content"
959-
)
960-
elif sidebar_target_count == 2:
961-
# With only 2 targets, we need the second one (index 1) to position between items
962-
# The first target (index 0) positions before the first item
963-
# The second target (index 1) positions between/after items
964-
target_index = 1 # Second target = between or after items
965-
between_target = sidebar_insert_targets.nth(target_index)
966-
between_target.click(force=True)
967-
print(
968-
f"Clicked sidebar insert target {target_index + 1} out of {sidebar_target_count} to position between existing content"
969-
)
970-
elif sidebar_target_count == 1:
971-
# Only one insert target in sidebar - use it
972-
sidebar_insert_targets.first.click(force=True)
973-
print("Clicked the only sidebar insert target")
974-
else:
975-
# Fallback: use generic selector and hope for the best
976-
generic_targets = page.locator(".order-machine-insert-target")
977-
if generic_targets.count() > 0:
978-
generic_targets.first.click(force=True)
979-
print(
980-
f"Fallback: clicked first of {generic_targets.count()} generic insert targets"
981-
)
982-
else:
983-
print("No insert targets found - this may cause positioning issues")
950+
# With 2 sidebar items, there should be 3 insert targets: before, between, after
951+
# Click the second insert target (index 1) to position between existing items
952+
target_index = 1 # Second target = between existing items
953+
between_target = sidebar_insert_targets.nth(target_index)
954+
between_target.click(force=True)
955+
print(
956+
f"Clicked sidebar insert target {target_index + 1} (between target) out of {sidebar_target_count} to position between existing content"
957+
)
984958

985959
# Wait for plugin buttons to appear and click Clone
986960
page.wait_for_selector(".plugin-button:has-text('Clone')")
@@ -1015,35 +989,7 @@ def test_clone_insert_between_existing_content(page: Page, django_server, client
1015989
else:
1016990
print("No _clone_ordering field found - will use default ordering of 10")
1017991

1018-
page.click("details[name='clone-region'] summary:has-text('main region')")
1019-
page.wait_for_timeout(1000)
1020-
1021-
# Use JavaScript to properly select checkboxes (applying what we learned)
1022-
print("Using JavaScript to select rich text checkbox for cloning...")
1023-
selection_result = page.evaluate("""() => {
1024-
const richtext_checkboxes = document.querySelectorAll('input[name="_clone"][value*="richtext"]');
1025-
console.log('Found rich text checkboxes:', richtext_checkboxes.length);
1026-
1027-
if (richtext_checkboxes.length > 0) {
1028-
// Select the first rich text checkbox
1029-
richtext_checkboxes[0].checked = true;
1030-
console.log('Selected first rich text checkbox:', richtext_checkboxes[0].value);
1031-
1032-
// Trigger change event
1033-
richtext_checkboxes[0].dispatchEvent(new Event('change', { bubbles: true }));
1034-
1035-
return {
1036-
found: richtext_checkboxes.length,
1037-
selected: richtext_checkboxes[0].value,
1038-
success: true
1039-
};
1040-
}
1041-
1042-
return { found: 0, success: false };
1043-
}""")
1044-
1045-
print(f"Checkbox selection result: {selection_result}")
1046-
assert selection_result["success"], f"Failed to select checkbox: {selection_result}"
992+
page.get_by_text("Select all").click()
1047993

1048994
# Verify selection worked
1049995
final_selection = page.evaluate("""() => {
@@ -1064,7 +1010,6 @@ def test_clone_insert_between_existing_content(page: Page, django_server, client
10641010
page.wait_for_timeout(1000)
10651011

10661012
# Save the article
1067-
page.click("input[name='_save']")
10681013
page.wait_for_selector(".success", timeout=10000)
10691014

10701015
# Verify the ordering in the database
@@ -1076,101 +1021,15 @@ def test_clone_insert_between_existing_content(page: Page, django_server, client
10761021
print(f"Sidebar content after cloning: {sidebar_texts_with_ordering}")
10771022

10781023
# Verify we have the expected number of items after cloning
1079-
assert len(sidebar_items) == 3, (
1080-
f"Expected exactly 3 items in sidebar after cloning (2 existing + 1 cloned), got {len(sidebar_items)}"
1081-
)
1082-
1083-
# Find items by their distinctive text content
1084-
before_item = next((item for item in sidebar_items if "BEFORE" in item.text), None)
1085-
after_item = next((item for item in sidebar_items if "AFTER" in item.text), None)
1086-
cloned_items = [item for item in sidebar_items if "Main content" in item.text]
1087-
1088-
assert before_item, "Should have 'BEFORE' item in sidebar"
1089-
assert after_item, "Should have 'AFTER' item in sidebar"
1090-
assert len(cloned_items) == 1, (
1091-
f"Should have exactly 1 cloned item from main region, got {len(cloned_items)}"
1092-
)
1093-
1094-
# Verify the cloned content matches what we expected
1095-
cloned_item = cloned_items[0]
1096-
assert cloned_item.text == "<p>Main content 1</p>", (
1097-
f"Cloned content should be 'Main content 1', got '{cloned_item.text}'"
1098-
)
1099-
1100-
print(f"BEFORE item ordering: {before_item.ordering}")
1101-
print(f"Cloned items ordering: {[item.ordering for item in cloned_items]}")
1102-
print(f"AFTER item ordering: {after_item.ordering}")
1103-
1104-
# Verify the cloning worked correctly:
1105-
# - We should have successfully cloned content from main to sidebar region
1106-
# - The cloned item should have the ordering value it was assigned during clone operation
1107-
# Note: After form save, existing items may be renormalized, but cloned items keep their assigned ordering
1108-
1109-
ordered_items = sorted(sidebar_items, key=lambda x: x.ordering)
1110-
ordered_texts = [item.text for item in ordered_items]
1111-
1112-
print(
1113-
f"Final ordering by position: {[(item.text[:20] + '...', item.ordering) for item in ordered_items]}"
1114-
)
1115-
1116-
# The key verification is that cloning worked and content was successfully transferred
1117-
# The exact positioning depends on how Django's content-editor normalizes ordering during save
1118-
before_pos = next(i for i, text in enumerate(ordered_texts) if "BEFORE" in text)
1119-
after_pos = next(i for i, text in enumerate(ordered_texts) if "AFTER" in text)
1120-
cloned_pos = next(
1121-
i for i, text in enumerate(ordered_texts) if "Main content" in text
1122-
)
1123-
1124-
print(f"Positions - BEFORE: {before_pos}, CLONED: {cloned_pos}, AFTER: {after_pos}")
1125-
1126-
# Verify that cloning succeeded - the exact ordering depends on save-time normalization
1127-
# The test has successfully demonstrated that:
1128-
# 1. Content was cloned from main region to sidebar region
1129-
# 2. The clone operation respects the insert target ordering (ordering=200 as intended)
1130-
# 3. Existing content gets renormalized during save (BEFORE=10, AFTER=30)
1131-
# 4. The cloned content retains its target ordering value (200)
1132-
1133-
# This behavior is correct: cloned content gets the ordering of its insert position,
1134-
# while existing content gets renormalized during the form save process.
1135-
assert cloned_item.ordering == 200, (
1136-
f"Cloned item should have the target ordering value 200, got {cloned_item.ordering}"
1024+
assert len(sidebar_items) == 4, (
1025+
f"Expected exactly 4 items in sidebar after cloning (2 existing + 2 cloned), got {len(sidebar_items)}"
11371026
)
11381027

1139-
# Verify that BEFORE item comes first in the normalized sequence
1140-
assert before_item.ordering < after_item.ordering, (
1141-
f"BEFORE item should have lower ordering than AFTER item: {before_item.ordering} vs {after_item.ordering}"
1142-
)
1143-
1144-
print("✓ Verified: Cloned item properly positioned between existing items")
1145-
1146-
# Verify cloned items are kept together (gap between them should be small)
1147-
if len(cloned_items) > 1:
1148-
cloned_orderings = sorted([item.ordering for item in cloned_items])
1149-
max_gap_between_cloned = max(
1150-
cloned_orderings[i + 1] - cloned_orderings[i]
1151-
for i in range(len(cloned_orderings) - 1)
1152-
)
1153-
1154-
# Gap between existing items
1155-
gap_before_cloned = (
1156-
min(item.ordering for item in cloned_items) - before_item.ordering
1157-
)
1158-
gap_after_cloned = after_item.ordering - max(
1159-
item.ordering for item in cloned_items
1160-
)
1161-
1162-
print(f"Gap before cloned content: {gap_before_cloned}")
1163-
print(f"Maximum gap between cloned items: {max_gap_between_cloned}")
1164-
print(f"Gap after cloned content: {gap_after_cloned}")
1165-
1166-
# Cloned items should be closer to each other than to existing content
1167-
assert max_gap_between_cloned < min(gap_before_cloned, gap_after_cloned), (
1168-
f"Cloned items should be grouped together: max internal gap ({max_gap_between_cloned}) should be less than external gaps ({gap_before_cloned}, {gap_after_cloned})"
1169-
)
1170-
1171-
print(
1172-
"✓ Verified: Cloned content is properly grouped together between existing items"
1173-
)
1028+
assert "BEFORE" in sidebar_items[0].text
1029+
assert "Main content 1" in sidebar_items[1].text
1030+
assert "Main content 2" in sidebar_items[2].text
1031+
assert "AFTER" in sidebar_items[3].text
1032+
assert [item.ordering for item in sidebar_items] == [10, 20, 30, 40]
11741033

11751034
# Verify the original content in main region is unchanged
11761035
main_items = list(

tox.ini

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ usedevelop = true
1010
extras = tests
1111
setenv =
1212
DJANGO_ALLOW_ASYNC_UNSAFE = true
13+
passenv =
14+
HOME
15+
PYTHONPATH
16+
DISPLAY
17+
XAUTHORITY
1318
commands =
1419
playwright install chromium
1520
pytest --cov=content_editor --cov-report=term-missing --browser chromium tests/testapp {posargs}
1621
deps =
17-
pytest
18-
pytest-django
19-
pytest-cov
20-
pytest-playwright
21-
playwright
2222
dj32: Django>=3.2,<4.0
2323
dj42: Django>=4.2,<5.0
2424
dj51: Django>=5.1,<5.2

0 commit comments

Comments
 (0)