Hi guys,
Today I will post the code that I’ve improved to make the Cucumber take the screenshots and spoon use them:
Your helper class:
public void takeScreenshot() { String[] formattedInfo = treatFeatureScenarioStrings(); mFeature = formattedInfo[0]; mScenario = formattedInfo[1]; if (mScenario == null) { throw new ScreenshotException("Error taking screenshot: I'm missing a valid test mScenario to attach the screenshot to"); } mSolo.waitForActivity(mSolo.getCurrentActivity().getLocalClassName()); String tag = Thread.currentThread().getStackTrace()[3].getMethodName(); ScreenshotTaker.screenshot(mSolo.getCurrentActivity(), mSolo.getCurrentViews(), tag, mFeature, mScenario); }
/* This method is formatting the mScenario info to get the mFeature and mScenario namesand format them for the same format which Spoon is using. The name mFeature needs to follow this pattern: Feature Test something and mScenario: Scenario Test something - First letter of the first word of mScenario in uppercase, the same for mFeature - All the others letters need to be in lowercase - Before mFeature's name put the word Feature and before mScenario's name put the word Scenario - When Scenario Outline the prefix of the scenario needs to be diferent */ private String[] treatFeatureScenarioStrings() { String mFeatureCap = mScenarioInfo[0].substring(0, 1).toUpperCase() + mScenarioInfo[0].substring(1); String mScenarioCap = mScenarioInfo[1].substring(0, 1).toUpperCase() + mScenarioInfo[1].substring(1); mFeature = "Feature " + mFeatureCap.replace("-", " "); mScenario = "Scenario " + mScenarioCap.replace("-", " "); if (mScenarioInfo.length > 2) { mScenario = "Scenario Outline " + mScenarioCap.replace("-", " "); } return new String[]{mFeature, mScenario}; } private static class ScreenshotException extends RuntimeException { ScreenshotException(final String message) { super(message); } }
ScreenshotTaker class:
import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.os.Build; import android.os.Environment; import android.util.Log; import android.view.View;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.Set;
import timber.log.Timber;
import static org.assertj.core.api.Assertions.assertThat;
public abstract class ScreenshotTaker {
private static Set<String> mClearedOutputDirectories = new HashSet(); static final String NAME_SEPARATOR = "_"; static final String SPOON_SCREENSHOTS = "spoon-screenshots";
public static File screenshot(Activity activity, ArrayList<View> views , String tag, String testClassName, String testMethodName) { return screenshot(activity, getRecentDecorView(views), tag, testClassName, testMethodName); }
public static File screenshot(Activity activity, View view, String tag, String testClassName, String testMethodName) { try { if (view == null) { File viewFile = null; Log.e("Spoon", "Unable to take screenshot of this view, because it is null."); return viewFile; }
File parentFolder = obtainScreenshotDirectory (activity.getApplicationContext(), testClassName, testMethodName); assertThat(parentFolder).isNotNull(); final String screenshotName = System.currentTimeMillis() + NAME_SEPARATOR + tag + ".png"; File screenshotFile = new File(parentFolder, screenshotName);
getBitmapOfView(view, activity, screenshotFile); Log.d("Spoon", "Captured screenshot \'" + tag + "\'."); return screenshotFile; } catch (Exception var7) { return null; }
}
private static void getBitmapOfView(final View view, Activity activity , final File screenShotFile) { activity.runOnUiThread(new Runnable() { @Override public void run() { view.destroyDrawingCache(); view.buildDrawingCache(false); Bitmap orig = view.getDrawingCache(); android.graphics.Bitmap.Config config = null; if (orig == null) { Timber.e("Bitmap is null"); } else { config = orig.getConfig(); if (config == null) { config = android.graphics.Bitmap.Config.ARGB_8888; } Bitmap mBitmap = orig.copy(config, false);
FileOutputStream mFileOutput = null; try { mFileOutput = new FileOutputStream(screenShotFile); if (mFileOutput != null) { mBitmap.compress(Bitmap.CompressFormat.PNG, 100, mFileOutput); screenShotFile.setReadable(true, false); } mFileOutput.flush(); mFileOutput.close(); } catch (IOException e) { e.printStackTrace(); } orig.recycle(); view.destroyDrawingCache(); } } }); }
private static File obtainScreenshotDirectory(Context context, String testClassName, String testMethodName) { return filesDirectory(context, SPOON_SCREENSHOTS, testClassName, testMethodName); }
private static File filesDirectory(Context context, String directoryType, String testClassName, String testMethodName) { File directory = null; if (Build.VERSION.SDK_INT >= 21) { directory = new File(Environment.getExternalStorageDirectory(), "app_" + directoryType); } else { directory = context.getDir(directoryType, 1); }
if (!mClearedOutputDirectories.contains(directoryType)) { deletePath(directory, false); mClearedOutputDirectories.add(directoryType); }
File dirClass1 = new File(directory, testClassName); File dirMethod = new File(dirClass1, testMethodName);
if (!dirMethod.exists()) { createDir(dirMethod); }
return dirMethod; }
private static void createDir(File dir) { File parent = dir.getParentFile(); if (!parent.exists()) { createDir(parent); }
if (!dir.exists() && !dir.mkdirs()) { Timber.e("Unable to create output dir: " + dir.getAbsolutePath()); } else { Chmod.chmodPlusRWX(dir); } }
private static void deletePath(File path, boolean inclusive) { if (path.isDirectory()) { File[] children = path.listFiles(); if (children != null) { File[] arr$ = children; int len$ = children.length;
for (int i$ = 0; i$ < len$; ++i$) { File child = arr$[i$]; deletePath(child, true); } } }
if (inclusive) { path.delete(); }
}
/** * Returns the most recent DecorView * * @param views the views to check * @return the most recent DecorView */
public static final View getRecentDecorView(ArrayList<View> views) { if (views == null) { Timber.e("Error in getRecentDecorView: 0 views passed in."); return null; }
final View[] decorViews = new View[views.size()]; int i = 0; View view;
for (int j = 0; j < views.size(); j++) { view = views.get(j); if (view != null && view.getClass().getName() .equals("com.android.internal.policy.impl.PhoneWindow$DecorView")) { decorViews[i] = view; i++; } } return getRecentContainer(decorViews); }
/** * Returns the most recent view container * * @param views the views to check * @return the most recent view container */
private static final View getRecentContainer(View[] views) { View container = null; long drawingTime = 0; View view;
for (int i = 0; i < views.length; i++) { view = views[i]; if (view != null && view.isShown() && view.hasWindowFocus() && view.getDrawingTime() > drawingTime) { container = view; drawingTime = view.getDrawingTime(); } } return container; } }
Please fell free to improve if you have any comment and suggestion it would be great !
Thank you guys, see you next week !