Issue
I'm currently working on automating facebook login and logout, but I have problems. Basically, I have created a FacebookLogOutTest
class, that needs to run FacebookLogIn
first, and then continue. These are the classes:
FacebookLogIn
public class FacebookLogInTest {
WebDriver driver;
@Test
public void facebookLogIn() {
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.get("https://www.facebook.com/");
WebElement username = driver.findElement(By.id("email"));
WebElement password = driver.findElement(By.id("pass"));
WebElement login = driver.findElement(By.xpath("//*[@name='login']"));
username.sendKeys("xxxxxx");
password.sendKeys("xxxxxx");
login.click();
}
}
FabecookLogOut
public class FacebookLogOutTest {
WebDriver driver;
@Test
public void facebookLogOut() {
FacebookLogInTest fbLogin = new FacebookLogInTest();
fbLogin.facebookLogIn();
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
WebElement profileButton = driver.findElement(By.xpath(("//*[@aria-label='Your page']")));
profileButton.click();
WebElement logoutButton = driver.findElement(By.xpath("//span[text()='Log out']"));
logoutButton.click();
}
}
But when I'm trying to run the log out class, it throws an exception and I don't know why. The log in class works properly. What should I do?
Here's the stacktrace:
java.lang.NullPointerException
at FacebookLogOutTest.facebookLogOut(FacebookLogOutTest.java:18)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Solution
The problem is that you never assign a driver instance to the driver
variable in facebookLogIn()
. Each test should stand alone, e.g. you shouldn't be calling facebookLogIn()
from facebookLogOut()
. Each test should have it's own driver instance and should be run on it's own browser instance to keep your tests super clean.
Each test should look like this:
- Launch browser
- Do stuff
- Close browser
You have the right idea in trying to reuse code but investigate page objects instead. Create a page object for the login page (to log in) and one for the header (to click the profile icon and log out).
Now your test will look like:
WebDriverManager.chromedriver().setup();
driver = new ChromeDriver();
driver.get("https://www.facebook.com/");
new HomePage(driver).logIn(username, password);
Header header = new Header(driver);
header.clickProfileIcon();
header.clickLogOut();
Very simple, very easy to read and lots of code reuse. Now when you create your second test, you can start with the same few lines of code setting up the driver and logging in and then get on to whatever the new test is supposed to cover.
Answered By - JeffC
Answer Checked By - Katrina (JavaFixing Volunteer)