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
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
160
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 }