Skip to content

Commit

Permalink
Fix #286 -- Narrow CSS selector to avoid mismatches
Browse files Browse the repository at this point in the history
  • Loading branch information
codingjoe committed Mar 5, 2024
1 parent bdb771a commit 06070a8
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 31 deletions.
4 changes: 2 additions & 2 deletions s3file/static/s3file/js/s3file.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
window.uploading = 0
form.loaded = 0
form.total = 0
var inputs = Array.from(form.querySelectorAll('.s3file'))
var inputs = Array.from(form.querySelectorAll('input[type=file].s3file'))

inputs.forEach(function (input) {
var hiddenS3Input = document.createElement('input')
Expand All @@ -140,7 +140,7 @@
}

document.addEventListener('DOMContentLoaded', function () {
var forms = Array.from(document.querySelectorAll('.s3file')).map(function (input) {
var forms = Array.from(document.querySelectorAll('input[type=file].s3file')).map(function (input) {
return input.closest('form')
})
forms = new Set(forms)
Expand Down
62 changes: 39 additions & 23 deletions tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,17 @@
from contextlib import contextmanager

import pytest
from django.core.files.uploadedfile import SimpleUploadedFile
from django.forms import ClearableFileInput
from django.urls import reverse_lazy
from selenium.common.exceptions import NoSuchElementException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.expected_conditions import staleness_of
from selenium.webdriver.support.wait import WebDriverWait

from s3file.storages import storage
from tests.testapp.forms import UploadForm

try:
from django.urls import reverse
except ImportError:
# Django 1.8 support
from django.core.urlresolvers import reverse
from tests.testapp.forms import FileForm
from tests.testapp.models import FileModel


@contextmanager
Expand All @@ -27,15 +24,13 @@ def wait_for_page_load(driver, timeout=30):


class TestS3FileInput:
@property
def url(self):
return reverse("upload")
create_url = reverse_lazy("example-create")

def test_value_from_datadict(self, freeze_upload_folder, client, upload_file):
with open(upload_file) as f:
uploaded_file = storage.save(freeze_upload_folder / "test.jpg", f)
response = client.post(
reverse("upload"),
self.create_url,
{
"file": f"custom/location/{uploaded_file}",
"file-s3f-signature": "FxQXie3wnVnCUFqGzFZ8DCFKAXFA3bnQ8tE96U11o80",
Expand All @@ -46,31 +41,31 @@ def test_value_from_datadict(self, freeze_upload_folder, client, upload_file):
assert response.status_code == 201

def test_value_from_datadict_initial_data(self, filemodel):
form = UploadForm(instance=filemodel)
form = FileForm(instance=filemodel)
assert filemodel.file.name in form.as_p(), form.as_p()
assert not form.is_valid()

def test_file_does_not_exist_no_fallback(self, filemodel):
form = UploadForm(
form = FileForm(
data={"file": "foo.bar", "s3file": "file"},
instance=filemodel,
)
assert form.is_valid()
assert form.cleaned_data["file"] == filemodel.file

def test_initial_no_file_uploaded(self, filemodel):
form = UploadForm(data={"file": ""}, instance=filemodel)
form = FileForm(data={"file": ""}, instance=filemodel)
assert form.is_valid(), form.errors
assert not form.has_changed()
assert form.cleaned_data["file"] == filemodel.file

def test_initial_fallback(self, filemodel):
form = UploadForm(data={"file": ""}, instance=filemodel)
form = FileForm(data={"file": ""}, instance=filemodel)
assert form.is_valid()
assert form.cleaned_data["file"] == filemodel.file

def test_clear(self, filemodel):
form = UploadForm(data={"file-clear": "1"}, instance=filemodel)
form = FileForm(data={"file-clear": "1"}, instance=filemodel)
assert form.is_valid()
assert not form.cleaned_data["file"]

Expand Down Expand Up @@ -137,7 +132,7 @@ def test_accept(self):

@pytest.mark.selenium
def test_no_js_error(self, driver, live_server):
driver.get(live_server + self.url)
driver.get(live_server + self.create_url)

with pytest.raises(NoSuchElementException):
error = driver.find_element(By.XPATH, "//body[@JSError]")
Expand All @@ -147,7 +142,28 @@ def test_no_js_error(self, driver, live_server):
def test_file_insert(
self, request, driver, live_server, upload_file, freeze_upload_folder
):
driver.get(live_server + self.url)
driver.get(live_server + self.create_url)
file_input = driver.find_element(By.XPATH, "//input[@name='file']")
file_input.send_keys(upload_file)
assert file_input.get_attribute("name") == "file"
with wait_for_page_load(driver, timeout=10):
file_input.submit()
assert storage.exists("tmp/s3file/%s.txt" % request.node.name)

with pytest.raises(NoSuchElementException):
error = driver.find_element(By.XPATH, "//body[@JSError]")
pytest.fail(error.get_attribute("JSError"))

@pytest.mark.selenium
def test_file_update(
self, request, driver, live_server, upload_file, freeze_upload_folder
):
FileModel.objects.create(
file=SimpleUploadedFile(
f"{request.node.name}.txt", request.node.name.encode()
)
)
driver.get(live_server + reverse_lazy("example-update", kwargs={"pk": 1}))
file_input = driver.find_element(By.XPATH, "//input[@name='file']")
file_input.send_keys(upload_file)
assert file_input.get_attribute("name") == "file"
Expand All @@ -163,7 +179,7 @@ def test_file_insert(
def test_file_insert_submit_value(
self, driver, live_server, upload_file, freeze_upload_folder
):
driver.get(live_server + self.url)
driver.get(live_server + self.create_url)
file_input = driver.find_element(By.XPATH, "//input[@name='file']")
file_input.send_keys(upload_file)
assert file_input.get_attribute("name") == "file"
Expand All @@ -172,7 +188,7 @@ def test_file_insert_submit_value(
save_button.click()
assert "save" in driver.page_source

driver.get(live_server + self.url)
driver.get(live_server + self.create_url)
file_input = driver.find_element(By.XPATH, "//input[@name='file']")
file_input.send_keys(upload_file)
assert file_input.get_attribute("name") == "file"
Expand All @@ -184,7 +200,7 @@ def test_file_insert_submit_value(

@pytest.mark.selenium
def test_progress(self, driver, live_server, upload_file, freeze_upload_folder):
driver.get(live_server + self.url)
driver.get(live_server + self.create_url)
file_input = driver.find_element(By.XPATH, "//input[@name='file']")
file_input.send_keys(upload_file)
assert file_input.get_attribute("name") == "file"
Expand All @@ -193,7 +209,7 @@ def test_progress(self, driver, live_server, upload_file, freeze_upload_folder):
save_button.click()
assert "save" in driver.page_source

driver.get(live_server + self.url)
driver.get(live_server + self.create_url)
file_input = driver.find_element(By.XPATH, "//input[@name='file']")
file_input.send_keys(upload_file)
assert file_input.get_attribute("name") == "file"
Expand All @@ -213,7 +229,7 @@ def test_multi_file(
another_upload_file,
yet_another_upload_file,
):
driver.get(live_server + reverse("upload-multi"))
driver.get(live_server + reverse_lazy("upload-multi"))
file_input = driver.find_element(By.XPATH, "//input[@name='file']")
file_input.send_keys(
" \n ".join(
Expand Down
6 changes: 5 additions & 1 deletion tests/testapp/forms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django import forms
from django.contrib.admin.widgets import AdminFileWidget

from s3file.forms import S3FileInputMixin

Expand All @@ -10,10 +11,13 @@
) + forms.ClearableFileInput.__bases__


class UploadForm(forms.ModelForm):
class FileForm(forms.ModelForm):
class Meta:
model = FileModel
fields = ("file", "other_file")
widgets = {
"file": AdminFileWidget,
}


class MultipleFileInput(forms.ClearableFileInput):
Expand Down
8 changes: 8 additions & 0 deletions tests/testapp/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.admin",
"storages",
"s3file",
"tests.testapp",
Expand All @@ -41,6 +43,12 @@
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]

Expand Down
18 changes: 16 additions & 2 deletions tests/testapp/urls.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
try:
from django.urls import path
from django.urls import include, path
except ImportError:
from django.conf.urls import url as path

from . import views

urlpatterns = [
path("", views.ExampleFormView.as_view(), name="upload"),
path(
"example/",
include(
[
path(
"create", views.ExampleCreateView.as_view(), name="example-create"
),
path(
"<int:pk>/update",
views.ExampleUpdateView.as_view(),
name="example-update",
),
]
),
),
path("multi/", views.MultiExampleFormView.as_view(), name="upload-multi"),
]
26 changes: 23 additions & 3 deletions tests/testapp/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.http import JsonResponse
from django.views import generic

from tests.testapp import forms
from . import forms, models


class FileEncoder(DjangoJSONEncoder):
Expand All @@ -13,8 +13,28 @@ def default(self, o):
return super().default(o)


class ExampleFormView(generic.FormView):
form_class = forms.UploadForm
class ExampleCreateView(generic.CreateView):
model = models.FileModel
fields = ["file", "other_file"]
template_name = "form.html"

def form_valid(self, form):
return JsonResponse(
{
"POST": self.request.POST,
"FILES": {
"file": self.request.FILES.getlist("file"),
"other_file": self.request.FILES.getlist("other_file"),
},
},
status=201,
encoder=FileEncoder,
)


class ExampleUpdateView(generic.UpdateView):
model = models.FileModel
form_class = forms.FileForm
template_name = "form.html"

def form_valid(self, form):
Expand Down

0 comments on commit 06070a8

Please sign in to comment.