wicket 9: how to test downloading a resource - wicket

I have a component which allows a user to download an excel file after clicking a link.
It works and everything is fine, but I don't know how to write a test for this component.
I want to write a test to check if after pressing a link a file is sent to a client.
And so, my component looks like this
Link<Void> calculationsLink = new Link<>("calculationsLink") {
#Override
public void onClick() {
AbstractResourceStreamWriter rStream =
new AbstractResourceStreamWriter() {
#Override
public void write(OutputStream output)
throws IOException {
output.write(MyApp.class
.getResourceAsStream(pathToCalculations)
.readAllBytes());
}
};
ResourceStreamRequestHandler handler =
new ResourceStreamRequestHandler(rStream, "calculations.xslx");
getRequestCycle().scheduleRequestHandlerAfterCurrent(handler);
}
};
My test is
#Test
public void calculations_file_downloaded_Successfully() {
// then start and render the base page
tester.startPage(HomePage.class); <-- link is located in a HomePage
tester.clickLink("navBar:calculations", false); <-- link is clickable
tester.getResponse();//????
tester.assert???(?????); <-- how to assert and what to assert?
}

You should use tester.getLastResponse() and assert on its properties.
tester.getResponse() is the MockHttpServletResponse that will be used for the next HTTP call.
Some dummy examples:
assertEquals("application/octet-stream", tester.getLastResponse().getContentType());
assertEquals(3, tester.getLastResponse().getBinaryContent().length);
assertArrayEquals(new byte[] {1, 2, 3}, tester.getLastResponse().getBinaryContent());

Related

Page is not being loaded in GWT

