Browse Source

Add Upload to compatibility packages

Step 1 / 2 of adding a new Upload Component.

Change-Id: I137d7952a540db18a616da4a944a2a44f27435da
tags/8.0.0.alpha4
Pekka Hyvönen 7 years ago
parent
commit
8cdaeb241a

+ 39
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/ui/AbstractLegacyComponentConnector.java View File

@@ -0,0 +1,39 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.client.ui;

import com.vaadin.client.ui.AbstractComponentConnector;
import com.vaadin.client.ui.AbstractConnector;
import com.vaadin.shared.communication.ServerRpc;

/**
* Legacy connector for Vaadin 7 compatibility connectors. Needed because
* <code>immediate</code> has been removed from {@link AbstractConnector} in
* Vaadin 8.
*
* @author Vaadin Ltd
* @since 8.0
*/
public class AbstractLegacyComponentConnector
extends AbstractComponentConnector {

// overridden to be visible to VUpload in the same package. Without making
// it public in VUploadConnector
@Override
protected <T extends ServerRpc> T getRpcProxy(Class<T> rpcInterface) {
return super.getRpcProxy(rpcInterface);
}
}

+ 394
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/ui/VUpload.java View File

@@ -0,0 +1,394 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.vaadin.v7.client.ui;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.FormElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.Hidden;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ConnectorMap;
import com.vaadin.client.StyleConstants;
import com.vaadin.client.VConsole;
import com.vaadin.client.ui.VButton;
import com.vaadin.v7.client.ui.upload.UploadConnector;
import com.vaadin.v7.client.ui.upload.UploadIFrameOnloadStrategy;
import com.vaadin.v7.shared.ui.upload.UploadServerRpc;

/**
*
* Note, we are not using GWT FormPanel as we want to listen submitcomplete
* events even though the upload component is already detached.
*
*/
public class VUpload extends SimplePanel {

private final class MyFileUpload extends FileUpload {
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (event.getTypeInt() == Event.ONCHANGE) {
if (immediate && fu.getFilename() != null
&& !"".equals(fu.getFilename())) {
submit();
}
} else if (BrowserInfo.get().isIE()
&& event.getTypeInt() == Event.ONFOCUS) {
// IE and user has clicked on hidden textarea part of upload
// field. Manually open file selector, other browsers do it by
// default.
fireNativeClick(fu.getElement());
// also remove focus to enable hack if user presses cancel
// button
fireNativeBlur(fu.getElement());
}
}
}

public static final String CLASSNAME = "v-upload";

/**
* FileUpload component that opens native OS dialog to select file.
* <p>
* For internal use only. May be removed or replaced in the future.
*/
public FileUpload fu = new MyFileUpload();

Panel panel = new FlowPanel();

UploadIFrameOnloadStrategy onloadstrategy = GWT
.create(UploadIFrameOnloadStrategy.class);

/** For internal use only. May be removed or replaced in the future. */
public ApplicationConnection client;

/** For internal use only. May be removed or replaced in the future. */
public String paintableId;

/**
* Button that initiates uploading.
* <p>
* For internal use only. May be removed or replaced in the future.
*/
public final VButton submitButton;

/**
* When expecting big files, programmer may initiate some UI changes when
* uploading the file starts. Bit after submitting file we'll visit the
* server to check possible changes.
* <p>
* For internal use only. May be removed or replaced in the future.
*/
public Timer t;

/**
* some browsers tries to send form twice if submit is called in button
* click handler, some don't submit at all without it, so we need to track
* if form is already being submitted
*/
private boolean submitted = false;

private boolean enabled = true;

private boolean immediate;

private Hidden maxfilesize = new Hidden();

/** For internal use only. May be removed or replaced in the future. */
public FormElement element;

private com.google.gwt.dom.client.Element synthesizedFrame;

/** For internal use only. May be removed or replaced in the future. */
public int nextUploadId;

public VUpload() {
super(com.google.gwt.dom.client.Document.get().createFormElement());

element = getElement().cast();
setEncoding(getElement(), FormPanel.ENCODING_MULTIPART);
element.setMethod(FormPanel.METHOD_POST);

setWidget(panel);
panel.add(maxfilesize);
panel.add(fu);
submitButton = new VButton();
submitButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
if (immediate) {
// fire click on upload (eg. focused button and hit space)
fireNativeClick(fu.getElement());
} else {
submit();
}
}
});
panel.add(submitButton);

