Cucumber Spring PageObjectModel - spring

I'm trying to Integrate Spring into Cucumber Selenium Project.
Project is already configured with PageObjectModel design pattern and working perfectly before integrating with Spring.
public abstract class BasePage {
public WebDriver driver;
public BasePage(WebDriver driver) {
this.driver = driver;
}
public void verifyPage() {
//verify page
}
}
public class HomePage extends BasePage {
#FindBy(how = How.ID, using = "MENU_lINK")
private Link MENU_HEADER;
public HomePage(WebDriver driver) {
super(driver);
PageFactory.initElements(new HtmlElementDecorator(new HtmlElementLocatorFactory(driver)), this);
}
public Link getMENU_HEADER() {
return MENU_HEADER;
}
}
public class HomePageSteps {
private static final Logger LOGGER = Logger.getLogger(HomePageSteps.class.getName());
private WebDriver driver;
HomePage homePage;
HelperPage helperPage;
public HomePageSteps() {
driver = WebDriverProvider.driver; //Driver initiated here
homePage = new HomePage(driver);
}
#Given("I'm on home page")
public void navigateToHomePage() {
homePage.getMENU_HEADER().click();
}
After integrating with Spring issue noticed is all the features are executing in same browser.
Before Spring integration each feature used to execute in separated browser as #After and #Before annotations are used that are available in Cucumber
public class WebDriverProvider {
public static WebDriver driver;
#Before
public void openBrowser() throws MalformedURLException {
System.setProperty("webdriver.chrome.driver", new File(".").getAbsolutePath() + "/drivers/chromedriver.exe");
if (driver != null) driver.quit();
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(20,TimeUnit.SECONDS);
}
#After
public void embedScreenshot(Scenario scenario) {
driver.quit();
}
}
After integration with Spring in applicationcontext.xml file I have defined the Driver. I can't call driver from #After and #Before methods and all the tests are executed in same browser
Below is the code snippet attached.
<bean id="driverProvider" class="com.ecom.utils.DriverProvider" scope="prototype"/>
<bean id="webDriver"
class="org.openqa.selenium.WebDriver"
factory-bean="driverProvider"
factory-method="getDriver" scope="prototype"/>
public abstract class BasePage {
#Autowired
protected WebDriver driver;
public void verifyPage() {
//verify Page
}
}
#Component
public class HomePage extends BasePage {
#FindBy(how = How.XPATH, using = "//*[#id='js-siteMainNavigation']//a[#class='qa-Cl_Menu c-site-nav-main-link-1']")
private Link MENU_HEADER;
public HomePage(WebDriver driver) {
PageFactory.initElements(new HtmlElementDecorator(new HtmlElementLocatorFactory(driver)), this);
}
public Link getMENU_HEADER() {
return MENU_HEADER;
}
}
public class HomePageSteps {
private static final Logger LOGGER = Logger.getLogger(HomePageSteps.class.getName());
#Autowired
HomePage homePage;
#When("I navigate to pizza selection page")
public void navigateToMenuPage() {
homePage.getMENU_HEADER().click();
}
}
I don't see a way in calling spring bean from #After and #Before annotations.
I want to initiate a fresh browser for every feature.
I thought to create Web Driver in Steps and Pass across the Pages, but for this I have to define a constructor with WebDrviver
public HomePage(WebDriver driver) {
super(driver);
PageFactory.initElements(new HtmlElementDecorator(new HtmlElementLocatorFactory(driver)), this);
}
But Spring is complain for a bean associated to this.
Any help would be highly appreciated.

Why are you using Spring to inject the browser? Spring will make certain that the same instance, i.e. same browser, is used everywhere. That was dependency injection frameworks do.
Use Spring to inject objects that allows you to share state between steps if the steps are used in different step definition classes.

Related

Spring Boot #Component doesn't create Beans

Since according to the docs #Component registers beans for the Spring container I'm trying to create a simple example of dependency injection using the following code:
package pl.playground;
//...
#SpringBootApplication
public class PlaygroundApplication {
#Autowired
private static Building building;
public static void main(String[] args) {
building.setBuildingSize(12L);
System.out.println(building.monthlyHeatingCost());
}
}
package pl.playground.facade;
//...
#Component
public class Building {
private HeatingService service;
private Long buildingSize;
#Autowired
public Building(HeatingService service) {
this.service = service;
}
public Double monthlyHeatingCost() {
return service.getMonthlyHeatingCost(buildingSize);
}
// getters & setters...
}
package pl.playground.service;
public interface HeatingService {
Double getMonthlyHeatingCost(Long size);
}
package pl.playground.service;
//...
#Component
public class HeatingServiceImpl implements HeatingService {
private final Double CUBIC_PRICE = 2.3;
public HeatingServiceImpl() {}
#Override
public Double getMonthlyHeatingCost(Long size) {
return size * CUBIC_PRICE;
}
}
It builds and runs, but there is a NullPointerException at building.setBuildingSize(12L);. However the one below works without any issues:
//PlaygroundApplication.java
package pl.playground;
//...
#SpringBootApplication
public class PlaygroundApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
Building building = context.getBean(Building.class);
building.setBuildingSize(12L);
System.out.println(building.monthlyHeatingCost());
}
}
package pl.playground.config;
//...
#Configuration
public class Config {
#Bean
public Building building(HeatingService service) {
return new Building(service);
}
#Bean
public HeatingServiceImpl heatingServiceImpl() {
return new HeatingServiceImpl();
}
}
The rest is the same as before.
Why is #Component not creating Beans?
It is working the way I think it should when used inside a #Controller of a web app, does that make a difference? How does exactly #Bean and #Component differ?
What am I failing to understand?
EDIT
Consider the following scenario:
package pl.playground;
//...
#SpringBootApplication
public class ExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}
package pl.playground.controller;
//...
#Controller
public class Controller {
private Facade facade;
#Autowired
public Controller(Facade facade) {
this.facade = facade;
}
#GetMapping("/")
public String getIndexPage(Model model) {
return "index";
}
}
package pl.playground.facade;
//...
#Component
public class Facade {
private PostsService postService;
private UserService userService;
private TagService tagService;
#Autowired
public Facade(PostsService retrieve, UserService user, TagService tag) {
this.postService = retrieve;
this.userService = user;
this.tagService = tag;
}
//...
}
I don't need #Configuration here for it to work. That's my concern.
The problem with your code is that you are trying to #Autowire on a static field. You simply cannot do that. Look here: Can you use #Autowired with static fields?
It fails to work because the PlaygroundApplication class is not being created and managed by spring. The injection works only inside instances managed by spring. You can treat class annotated with #SpringBootApplication as configuration classes. Spring creates instances of those classes and injection works inside them but only on instance fields.
The second example shows the correct way to access spring beans from main method of the application.
Well. I used your original question and is working without any issues. #cezary-butler pointed out in the comments you can autowire into PlaygroundApplication but you can get hold of it easily in the static main method using context.getBean(Building.class)
#SpringBootApplication
public class PlaygroundApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context =
SpringApplication.run(PlaygroundApplication.class);
Building building = context.getBean(Building.class);
building.setBuildingSize(12L);
System.out.println(building.monthlyHeatingCost());
}
}
Here is the sample repo https://github.com/kavi-kanap/stackoverflow-63072236
TLDR;
A Spring context needs to be created before any bean can be injected. In the first scenario, just the fact of having a #SpringBootApplication decorator does not ensure a context in the scope of the class it decorates.
SpringApplication.run(ExampleApplication.class, args); instantiates a context (and e.g. a web server among other things)
var context = new AnnotationConfigApplicationContext(Config.class); instantiates a scoped context
Thus the first example had null inside of Building as there was no context with the bean to inject.