I am using activities and places to develop my application. When I click on the link on the left, my page is loaded, and I put the values in the fields. After I put the values, I send a RPC to the server, and get response back. This is also shown. Now the problem is that even if I click on the link on the left, I am getting the result page again. I am not getting the input page.
Impl code
#UiHandler("entInvoiceCompare")
void onClickSubmit(ClickEvent e) {
GWT.log("Going to enterprise compare place");
//listener.goTo(new EnterpriseInvoiceCompareViewPlace());
NewEBRM.getClientFactory().getPlaceController().goTo(new EnterpriseInvoiceCompareViewPlace());
}
Place
public class EnterpriseInvoiceCompareViewPlace extends Place{
public EnterpriseInvoiceCompareViewPlace() {
GWT.log("EnterpriseInvoiceCompareViewPlace: constructor");
}
public static class Tokenizer implements PlaceTokenizer<EnterpriseInvoiceCompareViewPlace> {
#Override
public String getToken(EnterpriseInvoiceCompareViewPlace place {
GWT.log("EnterpriseInvoiceCompareViewPlace: getToken: call");
return "EntInvoiceCompare";
}
#Override
public EnterpriseInvoiceCompareViewPlace getPlace(String token) {
GWT.log("EnterpriseInvoiceCompareViewPlace: getPlace: call");
return new EnterpriseInvoiceCompareViewPlace();
}
}
}
Activity
#Override
public void start(AcceptsOneWidget containerWidget, EventBus eventBus) {
// TODO Auto-generated method stub
GWT.log("EnterpriseInvoiceCompareActivity: start: starting activity");
EnterpriseInvoiceCompareView entInvoiceCompareView = clientFactory.getEnterpriseInvoiceCompareView();
entInvoiceCompareView.setPresenter(this);
containerWidget.setWidget(entInvoiceCompareView.asWidget());
GWT.log("EnterpriseInvoiceCompareActivity: start: ending activity");
}

How to find out component-path

I use junit to assert the existing of wicket components:
wicketTester.assertComponent("dev1WicketId:dev2WicketId:formWicketId", Form.class);
This works for some forms. For complex structure, it is defficult to find out the path of the form by searching all html files. Is there any method how to find out the path easy?
If you have the component you can call #getPageRelativePath(). E.g.
// Supposing c is a component that has been added to the page.
// Returns the full path to the component relative to the page, e.g., "path:to:label"
String pathToComponent = c.getPageRelativePath();
You can get the children of a markup container by using the visitChildren() method. The following example shows how to get all the Forms from a page.
List<Form> list = new ArrayList<Form<?>>();
Page page = wicketTester.getLastRenderedPage();
for (Form form : page.visitChildren(Form.class)) {
list.add(form);
}
An easy way to get those is to call getDebugSettings().setOutputComponentPath(true); when initializing your application. This will make Wicket to output these paths to the generated HTML as an attribute on every component-bound tag.
It's recommended to only enable this on debug mode, though:
public class WicketApplication extends WebApplication {
#Override
public void init() {
super.init();
if (getConfigurationType() == RuntimeConfigurationType.DEVELOPMENT) {
getDebugSettings().setOutputComponentPath(true);
}
}
}
Extending the RJo's answer.
It seems that the method page.visitChildren(<Class>) is deprecated (Wicket 6), so with an IVisitor it can be :
protected String findPathComponentOnLastRenderedPage(final String idComponent) {
final Page page = wicketTester.getLastRenderedPage();
return page.visitChildren(Component.class, new IVisitor<Component, String>() {
#Override
public void component(final Component component, final IVisit<String> visit) {
if (component.getId().equals(idComponent)) {
visit.stop(component.getPageRelativePath());
}
}
});
}

Wicket model window throw error when first open in new tab by right click and then click on model window link

When i am going to one page(A) to another page(B) using Ajax link URL show like ...?wicket:interface=:58::::#
On B page i have a link for open model window.when we direct click on link of model window its working fine but when first open link in new Tab by right click and then click on model window link its throwing an error.
I am using setResponsePage( new B(variable)) for come to another page.when i am using setResponsePage(B.class) instead of setResponsePage( new B(variable)) its working fine.
Note : I don't want to use pageparameter with bookmarkable and setResponsePage.
Error is :
org.apache.wicket.WicketRuntimeException: component listForm:group:issueList:1:editStatus not found on page com.B[id = 18], listener interface = [RequestListenerInterface name=IBehaviorListener, method=public abstract void org.apache.wicket.behavior.IBehaviorListener.onRequest()]
org.apache.wicket.protocol.http.request.InvalidUrlException: org.apache.wicket.WicketRuntimeException: component listForm:group:issueList:1:editStatus not found on page com.B[id = 18], listener interface = [RequestListenerInterface name=IBehaviorListener, method=public abstract void org.apache.wicket.behavior.IBehaviorListener.onRequest()]
at ...........................
... 27 more
"editStatus" is a link name on model window.
Code that i am using Class A
class A extends WebPage {
Link<String> escalated = new Link<String>("escalated") {
public void onClick() {
setResponsePage(new B(Variables));
} };
}
class B extends WebPage {
public B(variables..) {
}
final ModalWindow model = new ModalWindow("UpdateModel");
model.setContent(new C(model,variables,model.getContentId()));
item.add(new AjaxLink<Void>(**"editStatus"**) {
public void onClick(AjaxRequestTarget target) {
model.show(target);
}
}.add(new Image("edit_icon", "image/edit.png")));
}
}
class C extends Panel {
public C(.....) {
}
}
I have solved this issue.Error was relating with state of wicket component.
Use StatelessLink instead of Link.
correct code :
class A extends WebPage {
StatelessLink escalated = new StatelessLink("escalated") {
public void onClick() {
setResponsePage(new B(Variables));
} };
}
it would also removed "...?wicket:interface=:58::::#" from url.
when we used Link,AjaxLink it would maintain state.so when we open any link in new tab it would changed state on server side(change ids of component) but on client side it would remain same. so when we click any link on same page there are no information of updated ids and it would have thrown an error.

GWT FileUpload - Servlet options and handling response

