diff --git a/s3file/static/s3file/js/s3file.js b/s3file/static/s3file/js/s3file.js index e4c573d..ad88901 100644 --- a/s3file/static/s3file/js/s3file.js +++ b/s3file/static/s3file/js/s3file.js @@ -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') @@ -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) diff --git a/tests/test_forms.py b/tests/test_forms.py index e16ca82..9f4ee39 100644 --- a/tests/test_forms.py +++ b/tests/test_forms.py @@ -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 @@ -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", @@ -46,12 +41,12 @@ 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, ) @@ -59,18 +54,18 @@ def test_file_does_not_exist_no_fallback(self, filemodel): 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"] @@ -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]") @@ -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" @@ -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" @@ -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" @@ -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" @@ -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" @@ -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( diff --git a/tests/testapp/forms.py b/tests/testapp/forms.py index bd7f2cb..84bc9d4 100644 --- a/tests/testapp/forms.py +++ b/tests/testapp/forms.py @@ -1,4 +1,5 @@ from django import forms +from django.contrib.admin.widgets import AdminFileWidget from s3file.forms import S3FileInputMixin @@ -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): diff --git a/tests/testapp/settings.py b/tests/testapp/settings.py index 345369f..869f009 100644 --- a/tests/testapp/settings.py +++ b/tests/testapp/settings.py @@ -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", @@ -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", + ], + }, }, ] diff --git a/tests/testapp/urls.py b/tests/testapp/urls.py index f9da4df..9f54c24 100644 --- a/tests/testapp/urls.py +++ b/tests/testapp/urls.py @@ -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( + "/update", + views.ExampleUpdateView.as_view(), + name="example-update", + ), + ] + ), + ), path("multi/", views.MultiExampleFormView.as_view(), name="upload-multi"), ] diff --git a/tests/testapp/views.py b/tests/testapp/views.py index af2f257..85e8f54 100644 --- a/tests/testapp/views.py +++ b/tests/testapp/views.py @@ -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): @@ -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):