Vaadin Dashboard demo using Spring Boot

I'm trying to put together a simple application using Vaadin + Spring Boot with just two views: login and dashboard. I'm using pieces of code from the Vaadin Dashboard demo. There is this method in the DashboardUI class:
private void updateContent() {
User user = (User) VaadinSession.getCurrent().getAttribute(
User.class.getName());
if (user != null && "admin".equals(user.getRole())) {
// Authenticated user
setContent(new MainView());
removeStyleName("loginview");
getNavigator().navigateTo(getNavigator().getState());
} else {
setContent(new LoginView());
addStyleName("loginview");
}
}
As you see the views are instantiated via the new keyword. Since I'm using Spring I would like the container take care of that. But I cannot figure out how to have the views injected by Spring.
Annotate your view with #VaadinUIScope and #VaadinComponent. And then you can use #Autowired to inject your view.
You should probably setup two UI classes i.e LoginUI.class and MainUI.class. Have Spring Security redirect unauthorized to /login and authorized to /
LoginUI.class
#Theme("valo")
#SpringUI(path = "login")
#PreserveOnRefresh
public class LoginUI extends UI {
private SpringViewProvider viewProvider;
#Autowired
public LoginUI(SpringViewProvider viewProvider) {
this.viewProvider = viewProvider;
}
#Override
protected void init(VaadinRequest request) {
Navigator navigator = new Navigator(this, this);
navigator.addProvider(viewProvider);
navigator.navigateTo(LoginView.VIEW_NAME);
}
}
MainAppUI.class
#Theme("valo")
#SpringUI
#PreserveOnRefresh
public class MainAppUI extends UI {
private SpringViewProvider viewProvider;
#Autowired
public AppUI(SpringViewProvider viewProvider) {
this.viewProvider = viewProvider;
}
#Override
protected void init(VaadinRequest request) {
getPage().setTitle("Main App");
setSizeFull();
Navigator navigator = new Navigator(this, viewDisplay);
navigator.addProvider(viewProvider);
setContent();//viewport
navigator.navigateTo(DashboardView.VIEW_NAME);
}
}
Then just use #SpringView(name = "moduleOne", ui = MainAppUI.class) on your module views for your app as suggested by Morfic to have the main navigator and module views registered only when a user has logged in to save on resources.
Note: Taking a look at that example it seems that they're not actually using views & navigator, they're somewhat faking them. If you want to proceed on the same path you can simply autowire the fake views in the UI instead of using the navigator as below.
The Vaadin-spring boot wiki offers an introduction to this by the use of:
1) #SpringUI with autowired SpringViewProvider
#Theme("valo")
#SpringUI
public class MyVaadinUI extends UI {
// we can use either constructor autowiring or field autowiring
#Autowired
private SpringViewProvider viewProvider;
#Override
protected void init(VaadinRequest request) {
// other init stuff
Navigator navigator = new Navigator(this, viewContainer);
navigator.addProvider(viewProvider);
}
}
2) #SpringView
#SpringView(name = DefaultView.VIEW_NAME)
public class DefaultView extends VerticalLayout implements View {
public static final String VIEW_NAME = "";
#PostConstruct
void init() {
addComponent(new Label("This is the default view"));
}
#Override
public void enter(ViewChangeEvent event) {
// the view is constructed in the init() method()
}
}
For the decision whether the user should be redirected to the login view, or the other ones, I usually use a ViewChangeListener, something along the lines of:
navigator.addViewChangeListener(new ViewChangeListener() {
#Override
public boolean beforeViewChange(ViewChangeEvent event) {
if (VaadinSession.getCurrent().getAttribute("user") == null) {
navigator.getDisplay().showView(loginView);
return false;
} else {
return true;
}
}
#Override
public void afterViewChange(ViewChangeEvent event) {
// meh
}
});

