Skip to content

Commit

Permalink
revert regression introduced in 73d672a
Browse files Browse the repository at this point in the history
  • Loading branch information
jrief committed Apr 12, 2024
1 parent 949c8ab commit 777ffcc
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 29 deletions.
8 changes: 4 additions & 4 deletions client/django-formset/DjangoFormset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -493,10 +493,10 @@ class DjangoButton {
element.addEventListener('click', this.clicked);
}

private evalVisibility(attribute: string, visible: boolean): Function {
private evalVisibility(attribute: string, visible: boolean): Function|null {
const attrValue = this.element.getAttribute(attribute);
if (attrValue === null)
return () => {};
return null;
try {
const evalExpression = new Function(`return ${parse(attrValue, {startRule: 'OperabilityExpression'})}`);
return () => {
Expand Down Expand Up @@ -911,10 +911,10 @@ class DjangoFieldset {
this.updateDisabled = this.evalDisable();
}

private evalVisibility(attribute: string, visible: boolean): Function {
private evalVisibility(attribute: string, visible: boolean): Function|null {
const attrValue = this.element.getAttribute(attribute);
if (attrValue === null)
return () => {};
return null;
try {
const evalExpression = new Function(`return ${parse(attrValue, {startRule: 'OperabilityExpression'})}`);
return () => {
Expand Down
35 changes: 21 additions & 14 deletions testapp/tests/test_e2e_button.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import json
import pytest
import re
from playwright.sync_api import expect
from time import sleep
from timeit import default_timer as timer
Expand Down Expand Up @@ -64,10 +65,10 @@ def post(self, request, **kwargs):
@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['test_button_0'])
def test_button_disable(page, viewname):
button = page.locator('django-formset button').first
button = page.locator('django-formset button:not([df-click="reset"])')
expect(button).not_to_be_disabled()
button.click()
sleep(0.02)
sleep(0.02) # button remains disabled for 100ms
expect(button).to_be_disabled()
sleep(0.1)
# as a final action, <button> restores its state
Expand All @@ -77,11 +78,14 @@ def test_button_disable(page, viewname):
@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['test_button_1'])
def test_button_add_class(page, viewname):
button = page.locator('django-formset button').first
"""
addClass("foo") -> delay(100)
"""
button = page.locator('django-formset button:not([df-click="reset"])')
expect(button).to_have_class('button')
button.click()
sleep(0.02)
expect(button).to_have_class('button foo')
expect(button).to_have_class(re.compile(r'foo'))
sleep(0.1)
# as a final action, <button> restores its state
expect(button).to_have_class('button')
Expand All @@ -90,7 +94,10 @@ def test_button_add_class(page, viewname):
@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['test_button_2'])
def test_button_remove_class(page, viewname):
button = page.locator('django-formset button').first
"""
removeClass("button") -> delay(100)
"""
button = page.locator('django-formset button:not([df-click="reset"])')
expect(button).to_have_class('button')
button.click()
sleep(0.02)
Expand All @@ -100,29 +107,29 @@ def test_button_remove_class(page, viewname):
expect(button).to_have_class('button')


@pytest.mark.xfail(reason="playwright has some timing issues")
@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['test_button_3'])
def test_button_toggle_class(page, viewname):
"""
toggleClass("button") -> delay(100) -> toggleClass("foo") -> delay(100) -> toggleClass("bar") -> delay(100) -> toggleClass("foo") -> delay(100) -> toggleClass("bar")
"""
formset = page.locator('django-formset')
button = formset.locator('button[auto-disable]')
button = formset.locator('button:not([df-click="reset"])')
expect(button).to_be_visible()
expect(button).to_have_class('button')
start = timer()
button.click()
formset.locator('button[auto-disable]:not(.button)').wait_for()
formset.locator('button:not([df-click="reset"]):not(.button)').wait_for()
assert timer() - start < 0.1
formset.locator('button.foo').wait_for()
formset.locator('button:not([df-click="reset"]).foo').wait_for()
assert timer() - start > 0.1
formset.locator('button.foo.bar').wait_for()
formset.locator('button:not([df-click="reset"]).foo.bar').wait_for()
assert timer() - start > 0.2
sleep(0.01)
formset.locator('button.bar:not(.foo)').wait_for()
# sleep(0.01)
formset.locator('button:not([df-click="reset"]).bar:not(.foo)').wait_for()
assert timer() - start > 0.3
sleep(0.01)
formset.locator('button[auto-disable]:not(.foo):not(.bar)').wait_for()
# sleep(0.01)
formset.locator('button:not([df-click="reset"]):not(.foo):not(.bar)').wait_for()
assert timer() - start > 0.4
expect(button).to_have_class('button')

Expand Down
4 changes: 2 additions & 2 deletions testapp/tests/test_e2e_fieldset.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@ def test_submit_customer(page, mocker, viewname):
def test_submit_no_customer(page, mocker, viewname):
fieldset = page.locator('django-formset > django-form-collection fieldset')
expect(fieldset).to_have_attribute('df-hide', 'register.no_customer')
page.click('#id_register\\.no_customer')
page.locator('#id_register\\.no_customer').click()
expect(fieldset).to_be_hidden()
spy = mocker.spy(FormCollectionView, 'post')
page.click('django-formset button:first-of-type')
page.locator('django-formset button').first.click()
sleep(0.25)
spy.assert_called()
response = json.loads(spy.call_args.args[1].body)
Expand Down
99 changes: 99 additions & 0 deletions testapp/tests/test_e2e_operability.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import pytest
from playwright.sync_api import expect

from django.forms.forms import Form
from django.forms.fields import BooleanField, CharField, ChoiceField
from django.forms.widgets import CheckboxInput, TextInput, RadioSelect
from django.urls import path

from formset.views import FormView


class QuestionnaireForm(Form):
full_name = CharField(
widget=TextInput(attrs={'df-disable': ".gender=='x'"}),
)
gender = ChoiceField(
choices=[('m', "Male"), ('f', "Female"), ('x', "Inapplicable")],
widget=RadioSelect,
)
pregnant = BooleanField(
required=False,
widget=CheckboxInput(attrs={'df-show': ".gender=='f'"})
)


urlpatterns = [
path('questionnaire', FormView.as_view(
form_class=QuestionnaireForm,
template_name='testapp/native-form.html',
success_url='/success',
), name='questionnaire'),
path('questionnaire_initial_male', FormView.as_view(
form_class=QuestionnaireForm,
template_name='testapp/native-form.html',
initial={'full_name': "John Doe", 'gender': 'm'},
), name='questionnaire_initial_male'),
path('questionnaire_initial_female', FormView.as_view(
form_class=QuestionnaireForm,
template_name='testapp/native-form.html',
initial={'full_name': "Johanna Doe", 'gender': 'f'},
), name='questionnaire_initial_female'),
path('questionnaire_initial_inapplicable', FormView.as_view(
form_class=QuestionnaireForm,
template_name='testapp/native-form.html',
initial={'full_name': "Company Ltd.", 'gender': 'x'},
), name='questionnaire_initial_inapplicable'),
]


@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['questionnaire'])
def test_show_checkbox(page, viewname):
input_full_name = page.locator('#id_full_name')
radio_male = page.locator('#id_gender_0')
radio_female = page.locator('#id_gender_1')
radio_inapplicable = page.locator('#id_gender_2')
checkbox_pregnant = page.locator('#id_pregnant')
expect(input_full_name).to_be_visible()
expect(input_full_name).not_to_be_disabled()
expect(radio_male).to_be_visible()
expect(radio_female).to_be_visible()
expect(radio_inapplicable).to_be_visible()
expect(checkbox_pregnant).not_to_be_visible()
radio_female.click()
expect(checkbox_pregnant).to_be_visible()
radio_male.click()
expect(checkbox_pregnant).not_to_be_visible()
radio_inapplicable.click()
expect(input_full_name).to_be_disabled()


@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['questionnaire_initial_male'])
def test_show_checkbox_male(page, viewname):
radio_female = page.locator('#id_gender_1')
checkbox_pregnant = page.locator('#id_pregnant')
expect(checkbox_pregnant).not_to_be_visible()
radio_female.click()
expect(checkbox_pregnant).to_be_visible()


@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['questionnaire_initial_female'])
def test_show_checkbox_female(page, viewname):
radio_male = page.locator('#id_gender_0')
checkbox_pregnant = page.locator('#id_pregnant')
expect(checkbox_pregnant).to_be_visible()
radio_male.click()
expect(checkbox_pregnant).not_to_be_visible()


@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['questionnaire_initial_inapplicable'])
def test_show_checkbox_inapplicable(page, viewname):
input_full_name = page.locator('#id_full_name')
radio_male = page.locator('#id_gender_0')
expect(input_full_name).to_be_disabled()
radio_male.click()
expect(input_full_name).not_to_be_disabled()
16 changes: 8 additions & 8 deletions testapp/tests/test_e2e_richtextarea.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
controls.Blockquote(),
controls.HorizontalRule(),
controls.DialogControl(dialogs.SimpleLinkDialogForm()),
# controls.DialogControl(dialogs.FootnoteDialogForm()),
controls.DialogControl(dialogs.FootnoteDialogForm()),
controls.Separator(),
controls.Redo(),
controls.Undo(),
Expand Down Expand Up @@ -65,14 +65,14 @@ def richtext_wrapper(page):

