├── .gitignore
├── .travis.yml
├── Nakal.png
├── README.md
├── android
└── mask_images
│ ├── htc10.png
│ ├── nexus5.png
│ ├── oneplus.png
│ ├── onepluspng.xcf
│ └── samsung5.png
├── difference_HomeScreen1.png
├── ios
└── mask_images
│ ├── iphone5.png
│ └── iphone6.png
├── iosTest
├── nakal.yaml
├── pom.xml
├── src
├── main
│ └── java
│ │ └── com
│ │ └── nakal
│ │ ├── ScreenExecutor
│ │ ├── Configuration.java
│ │ ├── ExecutorService.java
│ │ ├── NakalAttributeValidator.java
│ │ └── NakalExecutor.java
│ │ ├── capturescreen
│ │ └── ScreenShooter.java
│ │ ├── devices
│ │ ├── AndroidDeviceScreen.java
│ │ ├── DeviceInterface.java
│ │ ├── ViewFactory.java
│ │ └── iOSDeviceScreen.java
│ │ ├── imageutil
│ │ └── ImageUtil.java
│ │ └── utils
│ │ ├── CommandPrompt.java
│ │ ├── InstallMobileDevice.java
│ │ ├── ScreenPaths.java
│ │ ├── Utils.java
│ │ └── YamlReader.java
└── test
│ └── java
│ └── com
│ └── nakal
│ └── screen
│ ├── AndroidTest.java
│ ├── NakalTest.java
│ └── iOSTest.java
└── testImages
├── ActivityScreen.png
├── ActivityScreen1.png
├── actual.png
├── googleActual.png
├── googleExpected.png
└── resized_picture.jpg
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/*
2 | /target/*
3 | ios/actual_images/*
4 | ios/baseline_images/*
5 | android/actual_images/*
6 | android/baseline_images/*
7 | android/native/*
8 | ?img?
9 | Desktop/*
10 | android/web/*
11 | testImages/*
12 | nakal_java.iml
13 | src/main/java/com/nakal/capturescreen/Sample.java
14 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | os:
3 | - linux
4 | sudo: enabled
5 | dist: trusty
6 | before_script:
7 | - rm -rf ImageMagick*
8 | - sudo apt-get install build-essential checkinstall && sudo apt-get build-dep imagemagick -y
9 | - wget http://www.imagemagick.org/download/ImageMagick.tar.gz
10 | - tar xzvf ImageMagick.tar.gz
11 | - cd "$(ls|grep ImageMagick-)"
12 | - pwd
13 | - ./configure && make
14 | - sudo checkinstall -y
15 | - sudo ldconfig /usr/local/lib
16 | - cd ..
17 |
18 | script:
19 | - mvn clean -Dtest=NakalTest test
20 |
--------------------------------------------------------------------------------
/Nakal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/Nakal.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | [](https://travis-ci.org/saikrishna321/nakal_java)
10 |
11 | Automated visual testing of Android/iOS/Web applications.
12 |
13 | 
14 |
15 | Nakal is used to add visual validations in your existing test framework (using appium or selenium-webDriver etc).
16 |
17 | ## Installation
18 | You need to install [imagemagick](http://www.imagemagick.org/script/index.php) on your machine
19 |
20 | Add this to your pom.xml
21 | ```
22 |
23 |
24 | jitpack.io
25 | https://jitpack.io
26 |
27 |
28 |
29 |
30 | com.github.saikrishna321
31 | nakal_java
32 | f4dcb0054e
33 |
34 | ```
35 |
36 | ## Usage
37 |
38 | Following mandatory properties need to be set before running test:
39 | * nakal.platform=ios/android
40 | * nakal.maskimage=image which needs to be considered for masking
41 | * nakal.mode=build/compare
42 |
43 | For Example:
44 |
45 | ```
46 | NakalExecutor nakalExecutor = new NakalExecutor();
47 | //Compare mobile native app screen
48 | @Test
49 | public void compareImagesExecutor(){
50 | Assert.assertTrue(nakalExecutor.nakalExecutorNativeCompare("HomeScreen"));
51 | }
52 | //Compare mobile-web/desktop-browser app screen
53 | @Test
54 | public void compareImagesExecutor(){
55 | Assert.assertTrue(nakalExecutor.nakalExecutorWebCompare(driver, "GoogleScreen"));
56 | }
57 | ```
58 |
59 |
60 | 1. Now, execute your test by passing env variable NAKAL_MODE=build to build the baseline images. All baseline images will be stored in baseline_images folder in current directory
61 |
62 | 2. Once baseline is built, next execution onwards, start using environment variable NAKAL_MODE=compare to compare against baseline.
63 | any difference will be put in the same directory with image file named "difference_current_screen_name.png"
64 |
65 | All mask images should and be stored at /ios/mask-images/fileName.png /android/mask-images/fileName.png.(mask images with transparent background has been created using gimp tool- eg:https://github.com/saikrishna321/nakal_java/tree/master/android/mask_images)
66 | MASKIMAGE value in the env should be the same fileName which is stored under the mask_images(For ex: ./mask_images/nexus5.png and MASKIMAGE="nexus5").
67 |
68 | #Running the tests
69 |
70 | mvn clean -Dtest=AndroidTest test -Dnakal.platform=android -Dnakal.mode=build -Dnakal.maskimage=nexus5 (captures a baseline image)
71 |
72 | mvn clean -Dtest=AndroidTest test -Dnakal.platform=android -Dnakal.mode=compare -Dnakal.maskimage=nexus5 ( compares expected and actual image)
73 |
74 | ## Ignore certain regions of the image
75 |
76 | 1. Create nakal.yaml under the root directory.
77 | 2. You can specify the areas of a screen you want to mask/ignore while comparing in nakal.yaml as below
78 |
79 | ```
80 | nexus5:
81 | HomeScreen: {mask_region_1: [69, 441, 357, 553],mask_region_2: [50, 1600, 371, 1652]}
82 | SearchScreen: {mask_region_1: [66,424,340,478],mask_region_2: [76,524,440,578]}
83 | ```
84 | 3.If you want to set certain threshold while comparing. You can pass option as:
85 |
86 | ```
87 | nakalExecutor.nakalExecutorNativeCompare("HomeScreen",3)
88 | ```
89 |
90 |
91 | Ruby Client
92 | https://github.com/rajdeepv/nakal
93 |
94 |
95 | ## Contributing
96 |
97 | 1. Fork it ( http://github.com//nakal_java/fork )
98 | 2. Create your feature branch (`git checkout -b my-new-feature`)
99 | 3. Commit your changes (`git commit -am 'Add some feature'`)
100 | 4. Push to the branch (`git push origin my-new-feature`)
101 | 5. Create new Pull Request
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/android/mask_images/htc10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/android/mask_images/htc10.png
--------------------------------------------------------------------------------
/android/mask_images/nexus5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/android/mask_images/nexus5.png
--------------------------------------------------------------------------------
/android/mask_images/oneplus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/android/mask_images/oneplus.png
--------------------------------------------------------------------------------
/android/mask_images/onepluspng.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/android/mask_images/onepluspng.xcf
--------------------------------------------------------------------------------
/android/mask_images/samsung5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/android/mask_images/samsung5.png
--------------------------------------------------------------------------------
/difference_HomeScreen1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/difference_HomeScreen1.png
--------------------------------------------------------------------------------
/ios/mask_images/iphone5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/ios/mask_images/iphone5.png
--------------------------------------------------------------------------------
/ios/mask_images/iphone6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/ios/mask_images/iphone6.png
--------------------------------------------------------------------------------
/iosTest:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/iosTest
--------------------------------------------------------------------------------
/nakal.yaml:
--------------------------------------------------------------------------------
1 | common: &common
2 | [17, 71, 850, 174]
3 |
4 | oneplus:
5 | Login: {region_1: *common, region_2:[180, 900, 900, 1008]}
6 |
7 | nexus5:
8 | Login: {mask_region_1: [69, 441, 357, 553],mask_region_2: [50, 1600, 371, 1652]}
9 | SearchScreen: {mask_region_1: [66,424,340,478],mask_region_2: [76,524,440,578]}
10 |
11 | iphone6:
12 | Login: {mask_region_1: [69, 441, 357, 553],mask_region_2: [50, 1600, 371, 1652]}
13 | SearchScreen: {mask_region_1: [66,424,340,478],mask_region_2: [76,524,440,578]}
14 |
15 | fuzzPercentage: 5.00
16 | fullScreen: false
17 |
18 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | nakal_java
8 | nakal_java
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.apache.maven.plugins
14 | maven-compiler-plugin
15 |
16 | 1.8
17 | 1.8
18 |
19 |
20 |
21 |
22 |
23 |
24 | com.github.SrinivasanTarget
25 | DeviceManager
26 | 802c543a22
27 |
28 |
29 | com.github.cosysoft
30 | device-api
31 | 0.9.1
32 |
33 |
34 | junit
35 | junit
36 | 4.12
37 |
38 |
39 |
40 | org.im4java
41 | im4java
42 | 1.4.0
43 |
44 |
45 |
46 | org.yaml
47 | snakeyaml
48 | 1.17
49 |
50 |
51 |
52 |
53 | jitpack.io
54 | https://jitpack.io
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/ScreenExecutor/Configuration.java:
--------------------------------------------------------------------------------
1 | package com.nakal.ScreenExecutor;
2 |
3 | /**
4 | * Created by hiteshs on 2/20/18.
5 | */
6 | public class Configuration {
7 | public static String nakalMode = System.getProperty("nakal.mode", "compare");
8 | public static String platform = System.getProperty("nakal.platform", "android");
9 | public static String maskImage = System.getProperty("nakal.maskimage");
10 | public static String screenshotFolder= System.getProperty("nakal.screenshot.folder");
11 | public static String baseDirectory= System.getProperty("user.dir");
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/ScreenExecutor/ExecutorService.java:
--------------------------------------------------------------------------------
1 | package com.nakal.ScreenExecutor;
2 |
3 | import com.nakal.capturescreen.ScreenShooter;
4 | import com.nakal.imageutil.ImageUtil;
5 | import com.nakal.utils.ScreenPaths;
6 | import org.im4java.core.IM4JavaException;
7 | import java.io.File;
8 | import java.io.FileNotFoundException;
9 | import java.io.IOException;
10 | import static com.nakal.ScreenExecutor.NakalAttributeValidator.isFullScreen;
11 | import static com.nakal.ScreenExecutor.NakalAttributeValidator.isIgnoreRegion;
12 |
13 | /**
14 | * Created by hiteshs on 2/25/18.
15 | */
16 | public class ExecutorService {
17 | private ScreenPaths screenPaths;
18 | private File file;
19 | private ImageUtil imageUtil;
20 | public ExecutorService(){
21 | imageUtil = new ImageUtil();
22 | }
23 |
24 | public boolean compareMode(String baseLineImageName,int threshold)
25 | throws InterruptedException, IOException, IM4JavaException {
26 | screenPaths = new ScreenPaths(baseLineImageName);
27 | String actualImage= screenPaths.getActualImage();
28 | String expectedImage=screenPaths.getExpectedImage();
29 | String diffImage=screenPaths.getDiffImage();
30 | screenCaptureAndMaskIfExist(baseLineImageName,actualImage);
31 | if (threshold >0 && imageUtil.compareImages(expectedImage,
32 | actualImage,diffImage )) {
33 | return true;
34 | }else{
35 | if (imageUtil.compareImages(expectedImage,
36 | actualImage, diffImage,threshold))
37 | return true;
38 | }
39 | mergerDiffHorizontal(expectedImage,actualImage,diffImage);
40 | return false;
41 | }
42 | public boolean buildMode(String baseLineImageName)
43 | throws InterruptedException, IOException, IM4JavaException {
44 | screenPaths = new ScreenPaths(baseLineImageName);
45 | String expectedImage= screenPaths.getExpectedImage();
46 | screenCaptureAndMaskIfExist(baseLineImageName,expectedImage);
47 | return checkIfScreenshotsCaptured(expectedImage);
48 | }
49 | private boolean checkIfScreenshotsCaptured(String image)
50 | throws FileNotFoundException {
51 | File expectedImage= new File(image);
52 | return expectedImage.exists();
53 |
54 | }
55 | private void screenCaptureAndMaskIfExist(String baseLineImageName,
56 | String image)
57 | throws IOException, InterruptedException, IM4JavaException {
58 | captureScreen(image);
59 | applyMaskIfPresent(baseLineImageName,image);
60 |
61 | }
62 | private void applyMaskIfPresent(String baseLineImageName,String image)
63 | throws IOException, InterruptedException, IM4JavaException {
64 | if(isIgnoreRegion(baseLineImageName))
65 | ignoreRegionOnApp(image,baseLineImageName);
66 | if(!isFullScreen())
67 | applyMaskImage(image);
68 | }
69 | private void ignoreRegionOnApp(String image, String baseLineImageName) throws InterruptedException, IOException, IM4JavaException {
70 | imageUtil.maskRegions(image,baseLineImageName);
71 | }
72 |
73 | private void captureScreen(String imagepath){
74 | new ScreenShooter().screenCapture(imagepath);
75 | }
76 | private void applyMaskImage(String maskedRegionImage) throws InterruptedException, IOException, IM4JavaException {
77 | imageUtil.maskImage(maskedRegionImage, screenPaths.getMaskImage());
78 | }
79 | private void mergerDiffHorizontal(String expectedImage,String actualImage,String diffImage)
80 | throws InterruptedException, IOException, IM4JavaException {
81 | imageUtil.mergeImagesHorizontally(expectedImage,
82 | actualImage, diffImage,
83 | screenPaths.getMergedDiffImage());
84 | Thread.sleep(1000);
85 | file = new File(screenPaths.getDiffImage());
86 | file.delete();
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/ScreenExecutor/NakalAttributeValidator.java:
--------------------------------------------------------------------------------
1 | package com.nakal.ScreenExecutor;
2 |
3 | import com.nakal.utils.YamlReader;
4 | import java.io.FileNotFoundException;
5 | import java.util.LinkedHashMap;
6 |
7 | import static com.nakal.ScreenExecutor.Configuration.maskImage;
8 | import static com.nakal.ScreenExecutor.Configuration.nakalMode;
9 | import static com.nakal.ScreenExecutor.Configuration.platform;
10 |
11 | /**
12 | * Created by hiteshs on 2/25/18.
13 | */
14 | public class NakalAttributeValidator {
15 |
16 | public static final String BUILDMODE = "build";
17 | public static final String COMPAREMODE = "compare";
18 | public static final String ANDROID="android";
19 | public static final String CHROME="chrome";
20 | public static final String IOS="ios";
21 | public static final String SAFARI="safari";
22 |
23 |
24 | public static boolean isBuildMode() {
25 | return BUILDMODE.equalsIgnoreCase(nakalMode);
26 | }
27 | public static boolean isCompareMode(){
28 | return COMPAREMODE.equalsIgnoreCase(nakalMode);
29 | }
30 |
31 | public static boolean isAndroid(){
32 | return ANDROID.equalsIgnoreCase(platform);
33 | }
34 | public static boolean isChrome(){
35 | return CHROME.equalsIgnoreCase(platform);
36 | }
37 |
38 | public static boolean isiOS(){
39 | return IOS.equalsIgnoreCase(platform);
40 | }
41 | public static boolean isSafari(){
42 | return SAFARI.equalsIgnoreCase(platform);
43 | }
44 | public static boolean isMaskImagePresent() {
45 | return maskImage!=null && !maskImage.isEmpty();
46 | }
47 |
48 | public static boolean isFullScreen() throws FileNotFoundException {
49 | final String fullScreenAttr="fullScreen";
50 | boolean result= false;
51 | String fullScreen=null;
52 | if(isYamlPresent() && hasAttributeInYaml(fullScreenAttr)) {
53 | fullScreen = YamlReader.getInstance().getValue(fullScreenAttr).toString();
54 | }
55 | return fullScreen!=null && fullScreen.equalsIgnoreCase("true");
56 | }
57 |
58 | public static boolean isIgnoreRegion(String baseLineImageName) throws FileNotFoundException {
59 | Object mask=null;
60 | if(isMaskImagePresent() && isYamlPresent() && hasAttributeInYaml(maskImage)) {
61 | mask = YamlReader.getInstance().getValue(maskImage);
62 | }
63 | return mask!=null && ((LinkedHashMap)mask).get(baseLineImageName)!=null;
64 | }
65 | public static boolean isYamlPresent(){
66 | return YamlReader.getInstance().checkIfYamlFileExists();
67 | }
68 | public static boolean hasAttributeInYaml(String value){
69 | return YamlReader.getInstance().getAllResultsMap().containsKey(value);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/ScreenExecutor/NakalExecutor.java:
--------------------------------------------------------------------------------
1 | package com.nakal.ScreenExecutor;
2 |
3 | import org.im4java.core.IM4JavaException;
4 | import java.io.IOException;
5 | import static com.nakal.ScreenExecutor.NakalAttributeValidator.isBuildMode;
6 |
7 | /**
8 | * Created by saikrisv on 22/02/16.
9 | */
10 | public class NakalExecutor {
11 |
12 | private ExecutorService executorService;
13 |
14 | public NakalExecutor(){
15 | executorService= new ExecutorService();
16 | }
17 |
18 | /**
19 | * @param baseLineImageName
20 | * @return false if actual and expected images are not similar and generate a difference Image
21 | */
22 | public boolean nakalExecutorNativeCompare(String baseLineImageName)
23 | throws InterruptedException, IOException, IM4JavaException {
24 |
25 | return isBuildMode() ? executorService.buildMode(baseLineImageName)
26 | : executorService.compareMode(baseLineImageName,0);
27 | }
28 | /**
29 | * @param baseLineImageName
30 | * @param threshold
31 | * @return false if actual and expected images are not similar and generate a difference Image
32 | */
33 | public boolean nakalExecutorNativeCompare(String baseLineImageName, int threshold)
34 | throws InterruptedException, IOException, IM4JavaException {
35 |
36 | return isBuildMode() ? executorService.buildMode(baseLineImageName)
37 | : executorService.compareMode(baseLineImageName,threshold);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/capturescreen/ScreenShooter.java:
--------------------------------------------------------------------------------
1 | package com.nakal.capturescreen;
2 |
3 | import static com.nakal.ScreenExecutor.Configuration.platform;
4 | import com.nakal.devices.DeviceInterface;
5 | import com.nakal.devices.ViewFactory;
6 |
7 | /**
8 | * Created by saikrisv on 22/02/16.
9 | */
10 | public class ScreenShooter {
11 | private ViewFactory viewFactory = new ViewFactory();
12 |
13 | public void screenCapture(String imagePath) {
14 | DeviceInterface runnerInfo = viewFactory.getMobilePlatform(platform);
15 | runnerInfo.captureScreenShot(imagePath);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/devices/AndroidDeviceScreen.java:
--------------------------------------------------------------------------------
1 | package com.nakal.devices;
2 |
3 | import com.github.cosysoft.device.android.AndroidDevice;
4 | import com.github.cosysoft.device.android.impl.AndroidDeviceStore;
5 | import com.github.cosysoft.device.image.ImageUtils;
6 | import com.nakal.imageutil.ImageUtil;
7 | import com.nakal.utils.Utils;
8 |
9 | import java.awt.image.BufferedImage;
10 | import java.io.File;
11 | import java.util.TreeSet;
12 |
13 | /**
14 | * Created by saikrisv on 22/02/16.
15 | */
16 | public class AndroidDeviceScreen implements DeviceInterface {
17 |
18 | TreeSet devices;
19 | AndroidDevice device;
20 | Utils util = new Utils();
21 | ImageUtil imageUtil = new ImageUtil();
22 | int deviceSize;
23 |
24 | public AndroidDeviceScreen() {
25 | getDeviceConnected();
26 | if (checkIfDevicesAreConnected() == false) {
27 | System.out.println("No Devices Connected.... Quiting the execution");
28 | System.exit(0);
29 | }
30 | }
31 |
32 | public AndroidDevice getDeviceConnected() {
33 | if (System.getenv("UDID") == null || System.getenv("UDID").isEmpty()) {
34 | devices = AndroidDeviceStore.getInstance()
35 | .getDevices();
36 | deviceSize = devices.size();
37 | device = devices.pollFirst();
38 | return device;
39 | } else {
40 | device = AndroidDeviceStore.getInstance().getDeviceBySerial(System.getenv("UDID"));
41 | if(!device.getName().isEmpty()){
42 | deviceSize = 1;
43 | }
44 | return device;
45 | }
46 | }
47 |
48 | public boolean checkIfDevicesAreConnected() {
49 | if (deviceSize > 0) {
50 | return true;
51 | }
52 | return false;
53 | }
54 |
55 | public String getDeviceName() {
56 | return device.getName().toString();
57 | }
58 |
59 |
60 | public void captureScreenShot( String imagePath) {
61 | //util.createDirectory(arg);
62 | String directoryPath=null;
63 | File file = new File(imagePath);
64 | if (file.exists()) {
65 | System.out.println("BaseLine Image already Exists");
66 | } else {
67 | if(!file.isDirectory())
68 | directoryPath=util.getParentDirectoryFromFile(file);
69 | util.createDirectory(directoryPath);
70 | BufferedImage image = device.takeScreenshot();
71 | ImageUtils.writeToFile(image, imagePath);
72 | }
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/devices/DeviceInterface.java:
--------------------------------------------------------------------------------
1 | package com.nakal.devices;
2 |
3 |
4 | /**
5 | * Created by saikrisv on 22/02/16.
6 | */
7 | public interface DeviceInterface {
8 |
9 | public void captureScreenShot(String imagePath);
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/devices/ViewFactory.java:
--------------------------------------------------------------------------------
1 | package com.nakal.devices;
2 | import static com.nakal.ScreenExecutor.NakalAttributeValidator.isAndroid;
3 | import static com.nakal.ScreenExecutor.NakalAttributeValidator.isChrome;
4 | import static com.nakal.ScreenExecutor.NakalAttributeValidator.isiOS;
5 | import static com.nakal.ScreenExecutor.NakalAttributeValidator.isSafari;
6 |
7 |
8 | public class ViewFactory{
9 |
10 | private AndroidDeviceScreen androidFlow;
11 | private iOSDeviceScreen iosFlow;
12 |
13 |
14 | public DeviceInterface getMobilePlatform(String platform) {
15 | if (platform == null) {
16 | return null;
17 | }
18 | if (isAndroid() || isChrome()) {
19 | if (androidFlow == null) {
20 | return androidFlow = new AndroidDeviceScreen();
21 | }
22 | return androidFlow;
23 | }
24 |
25 | if (isiOS() || isSafari()) {
26 | if (iosFlow == null) {
27 | return iosFlow = new iOSDeviceScreen();
28 | }
29 | return iosFlow;
30 |
31 | }
32 | return null;
33 |
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/devices/iOSDeviceScreen.java:
--------------------------------------------------------------------------------
1 | package com.nakal.devices;
2 |
3 | import com.nakal.ScreenExecutor.NakalAttributeValidator;
4 | import com.nakal.utils.CommandPrompt;
5 | import com.nakal.utils.Utils;
6 | import com.thoughtworks.device.Device;
7 | import com.thoughtworks.device.SimulatorManager;
8 | import com.thoughtworks.iOS.IOSManager;
9 | import org.apache.commons.io.FilenameUtils;
10 |
11 |
12 | import java.io.File;
13 | import java.io.IOException;
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | /**
18 | * Created by saikrisv on 22/02/16.
19 | */
20 | public class iOSDeviceScreen implements DeviceInterface {
21 | public ArrayList deviceUDIDiOS = new ArrayList();
22 | CommandPrompt commandPrompt = new CommandPrompt();
23 | SimulatorManager simulatorManager = new SimulatorManager();
24 | Utils utils = new Utils();
25 |
26 | public ArrayList getIOSUDID() throws IOException {
27 | List allAvailableDevices = new IOSManager().getDevices();
28 | allAvailableDevices.forEach(iosudid -> {
29 | deviceUDIDiOS.add(iosudid.getUdid());
30 | });
31 | return deviceUDIDiOS;
32 | }
33 |
34 | public void captureScreenShot(String imagePath){
35 | String directoryPath=null;
36 | File file = new File(imagePath);
37 | String fileName= file.getName();
38 | if(NakalAttributeValidator.isBuildMode() && file.exists()){
39 | System.out.println("BaseLine Image already Exists");
40 | }else{
41 | if(!file.isDirectory())
42 | directoryPath=utils.getParentDirectoryFromFile(file);
43 | utils.createDirectory(directoryPath);
44 | try {
45 | if(getIOSUDID().size() != 0) {
46 | commandPrompt.runCommand("idevicescreenshot " + imagePath);
47 | } else if(simulatorManager.getAllBootedSimulators("iOS").size() != 0) {
48 | fileName= FilenameUtils.removeExtension(fileName);
49 | String UDID = simulatorManager.getAllBootedSimulators("iOS").get(0).getUdid();
50 | simulatorManager.captureScreenshot(UDID, fileName, directoryPath, "png");
51 | } else {
52 | System.exit(0);
53 | }
54 | } catch (IOException e) {
55 | e.printStackTrace();
56 | } catch (InterruptedException e) {
57 | e.printStackTrace();
58 | }
59 | }
60 |
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/imageutil/ImageUtil.java:
--------------------------------------------------------------------------------
1 | package com.nakal.imageutil;
2 |
3 | import static com.nakal.ScreenExecutor.NakalAttributeValidator.hasAttributeInYaml;
4 | import static com.nakal.ScreenExecutor.NakalAttributeValidator.isYamlPresent;
5 |
6 | import com.nakal.utils.YamlReader;
7 | import org.im4java.core.*;
8 | import org.im4java.process.ArrayListErrorConsumer;
9 |
10 | import javax.imageio.ImageIO;
11 | import java.awt.image.BufferedImage;
12 | import java.io.*;
13 |
14 |
15 | /**
16 | * Created by saikrisv on 22/02/16.
17 | */
18 | public class ImageUtil {
19 | ArrayListErrorConsumer arrayListErrorConsumer = new ArrayListErrorConsumer();
20 |
21 | /**
22 | * @param actualImage
23 | * @param expectedImage
24 | * @param diffImage
25 | * @return
26 | * @throws IOException
27 | * @throws InterruptedException
28 | * @throws IM4JavaException
29 | */
30 | public boolean compareImages(String actualImage, String expectedImage, String diffImage)
31 | throws IOException, InterruptedException, IM4JavaException {
32 |
33 | IMOps cmpOp = new IMOperation();
34 | cmpOp.metric("AE");
35 | cmpOp.fuzz(getFuzzValue(), true);
36 | cmpOp.addImage();
37 | cmpOp.addImage();
38 | cmpOp.addImage();
39 | CompareCmd compare = new CompareCmd();
40 | compare.setErrorConsumer(arrayListErrorConsumer);
41 | try {
42 | compare.run(cmpOp, actualImage, expectedImage);
43 | System.out.println("**Image Is Same**");
44 | return true;
45 | } catch (Throwable e) {
46 | try {
47 | compare.run(cmpOp, actualImage, expectedImage, diffImage);
48 |
49 | } catch (Throwable e1) {
50 | System.out.println(
51 | "Total Pixel Difference of the Images:::" + arrayListErrorConsumer.getOutput()
52 | .get(0));
53 | }
54 | return false;
55 | }
56 |
57 | }
58 |
59 |
60 | /**
61 | * returns true if the images are similar
62 | * returns false if the images are not identical
63 | *
64 | * @param actualImage
65 | * @param expectedImage
66 | * @return
67 | * @throws IOException
68 | * @throws InterruptedException
69 | * @throws IM4JavaException
70 | */
71 | public boolean compareImages(String actualImage, String expectedImage)
72 | throws IOException, InterruptedException, IM4JavaException {
73 | IMOps cmpOp = new IMOperation();
74 | cmpOp.metric("AE");
75 | cmpOp.fuzz(getFuzzValue(), true);
76 | cmpOp.addImage();
77 | cmpOp.addImage();
78 | cmpOp.addImage();
79 | CompareCmd compare = new CompareCmd();
80 | compare.setErrorConsumer(arrayListErrorConsumer);
81 | try {
82 | compare.run(cmpOp, actualImage, expectedImage);
83 | return true;
84 | } catch (Throwable e) {
85 | return false;
86 | }
87 | }
88 |
89 | /**
90 | * @param actualImage actualImagePath
91 | * @param value set the ignore % of image pixels
92 | * @throws IOException
93 | */
94 | public boolean compareImages(String expectedImage, String actualImage, String diffImage, int value)
95 | throws IOException, IM4JavaException, InterruptedException {
96 | compareImages(actualImage, expectedImage, diffImage);
97 | long totalImagePixel = getCompleteImagePixel(actualImage);
98 | if (arrayListErrorConsumer.getOutput().get(0).contains("+") == true) {
99 | return false;
100 | } else {
101 | long totalPixelDifferne = Integer.parseInt(arrayListErrorConsumer.getOutput().get(0));
102 | double c = ((double) totalPixelDifferne / totalImagePixel) * 100;
103 | long finalPercentageDifference = Math.round(c);
104 | System.out.println("Difference in the images is ::" + finalPercentageDifference + "%");
105 | try {
106 | if (finalPercentageDifference <= value) {
107 | return true;
108 | }
109 | } catch (NumberFormatException e) {
110 | }
111 | return false;
112 | }
113 | }
114 |
115 | /**
116 | * @param actualImage
117 | * @param maskImage
118 | * @throws IOException
119 | * @throws InterruptedException
120 | * @throws IM4JavaException
121 | */
122 |
123 | public void maskImage(String actualImage, String maskImage)
124 | throws IOException, InterruptedException, IM4JavaException {
125 | String maskedImage=actualImage;
126 | IMOperation op = new IMOperation();
127 | op.addImage(actualImage);
128 | op.addImage(maskImage);
129 | op.alpha("on");
130 | op.compose("DstOut");
131 | op.composite();
132 | op.addImage(maskedImage);
133 | ConvertCmd convert = new ConvertCmd();
134 | convert.run(op);
135 | }
136 |
137 | /**
138 | * @throws InterruptedException
139 | * @throws IOException
140 | * @throws IM4JavaException
141 | */
142 | public void mergeImagesHorizontally(String expected, String actual, String diffImage,
143 | String mergedImage) throws InterruptedException, IOException, IM4JavaException {
144 | ConvertCmd cmd1 = new ConvertCmd();
145 | IMOperation op1 = new IMOperation();
146 | op1.addImage(expected); // source file
147 | op1.addImage(actual); // destination file file
148 | op1.addImage(diffImage);
149 | //op1.resize(1024,576);
150 | op1.p_append();
151 | op1.addImage(mergedImage);
152 | cmd1.run(op1);
153 | }
154 |
155 |
156 | public int getCompleteImagePixel(String actualImage) throws IOException {
157 | BufferedImage readImage = null;
158 | readImage = ImageIO.read(new File(actualImage));
159 | int h = readImage.getHeight();
160 | int w = readImage.getWidth();
161 | return h * w;
162 | }
163 |
164 | public void maskRegions(String imageToMaskRegion, String screenName)
165 | throws InterruptedException, IOException, IM4JavaException {
166 | drawRectangleToIgnore(imageToMaskRegion, screenName);
167 | }
168 |
169 | private void drawRectangleToIgnore(String imageToMaskRegion,
170 | String screenName) throws IOException, InterruptedException, IM4JavaException {
171 | ConvertCmd reg = new ConvertCmd();
172 | IMOperation rep_op = new IMOperation();
173 | rep_op.addImage(imageToMaskRegion);
174 | rep_op.fill("Blue");
175 | rep_op.draw(YamlReader.getInstance().fetchValueFromYaml(screenName));
176 | rep_op.addImage(imageToMaskRegion);
177 | reg.run(rep_op);
178 | }
179 | public static Double getFuzzValue() throws FileNotFoundException {
180 | Double fuzz=5.0;
181 | if(isYamlPresent() && hasAttributeInYaml("fuzzPercentage")) {
182 | fuzz = new Double(YamlReader.getInstance().getValue("fuzzPercentage").toString());
183 | }
184 | return fuzz;
185 | }
186 |
187 | }
188 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/utils/CommandPrompt.java:
--------------------------------------------------------------------------------
1 | package com.nakal.utils;
2 |
3 | /**
4 | * Command Prompt - this class contains method to run windows and mac commands
5 | */
6 |
7 | import java.io.BufferedReader;
8 | import java.io.IOException;
9 | import java.io.InputStreamReader;
10 |
11 | public class CommandPrompt {
12 |
13 | static Process p;
14 | ProcessBuilder builder;
15 |
16 | /**
17 | * This method run command on windows and mac
18 | *
19 | * @param command
20 | * to run
21 | */
22 | public String runCommand(String command) throws InterruptedException, IOException {
23 | p = Runtime.getRuntime().exec(command);
24 | // get std output
25 | BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
26 | String line = "";
27 | String allLine = "";
28 | int i = 1;
29 | while ((line = r.readLine()) != null) {
30 | /* if (line.isEmpty()) {
31 | break;
32 | }*/
33 | allLine = allLine + "" + line + "\n";
34 | if (line.contains("Console LogLevel: debug") && line.contains("Complete"))
35 | break;
36 | i++;
37 | }
38 | return allLine;
39 |
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/utils/InstallMobileDevice.java:
--------------------------------------------------------------------------------
1 | package com.nakal.utils;
2 |
3 | import java.io.IOException;
4 |
5 | /**
6 | * Created by saikrisv on 22/02/16.
7 | */
8 | public class InstallMobileDevice {
9 |
10 | CommandPrompt cmd = new CommandPrompt();
11 | public void checkIfMobileDeviceApiIsInstalled() throws InterruptedException, IOException {
12 | boolean checkMobileDevice = cmd.runCommand("brew list").contains("ideviceinstaller");
13 | if (checkMobileDevice) {
14 | System.out.println("iDeviceInstaller already exists");
15 | } else {
16 | System.out.println("Brewing mobileDevice API....");
17 | cmd.runCommand("brew install ideviceinstaller");
18 | }
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/utils/ScreenPaths.java:
--------------------------------------------------------------------------------
1 | package com.nakal.utils;
2 |
3 |
4 | import com.nakal.ScreenExecutor.Configuration;
5 |
6 | import java.io.File;
7 |
8 | import static com.nakal.ScreenExecutor.Configuration.baseDirectory;
9 | import static com.nakal.ScreenExecutor.Configuration.screenshotFolder;
10 | import static com.nakal.ScreenExecutor.Configuration.platform;
11 |
12 | /**
13 | * Created by saikrisv on 04/07/16.
14 | */
15 | public class ScreenPaths {
16 |
17 | private String customPath;
18 | private String expectedImage;
19 | private String maskImage;
20 | private String actualImage;
21 |
22 | private String mergedDiffImage;
23 | private String diffImage;
24 |
25 |
26 | public ScreenPaths(String baseLineImageName) {
27 | if (screenshotFolder!=null) {
28 | customPath = screenshotFolder
29 | + File.separator + platform;
30 | } else {
31 | customPath = platform;
32 | }
33 | init(baseLineImageName);
34 | }
35 |
36 |
37 | private void init(String baseLineImageName){
38 |
39 | setActualImage(baseLineImageName);
40 | setExpectedImage(baseLineImageName);
41 | setDiffImage(baseLineImageName);
42 | setMaskImage();
43 | setMergedDiffImage(baseLineImageName);
44 | }
45 |
46 | private void setExpectedImage(String baseLineImageName) {
47 | this.expectedImage =
48 | getBasePathForBaseLine(baseLineImageName) + baseLineImageName
49 | + ".png";
50 | }
51 |
52 | private void setMaskImage() {
53 | this.maskImage =
54 | baseDirectory + File.separator + platform + "/mask_images/"
55 | + Configuration.maskImage + ".png";
56 | }
57 |
58 | private void setMergedDiffImage(String baseLineImageName) {
59 | this.mergedDiffImage =
60 | getBasePathForTargetActualImage(baseLineImageName)+ "difference_"
61 | + baseLineImageName + ".png";
62 |
63 | }
64 |
65 | private void setDiffImage(String baseLineImageName) {
66 | this.diffImage =
67 | getBasePathForTargetActualImage(baseLineImageName)+ "diff_"
68 | + baseLineImageName + ".png";
69 |
70 | }
71 |
72 | private void setActualImage(String baseLineImageName) {
73 | this.actualImage =
74 | getBasePathForTargetActualImage(baseLineImageName)
75 | + baseLineImageName + ".png";
76 | }
77 |
78 |
79 | private String getBasePathForTargetActualImage(String baseLineImageName){
80 | return baseDirectory + "/target/" + customPath
81 | + "/actual_images/" + baseLineImageName + File.separator;
82 | }
83 |
84 | private String getBasePathForBaseLine(String baseLineImageName){
85 | return baseDirectory + File.separator + customPath
86 | + "/baseline_images/" + baseLineImageName + File.separator;
87 | }
88 |
89 | public String getCustomPath() {
90 | return customPath;
91 | }
92 |
93 | public String getExpectedImage() {
94 | return expectedImage;
95 | }
96 |
97 | public String getMaskImage() {
98 | return maskImage;
99 | }
100 |
101 | public String getActualImage() {
102 | return actualImage;
103 | }
104 |
105 | public String getMergedDiffImage() {
106 | return mergedDiffImage;
107 | }
108 |
109 | public String getDiffImage() {
110 | return diffImage;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/utils/Utils.java:
--------------------------------------------------------------------------------
1 | package com.nakal.utils;
2 |
3 | import org.apache.commons.io.FileUtils;
4 |
5 | import java.io.File;
6 | import java.io.IOException;
7 |
8 | /**
9 | * Created by saikrisv on 22/02/16.
10 | */
11 | public class Utils {
12 |
13 | public void createDirectory(String directoryPath) {
14 |
15 | deleteDirectory(directoryPath);
16 | File file = new File(directoryPath);
17 | if (!file.exists()) {
18 | if (file.mkdirs()) {
19 | System.out.println("BaseLine Image Directory is created!");
20 | } else {
21 | System.out.println("Failed to create BaseLine image directory!");
22 | }
23 | }
24 | }
25 |
26 | private void deleteDirectory(String path) {
27 |
28 | File file = new File(path);
29 | if (file.isDirectory()) {
30 | System.out.println("Deleting Directory :" + path);
31 | try {
32 | FileUtils.deleteDirectory(new File(path)); //deletes the whole folder
33 | } catch (IOException e) {
34 | // TODO Auto-generated catch block
35 | e.printStackTrace();
36 | }
37 | } else {
38 | System.out.println("Deleting File :" + path);
39 | //it is a simple file. Proceed for deletion
40 | file.delete();
41 | }
42 |
43 | }
44 |
45 | public String getParentDirectoryFromFile(File file) {
46 | return file.getParent();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/nakal/utils/YamlReader.java:
--------------------------------------------------------------------------------
1 | package com.nakal.utils;
2 |
3 | import org.yaml.snakeyaml.Yaml;
4 |
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.FileNotFoundException;
8 | import java.io.InputStream;
9 | import java.util.LinkedHashMap;
10 | import java.util.Map;
11 | import java.util.Set;
12 |
13 | import static com.nakal.ScreenExecutor.Configuration.baseDirectory;
14 | import static com.nakal.ScreenExecutor.Configuration.maskImage;
15 |
16 | /**
17 | * Created by shridhk on 12/20/17.
18 | */
19 | public class YamlReader {
20 | static Map result;
21 |
22 | private static YamlReader yamlReader;
23 |
24 | private YamlReader() {
25 | final String fileName = getPath();
26 | Yaml yaml = new Yaml();
27 | InputStream yamlParams = null;
28 | try {
29 | yamlParams = new FileInputStream(new File(fileName));
30 | } catch (FileNotFoundException e) {
31 | e.printStackTrace();
32 | }
33 | result = (Map) yaml.load(yamlParams);
34 | }
35 |
36 | public static YamlReader getInstance() {
37 | if (yamlReader == null) {
38 | yamlReader = new YamlReader();
39 | }
40 | return yamlReader;
41 | }
42 |
43 | private static String getPath() {
44 | return baseDirectory + "/nakal.yaml";
45 | }
46 |
47 | public static Object getValue(String key) {
48 | return result.get(key);
49 | }
50 |
51 | public static Map getAllResultsMap() {
52 | return result;
53 | }
54 |
55 | public static boolean checkIfYamlFileExists() {
56 | final String fileName = getPath();
57 | File file = new File(fileName);
58 | return file.exists();
59 | }
60 |
61 | public String fetchValueFromYaml(String screenName) throws FileNotFoundException {
62 | Set mask_region =
63 | ((LinkedHashMap) ((LinkedHashMap) YamlReader.getInstance().getValue(maskImage))
64 | .get(screenName)).entrySet();
65 | String maskingRegions = "";
66 | for (Object regions : mask_region) {
67 | maskingRegions =
68 | maskingRegions + " rectangle " + regions.toString().split("=")[1].toString()
69 | .replace("[", "").replace("]", "").trim();
70 | }
71 | return maskingRegions;
72 | }
73 |
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/test/java/com/nakal/screen/AndroidTest.java:
--------------------------------------------------------------------------------
1 | package com.nakal.screen;
2 |
3 | import com.nakal.ScreenExecutor.NakalExecutor;
4 | import com.nakal.imageutil.ImageUtil;
5 | import org.im4java.core.IM4JavaException;
6 | import org.junit.Assert;
7 | import org.junit.Test;
8 | import java.io.IOException;
9 |
10 | /**
11 | * Created by saikrisv on 22/02/16.
12 | */
13 | public class AndroidTest {
14 |
15 | NakalExecutor nakalExecutor = new NakalExecutor();
16 |
17 | @Test
18 | public void compareImagesExecutor() throws InterruptedException, IOException, IM4JavaException {
19 | Assert.assertTrue(nakalExecutor.nakalExecutorNativeCompare("Login",5));
20 | }
21 |
22 | @Test
23 | public void compareImagesWithPixelDifference()
24 | throws InterruptedException, IOException, IM4JavaException {
25 | Assert.assertTrue(nakalExecutor.nakalExecutorNativeCompare("ActivityScreen",3));
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/test/java/com/nakal/screen/NakalTest.java:
--------------------------------------------------------------------------------
1 | package com.nakal.screen;
2 |
3 | import com.nakal.imageutil.ImageUtil;
4 | import org.im4java.core.IM4JavaException;
5 | import org.junit.Assert;
6 | import org.junit.Test;
7 |
8 | import java.io.IOException;
9 |
10 | /**
11 | * Created by hiteshs on 3/2/18.
12 | */
13 | public class NakalTest {
14 |
15 | ImageUtil imageUtil = new ImageUtil();
16 |
17 | @Test
18 | public void verifyImagesAreSimilar() throws InterruptedException, IOException, IM4JavaException {
19 | boolean imagePixels = imageUtil.compareImages(System.getProperty("user.dir") + "/testImages/ActivityScreen.png",
20 | System.getProperty("user.dir") + "/testImages/ActivityScreen.png");
21 | Assert.assertTrue(imagePixels);
22 |
23 | }
24 |
25 | @Test
26 | public void verifyImagesAreNotSimilarAndCreatDiffImage() throws InterruptedException, IOException, IM4JavaException {
27 | boolean imagePixels = imageUtil.compareImages(System.getProperty("user.dir") + "/testImages/ActivityScreen.png",
28 | System.getProperty("user.dir") + "/testImages/ActivityScreen1.png",
29 | System.getProperty("user.dir") + "/testImages/ActivityDifferentImage.png");
30 | Assert.assertFalse(imagePixels);
31 | }
32 |
33 | @Test
34 | public void mergeImagesHorizontally() throws InterruptedException, IOException, IM4JavaException {
35 | imageUtil.mergeImagesHorizontally(System.getProperty("user.dir") + "/testImages/ActivityScreen.png",
36 | System.getProperty("user.dir") + "/testImages/ActivityScreen1.png",
37 | System.getProperty("user.dir") + "/testImages/ActivityDifferentImage.png",
38 | System.getProperty("user.dir") + "/testImages/MergedImage.png");
39 | }
40 |
41 |
42 | @Test
43 | public void verifyThresholdDifference() throws InterruptedException, IOException, IM4JavaException {
44 | imageUtil.compareImages(System.getProperty("user.dir") + "/testImages/googleActual.png",
45 | System.getProperty("user.dir") + "/testImages/googleExpected.png",
46 | System.getProperty("user.dir") + "/testImages/percentageDiff.png",2);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/test/java/com/nakal/screen/iOSTest.java:
--------------------------------------------------------------------------------
1 | package com.nakal.screen;
2 |
3 | import com.nakal.ScreenExecutor.NakalExecutor;
4 | import org.im4java.core.IM4JavaException;
5 | import org.junit.Assert;
6 | import org.junit.Test;
7 |
8 | import java.io.IOException;
9 |
10 | /**
11 | * Created by saikrisv on 22/02/16.
12 | */
13 | public class iOSTest {
14 |
15 | NakalExecutor nakalExecutor = new NakalExecutor();
16 |
17 | @Test
18 | public void captureScreenShotFromDevice()
19 | throws InterruptedException, IOException, IM4JavaException {
20 | nakalExecutor.nakalExecutorNativeCompare("Login");
21 | }
22 |
23 | @Test
24 | public void compareImagesWithPixelDifference()
25 | throws InterruptedException, IOException, IM4JavaException {
26 | Assert.assertTrue(nakalExecutor.nakalExecutorNativeCompare("ActivityScreen",3));
27 | }
28 | }
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/testImages/ActivityScreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/testImages/ActivityScreen.png
--------------------------------------------------------------------------------
/testImages/ActivityScreen1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/testImages/ActivityScreen1.png
--------------------------------------------------------------------------------
/testImages/actual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/testImages/actual.png
--------------------------------------------------------------------------------
/testImages/googleActual.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/testImages/googleActual.png
--------------------------------------------------------------------------------
/testImages/googleExpected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/testImages/googleExpected.png
--------------------------------------------------------------------------------
/testImages/resized_picture.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saikrishna321/nakal_java/d1685d640d50c8b2d4074a3f839685edce3b7f1b/testImages/resized_picture.jpg
--------------------------------------------------------------------------------