Why can't i create a neo4j relationship with spring data for neo?

i'm fairly new to spring data for neo (though i have experience with neo4j itself). i tried following the 'official' guide on spring data for neo, specifically the chapter on creating relationships.
But it seems i cannot get it to work. Spring is giving me an
java.lang.IllegalStateException: This index (Index[__rel_types__,Relationship]) has been marked as deleted in this transaction
Let me stress, that i am NOT removing any nodes or relationships. These are the relevant classes of my domain model:
#NodeEntity
public class User {
#GraphId
private Long nodeid;
#Indexed(unique = true)
private String uuid;
....
}
#NodeEntity
public class Website {
#GraphId
private Long nodeid;
#Indexed(unique = true)
private String uuid;
....
}
#RelationshipEntity(type = RelTypes.REL_USER_INTERESTED_IN)
public class UserInterest {
#GraphId
private Long nodeid;
#StartNode
private User user;
#EndNode
private Website site;
...
}
And this is my basic test which i can't get to turn green ..
(note that i omitted large portions of the code, the basic setup of the spring context etc. is working fine)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#Transactional
public class BaseTest {
#Autowired
protected Neo4jTemplate template;
#Autowired
protected GraphDatabaseService graphDatabaseService;
protected Transaction tx;
#Configuration
#EnableNeo4jRepositories
static class TestConfig extends Neo4jConfiguration {
TestConfig() throws ClassNotFoundException {
setBasePackage("me.bcfh.model");
}
#Bean
GraphDatabaseService graphDatabaseService() {
return new TestGraphDatabaseFactory().newImpermanentDatabase();
}
}
public void before() {
// provide implementation if necessary
}
public void after() {
// provide implementation if necessary
}
#Before
public void setup() throws Exception {
Neo4jHelper.cleanDb(graphDatabaseService, false);
before();
}
#After
public void tearDown() throws Exception {
after();
if (tx != null) {
tx.success();
tx.close();
tx = null;
}
}
}
public class BasicGraphTest extends BaseTest {
User user;
Website website;
UserInterest interest;
#Override
public void before() {
user = new User();
website = new Website();
website = template.save(website);
user = template.save(user);
}
#Test
#Transactional
public void dbShouldContainData() throws Exception {
UserInterest interest = new UserInterest();
interest.setSite(website);
interest.setUser(user);
template.save(interest);
// some assertions
...
}
}
The IllegalStateException is being thrown when I try persisting the UserInterest instance, which I do not understand because I am not removing anything anywhere.
The ways to create a relationship mentioned in the spring guide did not work for me either, here I got the same exception ..
Can anyone spot what I'm doing wrong here?
I am using Spring Version 4.1.4.RELEASE and Spring Data For Neo Version 3.2.1.RELEASE. Neo4j has version 2.1.6
Note: I also tried copying the domain model classes from the cineasts example into my project and borrowed a few lines of the DomainTest class but this too gives me the IllegalStateException, maybe there is something wrong with my setup?
I think you are getting your IllegalStateException because you are calling cleanDb in your setup method.
You may not need to clean the database. Since your tests are makred #Transactional anything you do in your tests gets rolled back at the end of the test.
Looks like the transaction is trying to rollback and can't find the relationship it expects.