setStyleName(CLASSNAME);
}

private static native void setEncoding(Element form, String encoding)
/*-{
form.enctype = encoding;
}-*/;

/** For internal use only. May be removed or replaced in the future. */
public void setImmediate(boolean booleanAttribute) {
if (immediate != booleanAttribute) {
immediate = booleanAttribute;
if (immediate) {
fu.sinkEvents(Event.ONCHANGE);
fu.sinkEvents(Event.ONFOCUS);
}
}
setStyleName(getElement(), CLASSNAME + "-immediate", immediate);
}

private static native void fireNativeClick(Element element)
/*-{
element.click();
}-*/;

private static native void fireNativeBlur(Element element)
/*-{
element.blur();
}-*/;

/** For internal use only. May be removed or replaced in the future. */
public void disableUpload() {
setEnabledForSubmitButton(false);
if (!submitted) {
// Cannot disable the fileupload while submitting or the file won't
// be submitted at all
fu.getElement().setPropertyBoolean("disabled", true);
}
enabled = false;
}

/** For internal use only. May be removed or replaced in the future. */
public void enableUpload() {
setEnabledForSubmitButton(true);
fu.getElement().setPropertyBoolean("disabled", false);
enabled = true;
if (submitted) {
/*
* An old request is still in progress (most likely cancelled),
* ditching that target frame to make it possible to send a new
* file. A new target frame is created later."
*/
cleanTargetFrame();
submitted = false;
}
}

private void setEnabledForSubmitButton(boolean enabled) {
submitButton.setEnabled(enabled);
submitButton.setStyleName(StyleConstants.DISABLED, !enabled);
}

/**
* Re-creates file input field and populates panel. This is needed as we
* want to clear existing values from our current file input field.
*/
private void rebuildPanel() {
panel.remove(submitButton);
panel.remove(fu);
fu = new MyFileUpload();
fu.setName(paintableId + "_file");
fu.getElement().setPropertyBoolean("disabled", !enabled);
panel.add(fu);
panel.add(submitButton);
if (immediate) {
fu.sinkEvents(Event.ONCHANGE);
}
}

/**
* Called by JSNI (hooked via {@link #onloadstrategy})
*/
private void onSubmitComplete() {
/* Needs to be run dereferred to avoid various browser issues. */
Scheduler.get().scheduleDeferred(new Command() {
@Override
public void execute() {
if (submitted) {
if (client != null) {
if (t != null) {
t.cancel();
}
VConsole.log("VUpload:Submit complete");
((UploadConnector) ConnectorMap.get(client)
.getConnector(VUpload.this))
.getRpcProxy(UploadServerRpc.class)
.poll();
}

rebuildPanel();

submitted = false;
enableUpload();
if (!isAttached()) {
/*
* Upload is complete when upload is already abandoned.
*/
cleanTargetFrame();
}
}
}
});
}

ScheduledCommand startUploadCmd = new ScheduledCommand() {

@Override
public void execute() {
element.submit();
submitted = true;

disableUpload();

/*
* Visit server a moment after upload has started to see possible
* changes from UploadStarted event. Will be cleared on complete.
*
* Must get the id here as the upload can finish before the timer
* expires and in that case nextUploadId has been updated and is
* wrong.
*/
final int thisUploadId = nextUploadId;
t = new Timer() {
@Override
public void run() {
// Only visit the server if the upload has not already
// finished
if (thisUploadId == nextUploadId) {
VConsole.log(
"Visiting server to see if upload started event changed UI.");
client.updateVariable(paintableId, "pollForStart",
thisUploadId, true);
}
}
};
t.schedule(800);
}

};

/** For internal use only. May be removed or replaced in the future. */
public void submit() {
if (submitted || !enabled) {
VConsole.log("Submit cancelled (disabled or already submitted)");
return;
}
if (fu.getFilename().length() == 0) {
VConsole.log("Submitting empty selection (no file)");
}
// flush possibly pending variable changes, so they will be handled
// before upload
client.sendPendingVariableChanges();

// This is done as deferred because sendPendingVariableChanges is also
// deferred and we want to start the upload only after the changes have
// been sent to the server
Scheduler.get().scheduleDeferred(startUploadCmd);
}

