View Javadoc

1   package com.atlassian.selenium.visualcomparison;
2   
3   import com.atlassian.selenium.visualcomparison.utils.BoundingBox;
4   import com.atlassian.selenium.visualcomparison.utils.ScreenResolution;
5   import com.atlassian.selenium.visualcomparison.utils.Screenshot;
6   import com.atlassian.selenium.visualcomparison.utils.ScreenshotDiff;
7   import junit.framework.Assert;
8   
9   import java.io.File;
10  import java.io.FileFilter;
11  import java.io.IOException;
12  import java.util.ArrayList;
13  import java.util.Collections;
14  import java.util.List;
15  import java.util.Map;
16  
17  public class VisualComparer
18  {
19      private ScreenResolution[] resolutions = new ScreenResolution[]
20              {
21                      new ScreenResolution(1280, 1024)
22              };
23      private VisualComparableClient client;
24      private boolean refreshAfterResize = false;
25      private boolean reportingEnabled = false;
26      private String reportOutputPath;
27      private String imageSubDirName = "report_images";
28      private String tempPath = System.getProperty("java.io.tmpdir");
29      private Map<String, String> uiStringReplacements = null;
30      private long waitforJQueryTimeout = 0;
31      private List<BoundingBox> ignoreAreas = null;
32      private boolean ignoreSingleLineDiffs = false;
33  
34      public long getWaitforJQueryTimeout() {
35          return waitforJQueryTimeout;
36      }
37  
38      public void setWaitforJQueryTimeout(long waitforJQueryTimeout) {
39          this.waitforJQueryTimeout = waitforJQueryTimeout;
40      }
41  
42      public VisualComparer(VisualComparableClient client)
43      {
44          this.client = client;
45      }
46  
47      public void setScreenResolutions(ScreenResolution[] resolutions)
48      {
49          this.resolutions = resolutions;
50      }
51  
52      public ScreenResolution[] getScreenResolutions()
53      {
54          return this.resolutions;
55      }
56  
57      public void setRefreshAfterResize(boolean refreshAfterResize)
58      {
59          this.refreshAfterResize = refreshAfterResize;
60      }
61  
62      public boolean getRefreshAfterResize()
63      {
64          return this.refreshAfterResize;
65      }
66  
67      public void setUIStringReplacements(Map<String,String> uiStringReplacements)
68      {
69          this.uiStringReplacements = uiStringReplacements;
70      }
71  
72      public Map<String,String> getUIStringReplacements()
73      {
74          return this.uiStringReplacements;
75      }
76  
77      public void enableReportGeneration(String reportOutputPath)
78      {
79          this.reportingEnabled = true;
80          this.reportOutputPath = reportOutputPath;
81          
82          File file = new File(reportOutputPath + "/" + imageSubDirName);
83          file.mkdirs();
84      }
85  
86      public void disableReportGeneration()
87      {
88          this.reportingEnabled = false;
89      }
90  
91      public void setTempPath(String tempPath)
92      {
93          File file = new File(tempPath);
94          file.mkdirs();
95          this.tempPath = tempPath;
96      }
97  
98      public String getTempPath()
99      {
100         return this.tempPath;
101     }
102 
103 
104     public List<BoundingBox> getIgnoreAreas()
105     {
106         return ignoreAreas;
107     }
108 
109     public boolean getIgnoreSingleLineDiffs()
110     {
111         return ignoreSingleLineDiffs;
112     }
113 
114     public void setIgnoreSingleLineDiffs(boolean ignoreSingleLineDiffs)
115     {
116         this.ignoreSingleLineDiffs = ignoreSingleLineDiffs;
117     }
118 
119     public void setIgnoreAreas(List<BoundingBox> ignoreAreas)
120     {
121         this.ignoreAreas = ignoreAreas;
122     }
123 
124     public void assertUIMatches(String id, String baselineImagePath)
125     {
126         try
127         {
128             Assert.assertTrue("Screenshots were not equal", uiMatches(id, baselineImagePath));
129         }
130         catch (Exception e)
131         {
132             throw new RuntimeException(e);
133         }
134     }
135 
136     public boolean uiMatches(final String id, final String baselineImagePath) throws Exception
137     {
138         ArrayList<Screenshot> currentScreenshots = takeScreenshots(id);
139         ArrayList<Screenshot> baselineScreenshots = loadBaselineScreenshots(id, baselineImagePath);
140         return compareScreenshots(baselineScreenshots, currentScreenshots);
141     }
142 
143     public ArrayList<Screenshot> takeScreenshots(final String id) throws IOException
144     {
145         // Capture a series of screenshots in all the valid screen resolutions.
146         ArrayList<Screenshot> screenshots = new ArrayList<Screenshot>();
147         for (ScreenResolution res : resolutions)
148         {
149             res.resize(client, refreshAfterResize);
150             if (waitforJQueryTimeout > 0)
151             {
152                 if (!client.waitForJQuery (waitforJQueryTimeout))
153                 {
154                     Assert.fail("Timed out while waiting for jQuery to complete");
155                 }
156             }
157             if (uiStringReplacements != null)
158             {
159                 // Remove strings from the UI that we are expecting will change
160                 // (such as the build number in the JIRA footer)
161                 for (String key : uiStringReplacements.keySet())
162                 {
163                     replaceUIHtml(key, uiStringReplacements.get(key));
164                 }
165             }
166             screenshots.add(new Screenshot(client, id, tempPath, res));
167         }
168         Collections.sort(screenshots);
169         return screenshots;
170     }
171 
172     public ArrayList<Screenshot> loadBaselineScreenshots(final String id, final String baselineImagePath) throws IOException
173     {
174         File screenshotDir = new File(baselineImagePath);
175         File[] screenshotFiles = screenshotDir.listFiles(
176                 new FileFilter()
177                 {
178                     public boolean accept(File file) { return file.getName().startsWith(id);}
179                 });
180 
181         ArrayList<Screenshot> screenshots = new ArrayList<Screenshot>();
182         for (File screenshotFile : screenshotFiles)
183         {
184             screenshots.add(new Screenshot(screenshotFile));
185         }
186         Collections.sort(screenshots);
187         return screenshots;
188     }
189 
190     protected void replaceUIHtml(String id, String newContent)
191     {
192         client.evaluate("window.document.getElementById('" + id + "').innerHTML = \"" + newContent + "\"");
193     }
194 
195     public boolean compareScreenshots(ArrayList<Screenshot> oldScreenshots, ArrayList<Screenshot> newScreenshots)
196             throws Exception
197     {
198         if (oldScreenshots.size() != newScreenshots.size())
199         {
200             throw new IllegalArgumentException("Did not find correct number of baseline images");
201         }
202 
203         boolean matches = true;
204         for (int i = 0; i < oldScreenshots.size(); i++)
205         {
206             ScreenshotDiff diff = getScreenshotDiff(oldScreenshots.get(i), newScreenshots.get(i));
207             if (reportingEnabled)
208             {
209                 diff.writeDiffReport(reportOutputPath, imageSubDirName);
210             }
211             matches = !diff.hasDifferences() && matches;
212         }
213 
214         return matches;
215     }
216 
217     public ScreenshotDiff getScreenshotDiff(Screenshot oldScreenshot, Screenshot newScreenshot) throws Exception
218     {
219         return oldScreenshot.getDiff(newScreenshot, ignoreAreas, ignoreSingleLineDiffs);
220     }
221 
222 
223 }