PlayFramework: Depedencies are not inject using Spring and got NullPointerException

When i try to integrate Spring-Dependency-Injection in Play-framework with Java 8. In controller the dependencies are not injected. I am using spring stereo-type annotations. Get
Follwowing is my code:
Configuration:
public class GlobalConfiguration extends GlobalSettings{
private AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
#Override
public void onStart(Application app) {
super.onStart(app);
// AnnotationConfigApplicationContext can only be refreshed once, but we do it here even though this method
// can be called multiple times. The reason for doing during startup is so that the Play configuration is
// entirely available to this application context.
applicationContext.scan("com.harmeetsingh13.controllers", "com.harmeetsingh13.service.impl", "com.harmeetsingh13.dao.impl");
applicationContext.refresh();
// This will construct the beans and call any construction lifecycle methods e.g. #PostConstruct
applicationContext.start();
}
#Override
public void onStop(Application app) {
// This will call any destruction lifecycle methods and then release the beans e.g. #PreDestroy
applicationContext.close();
super.onStop(app);
}
#Override
public <A> A getControllerInstance(Class<A> clazz) throws Exception {
return applicationContext.getBean(clazz);
}
}
Controller:
#Component
public class UserController extends Controller{
#Autowired
private UserService userService;
public Result findUserById(Integer userId) {
Optional<User> user = userService.findUserById(userId);
if(user.isPresent()){
}
return null;
}
}
Service:
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserDao userDao;
#Override
public Optional<User> findUserById(int id) {
List<User> users = userDao.getAllUsers();
return users.stream().filter(user -> user.id == id).findFirst();
}
}
This is the link where i found sample application
This is really my stupid mistake. In play-framework we always need to put the custom global configuration file in project app folder at root and play-framework always find to search Global file name at app folder root and load into the memory. In my case, my GlobalConfiguration file are not loaded in the memory and default configuration are used by play-framework. For Global-Settings click on this link for more information

How to use guice-servlet with Jersey 2.0?

