package com.thoughtworks.calabash.android.IT;
import com.thoughtworks.calabash.android.*;
import org.apache.commons.io.FileUtils;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.*;
import org.junit.rules.ExpectedException;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static com.thoughtworks.calabash.android.IT.AllActionsIT.EMULATOR;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
//Just run all the test. Can't help with emulator state dependency.
public class AndroidRunnerIT {
@Rule
public ExpectedException expectedException = ExpectedException.none();
private File tempDir;
private File tempAndroidApkPath;
private String packageName;
private AndroidConfiguration configuration;
@Before
public void setUp() throws Exception {
packageName = "com.example.AndroidTestApplication";
tempDir = TestUtils.createTempDir("TestAndroidApps");
tempAndroidApkPath = createTempDirWithProj("AndroidTestApplication.apk", tempDir);
configuration = new AndroidConfiguration();
configuration.setLogsDirectory(new File("logs"));
}
private File createTempDirWithProj(String androidApp, File dir) throws IOException {
File androidAppPath = new File("tests/resources/" + androidApp);
File tempAndroidPath = new File(dir, androidApp);
FileUtils.copyFile(androidAppPath, tempAndroidPath);
return tempAndroidPath;
}
@After
public void tearDown() throws IOException {
FileUtils.deleteDirectory(tempDir);
}
@Test
public void shouldCreateTestServerApk() throws CalabashException, IOException {
AndroidRunner androidRunner = new AndroidRunner(tempAndroidApkPath.getAbsolutePath(), this.configuration);
androidRunner.setup();
File testServersDir = new File(tempDir, "test_servers");
assertTrue(testServersDir.exists());
File[] testServerApk = testServersDir.listFiles(new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".apk");
}
});
assertEquals(1, testServerApk.length);
}
@Ignore("Since the emulator is always running, we can't test this")
@Test
public void shouldThrowExceptionIfSerialOrDeviceNotProvided() throws CalabashException {
expectedException.expect(CalabashException.class);
expectedException.expectMessage("Could not get the device serial, set the serial or devicename in the AndroidConfiguration");
AndroidRunner androidRunner = new AndroidRunner(tempAndroidApkPath.getAbsolutePath(), this.configuration);
androidRunner.setup();
androidRunner.start();
}
@Test
public void shouldThrowExceptionIfSerialIsGivenWhenNotStarted() throws CalabashException {
String serial = "emulator-x";
expectedException.expect(CalabashException.class);
expectedException.expectMessage(String.format("%s not found in the device list, installation failed", serial));
configuration.setSerial(serial);
AndroidRunner androidRunner = new AndroidRunner(tempAndroidApkPath.getAbsolutePath(), configuration);
androidRunner.setup();
androidRunner.start();
}
@Test
public void shouldInstallAppOnDeviceWithName() throws CalabashException {
configuration.setDeviceName("device");
configuration.setShouldReinstallApp(true);
AndroidRunner androidRunner = new AndroidRunner(tempAndroidApkPath.getAbsolutePath(), configuration);
androidRunner.setup();
AndroidApplication application = androidRunner.start();
assertTrue(TestUtils.isAppInstalled(packageName, application.getInstalledOnSerial()));
assertTrue(TestUtils.isMainActivity(application, "MyActivity"));
}
@Test
public void shouldInstallApplicationIfSerialIsProvided() throws CalabashException {
//note: emulator should be launched with serial 'EMULATOR
String serial = EMULATOR;
TestUtils.uninstall(packageName, serial);
configuration.setSerial(serial);
AndroidRunner androidRunner = new AndroidRunner(tempAndroidApkPath.getAbsolutePath(), configuration);
androidRunner.setup();
AndroidApplication application = androidRunner.start();
assertTrue(TestUtils.isAppInstalled(packageName, serial));
assertTrue(TestUtils.isMainActivity(application, "MyActivity"));
}
@Test
public void shouldInstallApplicationAlreadyRunningDevice() throws CalabashException {
//note: emulator with name 'device' should be launched with serial 'EMULATOR'
String device = "device";
String serial = EMULATOR;
TestUtils.uninstall(packageName, serial);
configuration.setDeviceName(device);
AndroidRunner androidRunner = new AndroidRunner(tempAndroidApkPath.getAbsolutePath(), configuration);
androidRunner.setup();
AndroidApplication application = androidRunner.start();
assertTrue(TestUtils.isAppInstalled(packageName, serial));
assertTrue(TestUtils.isMainActivity(application, TestUtils.activityMap.get(TestUtils.ACTIVITY_MAIN)));
}
@Test
public void shouldRetryTimesSpecified() throws Exception {
final List<Integer> times = new ArrayList<Integer>();
final String timeoutMessage = "custom timeout message";
int retryFreqInSec = 5;
int timeoutInSec = 20;
expectedException.expect(OperationTimedoutException.class);
expectedException.expectMessage(new BaseMatcher<String>() {
public boolean matches(Object o) {
return o.toString().contains(timeoutMessage);
}
public void describeTo(Description description) {
}
});
final AndroidApplication application = TestUtils.installAppOnEmulator(EMULATOR, packageName, tempAndroidApkPath);
application.waitFor(new ICondition() {
@Override
public boolean test() throws CalabashException {
times.add(1);
return application.query("button marked:'some foo element'").size() == 1;
}
}, new WaitOptions(timeoutInSec, retryFreqInSec, 0, timeoutMessage, false));
assertEquals(timeoutInSec / retryFreqInSec, times.size());
}
}