I am new to GWT and am trying to implement a file upload functionality.
Found some implementation help over the internet and used that as reference.
But have some questions related to that:
The actual upload or writing the contents of file on server(or disk) will be done by a servlet.
Is it necessary that this servlet (say MyFileUploadServlet) extends HttpServlet? OR
I can use RemoteServiceServlet or implement any other interface? If yes, which method do I need to implement/override?
In my servlet, after everything is done, I need to return back the response back to the client.
I think form.addSubmitCompleteHandler() can be used to achieve that. From servlet, I could return text/html (or String type object) and then use SubmitCompleteEvent.getResults() to get the result.
Question is that can I use my custom object instead of String (lets say MyFileUploadResult), populate the results in it and then pass it back to client?
or can I get back JSON object?
Currently, after getting back the response and using SubmitCompleteEvent.getResults(), I am getting some HTML tags added to the actual response such as :
pre> Image upload successfully /pre> .
Is there a way to get rid of that?
Thanks a lot in advance!
Regards,
Ashish
To upload files, I have extended HttpServlet in the past. I used it together with Commons-FileUpload.
I made a general widget for form-based uploads. That was to accommodate uploads for different file types (plain text and Base64). If you just need to upload plain text files, you could combine the following two classes into one.
public class UploadFile extends Composite {
#UiField FormPanel uploadForm;
#UiField FileUpload fileUpload;
#UiField Button uploadButton;
interface Binder extends UiBinder<Widget, UploadFile> {}
public UploadFile() {
initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));
fileUpload.setName("fileUpload");
uploadForm.setEncoding(FormPanel.ENCODING_MULTIPART);
uploadForm.setMethod(FormPanel.METHOD_POST);
uploadForm.addSubmitHandler(new SubmitHandler() {
#Override
public void onSubmit(SubmitEvent event) {
if ("".equals(fileUpload.getFilename())) {
Window.alert("No file selected");
event.cancel();
}
}
});
uploadButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
uploadForm.submit();
}
});
}
public HandlerRegistration addCompletedCallback(
final AsyncCallback<String> callback) {
return uploadForm.addSubmitCompleteHandler(new SubmitCompleteHandler() {
#Override
public void onSubmitComplete(SubmitCompleteEvent event) {
callback.onSuccess(event.getResults());
}
});
}
}
The UiBinder part is pretty straighforward.
<g:HTMLPanel>
<g:HorizontalPanel>
<g:FormPanel ui:field="uploadForm">
<g:FileUpload ui:field="fileUpload"></g:FileUpload>
</g:FormPanel>
<g:Button ui:field="uploadButton">Upload File</g:Button>
</g:HorizontalPanel>
</g:HTMLPanel>
Now you can extend this class for plain text files. Just make sure your web.xml serves the HttpServlet at /textupload.
public class UploadFileAsText extends UploadFile {
public UploadFileAsText() {
uploadForm.setAction(GWT.getModuleBaseURL() + "textupload");
}
}
The servlet for plain text files goes on the server side. It returns the contents of the uploaded file to the client. Make sure to install the jar for FileUpload from Apache Commons somewhere on your classpath.
public class TextFileUploadServiceImpl extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (! ServletFileUpload.isMultipartContent(request)) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
"Not a multipart request");
return;
}
ServletFileUpload upload = new ServletFileUpload(); // from Commons
try {
FileItemIterator iter = upload.getItemIterator(request);
if (iter.hasNext()) {
FileItemStream fileItem = iter.next();
// String name = fileItem.getFieldName(); // file name, if you need it
ServletOutputStream out = response.getOutputStream();
response.setBufferSize(32768);
int bufSize = response.getBufferSize();
byte[] buffer = new byte[bufSize];
InputStream in = fileItem.openStream();
BufferedInputStream bis = new BufferedInputStream(in, bufSize);
long length = 0;
int bytes;
while ((bytes = bis.read(buffer, 0, bufSize)) >= 0) {
out.write(buffer, 0, bytes);
length += bytes;
}
response.setContentType("text/html");
response.setContentLength(
(length > 0 && length <= Integer.MAX_VALUE) ? (int) length : 0);
bis.close();
in.close();
out.flush();
out.close();
}
} catch(Exception caught) {
throw new RuntimeException(caught);
}
}
}
I cannot recall how I got around the <pre></pre> tag problem. You may have to filter the tags on the client. The topic is also addressed here.

