Browse Source

Create declarative UI test harness (#17484)

Change-Id: I8d83830f897b50a73f2fa125d297457f7a90888c
tags/7.5.0.beta1
patrik 9 years ago
parent
commit
255da01eb1
1 changed files with 175 additions and 0 deletions
  1. 175
    0
      uitest/src/com/vaadin/tests/components/DeclarativeTestUI.java

+ 175
- 0
uitest/src/com/vaadin/tests/components/DeclarativeTestUI.java View File

@@ -0,0 +1,175 @@
/*
* Copyright 2000-2014 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.tests.components;

import java.io.File;
import java.io.FileInputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.vaadin.server.VaadinRequest;
import com.vaadin.ui.Component;
import com.vaadin.ui.declarative.Design;

/**
* Declarative test UI. Provides simple instantiation of HTML designs located
* under {@code uitest/src}. Also provides {@link OnLoad} annotation that lets
* you easily hook up methods to run after the UI has been created. Note: you
* <i>must</i> add the {@link DeclarativeUI} annotation to your subclass; not
* doing this will result in program failure.
*/
@SuppressWarnings("serial")
public class DeclarativeTestUI extends AbstractTestUI {

private Logger logger;
private Component component;

/**
* Class marker indicating the design .html file to load
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public static @interface DeclarativeUI {
String value();

/**
* Set this property to true if you provide an absolute path to your
* design; otherwise, the DeclarativeTestUI logic will look for the HTML
* design file under {@code vaadin_project/uitest/src/<package path>/}.
*/
boolean absolutePath() default false;
}

/**
* Method marker interface indicating that a method should be run after the
* declarative UI has been created
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface OnLoad {

}

/**
* Figure out the proper path for the HTML design file
*/
private String getDesignPath() {
Class<?> clazz = getClass();
String designFilePath = null;
if (clazz.getAnnotation(DeclarativeUI.class).absolutePath()) {
designFilePath = "";
} else {
// This is rather nasty.. but it works well enough for now.
String userDir = System.getProperty("user.dir");
designFilePath = userDir + "/uitest/src/"
+ clazz.getPackage().getName().replace('.', '/') + "/";
}

String designFileName = clazz.getAnnotation(DeclarativeUI.class)
.value();

return designFilePath + designFileName;
}

private Component readDesign() throws Exception {
String path = getDesignPath();
getLogger().log(Level.INFO, "Reading design from " + path);

File file = new File(path);
return Design.read(new FileInputStream(file));
}

@Override
protected void setup(VaadinRequest request) {
Class<?> clazz = getClass();

if (clazz.isAnnotationPresent(DeclarativeUI.class)) {

// Create component
try {
component = readDesign();
} catch (Exception e1) {
getLogger().log(Level.SEVERE, "Error reading design", e1);
return;
}

addComponent(component);

// Call on-load methods (if applicable)
Method[] methods = clazz.getMethods();
for (Method m : methods) {
if (m.isAnnotationPresent(OnLoad.class)) {
try {
m.invoke(this, (Object[]) null);
} catch (IllegalAccessException e) {
getLogger().log(Level.SEVERE,
"Error invoking @OnLoad method", e);
return;
} catch (IllegalArgumentException e) {
getLogger().log(Level.SEVERE,
"Error invoking @OnLoad method", e);
return;
} catch (InvocationTargetException e) {
getLogger().log(Level.SEVERE,
"Error invoking @OnLoad method", e);
return;
}
}
}

} else {
throw new IllegalStateException(
"Cannot find declarative UI annotation");
}
}

/**
* Get access to the declaratively created component. This method typecasts
* the component to the receiving type; if there's a mismatch between what
* you expect and what's written in the design, this will fail with a
* ClassCastException.
*
* @return a Vaadin component
*/
@SuppressWarnings("unchecked")
public <T extends Component> T getComponent() {
try {
return (T) component;
} catch (ClassCastException ex) {
getLogger().log(Level.SEVERE,
"Component code/design type mismatch", ex);
}
return null;
}

/**
* Get access to the logger of this class
*
* @return a Logger instance
*/
protected Logger getLogger() {
if (logger == null) {
logger = Logger.getLogger(getClass().getName());
}
return logger;
}
}

Loading…
Cancel
Save