Is there any sample code demonstrating how to use guice-servlet with Jersey 2.0?
https://github.com/Squarespace/jersey2-guice seems to be the first genuine Guice integration for Jersey 2 but it requires version 2.11+.
NOTE: I haven't tested this, but the idea is sound.
Yes, I've adapted an example and it's available here - https://github.com/piersy/jersey2-guice-example-with-test
I've updated the example code now, its got a test using jetty and another using tomcat.
There is a page at HK2 official about correct guice implementation: https://javaee.github.io/hk2/guice-bridge.html
You should create your Injector something like this:
public class GuiceConfig extends ResourceConfig {
#Inject
public GuiceConfig(ServiceLocator serviceLocator) {
this();
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(GuiceListener.createBiDirectionalGuiceBridge(serviceLocator));
}
public GuiceConfig() {
packages(Injections.packages);
addProperties(Injections.propertiesMap);
}
}
And code from the doc should be upgraded like:
#WebListener
public class GuiceListener extends GuiceServletContextListener {
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
Locale.setDefault(Locale.ENGLISH);
super.contextInitialized(servletContextEvent);
}
public static volatile Injector injector = null;
#Override
protected Injector getInjector() {
return injector;
}
#SuppressWarnings("unchecked")
private static Module getModule() {
return binder -> {
Injections.singletonInterfaces.forEach((i, c) -> binder.bind(i).to(c).in(Scopes.SINGLETON));
Injections.singletonClasses.forEach(c -> binder.bind(c).in(Scopes.SINGLETON));
};
}
static synchronized Injector createBiDirectionalGuiceBridge(ServiceLocator serviceLocator) {
return GuiceListener.injector = createBiDirectionalGuiceBridge(serviceLocator, getModule());
}
}
Using the maven dependency at your pom.xml
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>guice-bridge</artifactId>
<version>2.3.0</version>
</dependency>
https://github.com/phxql/jersey2-guice doesn't work with jersey 2.22 and guice 4.0.
This is a minimum working PoC which wires Jersey 2 and Guice together:
https://github.com/phxql/jersey2-guice
I've already done in this sample:
https://github.com/jbescos/tododev
You have to register the class https://github.com/jbescos/tododev/blob/master/jersey2-guice/src/main/java/es/tododev/rest/ApplyGuiceContextFilter.java in your ResourceConfig, and the guice injector binded in an AbstractModule.
#Provider
#PreMatching
public class ApplyGuiceContextFilter implements ContainerRequestFilter, ContainerResponseFilter {
#Inject
public ApplyGuiceContextFilter(ServiceLocator serviceLocator, Injector injector) {
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
guiceBridge.bridgeGuiceInjector(injector);
}
#Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
}
#Override
public void filter(final ContainerRequestContext requestContext, final ContainerResponseContext responseContext) throws IOException {}
}
This is the ResouceConfig:
public class RestConfig extends ResourceConfig {
#Inject
public RestConfig() {
this(Guice.createInjector(new Module(){
#Override
public void configure(Binder arg0) {
// TODO Auto-generated method stub
}
}));
}
// Test
public RestConfig(Injector injector) {
packages(ResourceSample.class.getPackage().getName());
register(ApplyGuiceContextFilter.class);
register(new LoggingFilter(Logger.getLogger(LoggingFilter.class.getName()), true));
property(ServerProperties.TRACING, "ALL");
register(new RestBinder(injector));
}
private static class RestBinder extends AbstractBinder{
private final Injector injector;
private RestBinder(Injector injector){
this.injector = injector;
}
#Override
protected void configure() {
bind(injector).to(Injector.class);
}
}
}
GWizard includes a module that gives you out-of-the-box integration between Jersey2 and Guice. Here's an example of a complete JAX-RS service:
public class Main {
#Path("/hello")
public static class HelloResource {
#GET
public String hello() {
return "hello, world";
}
}
public static class MyModule extends AbstractModule {
#Override
protected void configure() {
bind(HelloResource.class);
}
}
public static void main(String[] args) throws Exception {
Guice.createInjector(new MyModule(), new JerseyModule()).getInstance(WebServer.class).startJoin();
}
}
Note that this is based on the Squarespace jersey2-guice adapter, which may not function properly with future point releases of Jersey. GWizard also offers a RESTEasy JAX-RS module, which is preferred.
Here is a blog entry about this that might help: http://blorn.com/post/107397841765/guice-and-jersey-2-the-easy-way
For those interested, there is a sample of guice/jersey integration available at https://github.com/mycom-int/jersey-guice-aop.
Here is an example using Embedded Jetty (it should probably work for Jetty server too)
jetty-jersey-HK2-Guice-boilerplate
If you are planning to use Guice for your application, all Guice components injected into Jersey need to be declared as a binding in the Guice config.
If you don't want to declare every binding in Guice config, there is an adapter here:
guice-bridge-jit-injector

Resources