GWT new EntityProxy in #OneToOne with another EntityProxy from server

I am just creating a new Proxy:
LayoutExampleRequest r = requestFactory.employeeRequest();
DepartmentProxy d = r.create(DepartmentProxy.class);
r.save(d);
departmentEditor.editProxy(d, r);
Then pass the Proxy and the Request(LayoutExampleRequest ) to my editor
driver.edit(proxy, request);
Until here ! everything works as espected. I can save Department objects with null EmployeeProxy. Now iam getting with a suggest box Proxys of EmployeeProxy from the server.
search = new SuggestBox(new SuggestOracle() {
#Override
public void requestSuggestions(final Request request,final Callback callback) {
System.out.println(request.getQuery());
//ignore less than 3
if(request.getQuery().length() > 3){
requestFactory.employeeRequest().search(request.getQuery()).fire(new Receiver<List<EmployeeProxy>>(){
#Override
public void onSuccess(List<EmployeeProxy> response) {
List<MySuggestion<EmployeeProxy>> suggestions = new ArrayList<MySuggestion<EmployeeProxy>>();
for(EmployeeProxy e:response){
MySuggestion<EmployeeProxy> suggestion = new MySuggestion<EmployeeProxy>();
suggestion.setModel(e,e.getFirstName(),e.getFirstName()+" "+e.getLastName());
suggestions.add(suggestion);
}
callback.onSuggestionsReady(request, new Response(suggestions));
}
});
}
}
});
MySuggestion is a wrapper class to handle the EmployeeProxy.
Now i want to add this EmployeeProxy to my DeparmentProxy since i have a #OneToOne on JPA.
search.addSelectionHandler(new SelectionHandler<SuggestOracle.Suggestion>() {
#Override
public void onSelection(SelectionEvent<Suggestion> event) {
MySuggestion<EmployeeProxy> s = (MySuggestion<EmployeeProxy>)event.getSelectedItem();
proxy.setSupervisor(s.getModel());
}
});
proxy is the EntityProxy for Department (I sent to my editor) driver.edit(proxy, request);
then i fire the driver:
departmentEditor.getDriver().flush().fire(new Receiver<Void>() {
#Override
public void onSuccess(Void response) {
Window.alert("Success");
// refresh the datagrid
Range range = dataGrid.getVisibleRange();
dataGrid.setVisibleRangeAndClearData(range, true); //1st way
// create a new DepartmentProxy to bind to the Editor.
createProxy();
// change button text
updateButton.setText("Save");
}
#Override
public void onConstraintViolation(Set<ConstraintViolation<?>> violations) {
for(ConstraintViolation v :violations){
Window.alert(v.getMessage()+" "+v.getPropertyPath());
}
}
#Override
public void onFailure(ServerFailure error) {
Window.alert(error.getMessage());
}
});
The problem is iam getting ConstraintViolations from the EmployeeProxy, is like the driver atach the EmployeeProxy but with null values.
(Iam validating my Entityes with JSR-330 )
Dont know how to make a relationship with a new Proxy with other taked from the server. in a #OneToOne relationship
Any help would be nice!
Thank you
/* UPDATE */
Something like this but with editor
final LayoutExampleRequest r = requestFactory.employeeRequest();
final DepartmentProxy d = r.create(DepartmentProxy.class);
d.setName("Name");
d.setService(Service.CONTRACT_MANAGMENT);
// get some random employee
requestFactory.employeeRequest().findById(1).fire(new Receiver<EmployeeProxy>() {
#Override
public void onSuccess(EmployeeProxy response) {
d.setSupervisor(response);
r.save(d).fire(new Receiver<DepartmentProxy>() {
#Override
public void onSuccess(DepartmentProxy response) {
Window.alert("Kidding me! why editor cant get it work =p?");
}
});
}
});
The problem was i put on my editor properties of the EmployeeProxy so when a user select the employeproxy would see information about it, so i delete them and then do the same and now works.
Is like GWT when detects properties from another proxy on the editor thinks you will fill it. And the line:
proxy.setSupervisor(s.getModel());
doesn't works.