/** For internal use only. May be removed or replaced in the future. */
public void disableTitle(boolean disable) {
if (disable) {
// Disable title attribute for upload element.
if (BrowserInfo.get().isChrome()) {
// In Chrome title has to be set to " " to make it invisible
fu.setTitle(" ");
} else if (BrowserInfo.get().isFirefox()) {
// In FF title has to be set to empty string to make it
// invisible
// Method setTitle removes title attribute when it's an empty
// string, so setAttribute() should be used here
fu.getElement().setAttribute("title", "");
}
// For other browsers absent title doesn't show default tooltip for
// input element
} else {
fu.setTitle(null);
}
}

@Override
protected void onAttach() {
super.onAttach();
if (client != null) {
ensureTargetFrame();
}
}

/** For internal use only. May be removed or replaced in the future. */
public void ensureTargetFrame() {
if (synthesizedFrame == null) {
// Attach a hidden IFrame to the form. This is the target iframe to
// which the form will be submitted. We have to create the iframe
// using innerHTML, because setting an iframe's 'name' property
// dynamically doesn't work on most browsers.
DivElement dummy = Document.get().createDivElement();
dummy.setInnerHTML("<iframe src=\"javascript:''\" name='"
+ getFrameName()
+ "' style='position:absolute;width:0;height:0;border:0'>");
synthesizedFrame = dummy.getFirstChildElement();
Document.get().getBody().appendChild(synthesizedFrame);
element.setTarget(getFrameName());
onloadstrategy.hookEvents(synthesizedFrame, this);
}
}

private String getFrameName() {
return paintableId + "_TGT_FRAME";
}

@Override
protected void onDetach() {
super.onDetach();
if (!submitted) {
cleanTargetFrame();
}
}

private void cleanTargetFrame() {
if (synthesizedFrame != null) {
Document.get().getBody().removeChild(synthesizedFrame);
onloadstrategy.unHookEvents(synthesizedFrame);
synthesizedFrame = null;
}
}

}

+ 112
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadConnector.java View File

@@ -0,0 +1,112 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.vaadin.v7.client.ui.upload;

import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Paintable;
import com.vaadin.client.UIDL;
import com.vaadin.client.communication.StateChangeEvent;
import com.vaadin.shared.EventId;
import com.vaadin.shared.ui.Connect;
import com.vaadin.v7.client.ui.AbstractLegacyComponentConnector;
import com.vaadin.v7.client.ui.VUpload;
import com.vaadin.v7.shared.ui.upload.UploadClientRpc;
import com.vaadin.v7.shared.ui.upload.UploadServerRpc;
import com.vaadin.v7.shared.ui.upload.UploadState;

@Connect(com.vaadin.v7.ui.Upload.class)
public class UploadConnector extends AbstractLegacyComponentConnector
implements Paintable {

public UploadConnector() {
registerRpc(UploadClientRpc.class, new UploadClientRpc() {
@Override
public void submitUpload() {
getWidget().submit();
}
});
}

@Override
protected void init() {
super.init();

getWidget().fu.addChangeHandler(new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
if (hasEventListener(EventId.CHANGE)) {
getRpcProxy(UploadServerRpc.class)
.change(getWidget().fu.getFilename());
}
}
});
}

@Override
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
if (!isRealUpdate(uidl)) {
return;
}
if (uidl.hasAttribute("notStarted")) {
getWidget().t.schedule(400);
return;
}
getWidget().setImmediate(getState().immediate);
getWidget().client = client;
getWidget().paintableId = uidl.getId();
getWidget().nextUploadId = uidl.getIntAttribute("nextid");
final String action = client
.translateVaadinUri(uidl.getStringVariable("action"));
getWidget().element.setAction(action);
if (uidl.hasAttribute("buttoncaption")) {
getWidget().submitButton
.setText(uidl.getStringAttribute("buttoncaption"));
getWidget().submitButton.setVisible(true);
} else {
getWidget().submitButton.setVisible(false);
}
getWidget().fu.setName(getWidget().paintableId + "_file");