@pytest.fixture
def menubar(richtext_wrapper):
menubar = richtext_wrapper.locator('[role="menubar"]')
menubar = richtext_wrapper.locator('[role="menubar"]').first
expect(menubar).to_be_visible()
return menubar


@pytest.fixture
def contenteditable(richtext_wrapper):
contenteditable = richtext_wrapper.locator('[contenteditable="true"]')
contenteditable = richtext_wrapper.locator('[contenteditable="true"]').last
expect(contenteditable).to_be_visible()
return contenteditable

Expand Down Expand Up @@ -152,13 +152,13 @@ def test_tiptap_blockquote(page, viewname, menubar, contenteditable):

@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['plain_richtext', 'json_richtext'])
def test_tiptap_valid_simple_link(page, viewname, menubar, contenteditable):
def test_tiptap_valid_simple_link(page, viewname, richtext_wrapper, menubar, contenteditable):
clickme = "Click here"
contenteditable.type(clickme)
assert contenteditable.inner_html() == f"<p>{clickme}</p>"
select_text(contenteditable.locator('p'), 6, 10)
menu_button = menubar.locator('button[name="dialog_simple_link"]')
dialog = page.locator('dialog[df-induce-open="dialog_simple_link:active"]')
dialog = richtext_wrapper.locator('dialog[df-induce-open="dialog_simple_link:active"]').first
expect(dialog).not_to_be_visible()
menu_button.click()
expect(dialog).to_be_visible()
Expand All @@ -182,13 +182,13 @@ def test_tiptap_valid_simple_link(page, viewname, menubar, contenteditable):