if (!isEnabled() || isReadOnly()) {
getWidget().disableUpload();
} else if (!uidl.getBooleanAttribute("state")) {
// Enable the button only if an upload is not in progress
getWidget().enableUpload();
getWidget().ensureTargetFrame();
}
}

@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);

getWidget().disableTitle(hasTooltip());
}

@Override
public VUpload getWidget() {
return (VUpload) super.getWidget();
}

@Override
public UploadState getState() {
return (UploadState) super.getState();
}

}

+ 39
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadIFrameOnloadStrategy.java View File

@@ -0,0 +1,39 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.client.ui.upload;

import com.vaadin.v7.client.ui.VUpload;

public class UploadIFrameOnloadStrategy {

public native void hookEvents(com.google.gwt.dom.client.Element iframe,
VUpload upload)
/*-{
iframe.onload = $entry(function() {
upload.@com.vaadin.client.ui.VUpload::onSubmitComplete()();
});
}-*/;

/**
* @param iframe
* the iframe whose onLoad event is to be cleaned
*/
public native void unHookEvents(com.google.gwt.dom.client.Element iframe)
/*-{
iframe.onload = null;
}-*/;

}

+ 42
- 0
compatibility-client/src/main/java/com/vaadin/v7/client/ui/upload/UploadIFrameOnloadStrategyIE.java View File

@@ -0,0 +1,42 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.client.ui.upload;

import com.google.gwt.dom.client.Element;
import com.vaadin.v7.client.ui.VUpload;

/**
* IE does not have onload, detect onload via readystatechange
*
*/
public class UploadIFrameOnloadStrategyIE extends UploadIFrameOnloadStrategy {
@Override
public native void hookEvents(Element iframe, VUpload upload)
/*-{
iframe.onreadystatechange = $entry(function() {
if (iframe.readyState == 'complete') {
upload.@com.vaadin.client.ui.VUpload::onSubmitComplete()();
}
});
}-*/;

@Override
public native void unHookEvents(Element iframe)
/*-{
iframe.onreadystatechange = null;
}-*/;

}

+ 1173
- 0
compatibility-server/src/main/java/com/vaadin/v7/ui/Upload.java
File diff suppressed because it is too large
View File


+ 26
- 0
compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/upload/UploadClientRpc.java View File

@@ -0,0 +1,26 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.shared.ui.upload;

import com.vaadin.shared.communication.ClientRpc;

public interface UploadClientRpc extends ClientRpc {

/**
* Forces the upload the send selected file to the server.
*/
void submitUpload();
}

+ 38
- 0
compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/upload/UploadServerRpc.java View File

@@ -0,0 +1,38 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.shared.ui.upload;

import com.vaadin.shared.communication.ServerRpc;

public interface UploadServerRpc extends ServerRpc {

/**
* Event sent when the file name of the upload component is changed.
*
* @param filename
* The filename
*/
void change(String filename);

/**
* Called to poll the server to see if any changes have been made e.g. when
* starting upload
*
* @since 7.6
*/
void poll();

}

+ 30
- 0
compatibility-shared/src/main/java/com/vaadin/v7/shared/ui/upload/UploadState.java View File

@@ -0,0 +1,30 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.shared.ui.upload;

import com.vaadin.shared.AbstractComponentState;

/**
* Shared state for the Upload component.
*
* @since 7.6
*/
public class UploadState extends AbstractComponentState {

{
primaryStyleName = "v-upload";
}
}

+ 77
- 0
uitest/src/main/java/com/vaadin/v7/tests/components/upload/TestFileUpload.java View File

@@ -0,0 +1,77 @@
package com.vaadin.v7.tests.components.upload;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;

import org.apache.commons.codec.digest.DigestUtils;

import com.vaadin.tests.components.TestBase;
import com.vaadin.tests.util.Log;
import com.vaadin.v7.ui.Upload;
import com.vaadin.v7.ui.Upload.FailedEvent;
import com.vaadin.v7.ui.Upload.FailedListener;
import com.vaadin.v7.ui.Upload.Receiver;
import com.vaadin.v7.ui.Upload.SucceededEvent;
import com.vaadin.v7.ui.Upload.SucceededListener;