@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['plain_richtext', 'json_richtext'])
def test_tiptap_invalid_simple_link(page, viewname, menubar, contenteditable):
def test_tiptap_invalid_simple_link(page, viewname, richtext_wrapper, menubar, contenteditable):
clickme = "Click here"
contenteditable.type(clickme)
assert contenteditable.inner_html() == f"<p>{clickme}</p>"
select_text(contenteditable.locator('p'), 6, 10)
menu_button = menubar.locator('button[name="dialog_simple_link"]')
dialog = page.locator('dialog[df-induce-open="dialog_simple_link:active"]')
dialog = richtext_wrapper.locator('dialog[df-induce-open="dialog_simple_link:active"]').first
expect(dialog).not_to_be_visible()
menu_button.click()
expect(dialog).to_be_visible()
Expand All @@ -210,7 +210,7 @@ def test_tiptap_invalid_simple_link(page, viewname, menubar, contenteditable):
@pytest.mark.parametrize('viewname', ['plain_richtext_initialized'])
def test_tiptap_remove_simple_link(page, viewname, menubar, contenteditable):
assert contenteditable.inner_html() == '<p>Click <a href="https://example.org/">here</a></p>'
dialog = page.locator('dialog[df-induce-open="dialog_simple_link:active"]')
dialog = page.locator('dialog[df-induce-open="dialog_simple_link:active"]').first
expect(dialog).not_to_be_visible()
link_element = contenteditable.locator('p > a[href]')
expect(link_element).to_have_text("here")
Expand Down
2 changes: 1 addition & 1 deletion testapp/tests/test_e2e_upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def test_upload_in_progress(page, viewname):
error_placeholder = field_group.locator('.dj-errorlist .dj-placeholder')
expect(error_placeholder).to_have_text("File upload still in progress.")

@pytest.mark.xfail(reason="playwright does not abort route since version 1.31")
@pytest.mark.xfail(reason="Playwright does not abort route since version 1.31")
@pytest.mark.urls(__name__)
@pytest.mark.parametrize('viewname', ['upload'])
def test_interrupt_upload(page, viewname):
Expand Down

0 comments on commit 777ffcc

Please sign in to comment.