public class TestFileUpload extends TestBase implements Receiver {

private Log log = new Log(5);

ByteArrayOutputStream baos = new ByteArrayOutputStream();

@Override
protected void setup() {
Upload u = new Upload("Upload", new Upload.Receiver() {

@Override
public OutputStream receiveUpload(String filename,
String mimeType) {
return baos;
}
});
u.setId("UPL");
u.addFailedListener(new FailedListener() {

@Override
public void uploadFailed(FailedEvent event) {
String hash = DigestUtils.md5Hex(baos.toByteArray());

log.log("<span style=\"color: red;\">Upload failed. Name: "
+ event.getFilename() + ", Size: " + baos.size()
+ ", md5: " + hash + "</span>");
baos.reset();
}
});
u.addSucceededListener(new SucceededListener() {

@Override
public void uploadSucceeded(SucceededEvent event) {
String hash = DigestUtils.md5Hex(baos.toByteArray());
log.log("Upload finished. Name: " + event.getFilename()
+ ", Size: " + baos.size() + ", md5: " + hash);
baos.reset();
}
});

addComponent(log);
addComponent(u);
}

@Override
public OutputStream receiveUpload(String filename, String MIMEType) {
getMainWindow().showNotification("Receiving upload");
return new ByteArrayOutputStream();
}

@Override
protected Integer getTicketNumber() {
return 6465;
}

@Override
protected String getDescription() {
return "Creates and prints an MD5 hash of any uploaded file.";
}

}

+ 126
- 0
uitest/src/test/java/com/vaadin/v7/tests/components/upload/TestFileUploadTest.java View File

@@ -0,0 +1,126 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.vaadin.v7.tests.components.upload;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;

import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.internal.WrapsElement;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.LocalFileDetector;
import org.openqa.selenium.remote.RemoteWebElement;

import com.vaadin.testbench.elements.UploadElement;
import com.vaadin.tests.tb3.MultiBrowserTest;

public class TestFileUploadTest extends MultiBrowserTest {

@Override
public List<DesiredCapabilities> getBrowsersToTest() {
// PhantomJS fails to upload files for unknown reasons
return getBrowsersExcludingPhantomJS();
}

@Test
public void testUploadAnyFile() throws Exception {
openTestURL();

File tempFile = createTempFile();
fillPathToUploadInput(tempFile.getPath());

getSubmitButton().click();

String expected = String.format(
"1. Upload finished. Name: %s, Size: %s, md5: %s",
tempFile.getName(), getTempFileContents().length(),
md5(getTempFileContents()));

String actual = getLogRow(0);
Assert.assertEquals("Upload log row does not match expected", expected,
actual);
}

private String md5(String string) throws NoSuchAlgorithmException {
byte[] digest = MessageDigest.getInstance("MD5")
.digest(string.getBytes());
BigInteger bigInt = new BigInteger(1, digest);
String hashtext = bigInt.toString(16);
return hashtext;
}

/**
* @return The generated temp file handle
* @throws IOException
*/
private File createTempFile() throws IOException {
File tempFile = File.createTempFile("TestFileUpload", ".txt");
BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));
writer.write(getTempFileContents());
writer.close();
tempFile.deleteOnExit();
return tempFile;
}

private String getTempFileContents() {
return "This is a test file!\nRow 2\nRow3";
}

private void fillPathToUploadInput(String tempFileName) throws Exception {
// create a valid path in upload input element. Instead of selecting a
// file by some file browsing dialog, we use the local path directly.
WebElement input = getInput();
setLocalFileDetector(input);
input.sendKeys(tempFileName);
}

private WebElement getSubmitButton() {
UploadElement upload = $(UploadElement.class).first();
WebElement submitButton = upload.findElement(By.className("v-button"));
return submitButton;
}

private WebElement getInput() {
return getDriver().findElement(By.className("gwt-FileUpload"));
}

private void setLocalFileDetector(WebElement element) throws Exception {
if (getRunLocallyBrowser() != null) {
return;
}

if (element instanceof WrapsElement) {
element = ((WrapsElement) element).getWrappedElement();
}
if (element instanceof RemoteWebElement) {
((RemoteWebElement) element)
.setFileDetector(new LocalFileDetector());
} else {
throw new IllegalArgumentException(
"Expected argument of type RemoteWebElement, received "
+ element.getClass().getName());
}
}
}

Loading…
Cancel
Save