Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
michael@0 | 1 | Layout Engine Visual Tests (reftest) |
michael@0 | 2 | L. David Baron <dbaron@dbaron.org>, Mozilla Corporation |
michael@0 | 3 | July 19, 2006 |
michael@0 | 4 | |
michael@0 | 5 | This code is designed to run tests of Mozilla's layout engine. These |
michael@0 | 6 | tests consist of an HTML (or other format) file along with a reference |
michael@0 | 7 | in the same format. The tests are run based on a manifest file, and for |
michael@0 | 8 | each test, PASS or FAIL is reported, and UNEXPECTED is reported if the |
michael@0 | 9 | result (PASS or FAIL) was not the expected result noted in the manifest. |
michael@0 | 10 | |
michael@0 | 11 | Images of the display of both tests are captured, and most test types |
michael@0 | 12 | involve comparing these images (e.g., test types == or !=) to determine |
michael@0 | 13 | whether the test passed. The captures of the tests are taken in a |
michael@0 | 14 | viewport that is 800 pixels wide and 1000 pixels tall, so any content |
michael@0 | 15 | outside that area will be ignored (except for any scrollbars that are |
michael@0 | 16 | displayed). Ideally, however, tests should be written so that they fit |
michael@0 | 17 | within 600x600, since we may in the future want to switch to 600x600 to |
michael@0 | 18 | match http://lists.w3.org/Archives/Public/www-style/2012Sep/0562.html . |
michael@0 | 19 | |
michael@0 | 20 | Why this way? |
michael@0 | 21 | ============= |
michael@0 | 22 | |
michael@0 | 23 | Writing HTML tests where the reference rendering is also in HTML is |
michael@0 | 24 | harder than simply writing bits of HTML that can be regression-tested by |
michael@0 | 25 | comparing the rendering of an older build to that of a newer build |
michael@0 | 26 | (perhaps using stored reference images from the older build). However, |
michael@0 | 27 | comparing across time has major disadvantages: |
michael@0 | 28 | |
michael@0 | 29 | * Comparisons across time either require two runs for every test, or |
michael@0 | 30 | they require stored reference images appropriate for the platform and |
michael@0 | 31 | configuration (often limiting testing to a very specific |
michael@0 | 32 | configuration). |
michael@0 | 33 | |
michael@0 | 34 | * Comparisons across time may fail due to expected changes, for |
michael@0 | 35 | example, changes in the default style sheet for HTML, changes in the |
michael@0 | 36 | appearance of form controls, or changes in default preferences like |
michael@0 | 37 | default font size or default colors. |
michael@0 | 38 | |
michael@0 | 39 | Using tests for which the pass criteria were explicitly chosen allows |
michael@0 | 40 | running tests at any time to see whether they still pass. |
michael@0 | 41 | |
michael@0 | 42 | Manifest Format |
michael@0 | 43 | =============== |
michael@0 | 44 | |
michael@0 | 45 | The test manifest format is a plain text file. A line starting with a |
michael@0 | 46 | "#" is a comment. Lines may be commented using whitespace followed by |
michael@0 | 47 | a "#" and the comment. Each non-blank line (after removal of comments) |
michael@0 | 48 | must be one of the following: |
michael@0 | 49 | |
michael@0 | 50 | 1. Inclusion of another manifest |
michael@0 | 51 | |
michael@0 | 52 | <failure-type>* include <relative_path> |
michael@0 | 53 | |
michael@0 | 54 | <failure-type> is the same as listed below for a test item. As for |
michael@0 | 55 | test items, multiple failure types listed on the same line are |
michael@0 | 56 | combined by using the last matching failure type listed. However, |
michael@0 | 57 | the failure type on a manifest is combined with the failure type on |
michael@0 | 58 | the test (or on a nested manifest) with the rule that the last in the |
michael@0 | 59 | following list wins: fails, random, skip. (In other words, skip |
michael@0 | 60 | always wins, and random beats fails.) |
michael@0 | 61 | |
michael@0 | 62 | 2. A test item |
michael@0 | 63 | |
michael@0 | 64 | [ <failure-type> | <preference> ]* [<http>] <type> <url> <url_ref> |
michael@0 | 65 | |
michael@0 | 66 | where |
michael@0 | 67 | |
michael@0 | 68 | a. <failure-type> (optional) is one of the following: |
michael@0 | 69 | |
michael@0 | 70 | fails The test passes if the images of the two renderings DO NOT |
michael@0 | 71 | meet the conditions specified in the <type>. |
michael@0 | 72 | |
michael@0 | 73 | fails-if(condition) If the condition is met, the test passes if the |
michael@0 | 74 | images of the two renderings DO NOT meet the |
michael@0 | 75 | conditions of <type>. If the condition is not met, |
michael@0 | 76 | the test passes if the conditions of <type> are met. |
michael@0 | 77 | |
michael@0 | 78 | needs-focus The test fails or times out if the reftest window is not |
michael@0 | 79 | focused. |
michael@0 | 80 | |
michael@0 | 81 | random The results of the test are random and therefore not to be |
michael@0 | 82 | considered in the output. |
michael@0 | 83 | |
michael@0 | 84 | random-if(condition) The results of the test are random if a given |
michael@0 | 85 | condition is met. |
michael@0 | 86 | |
michael@0 | 87 | silentfail This test may fail silently, and if that happens it should |
michael@0 | 88 | count as if the test passed. This is useful for cases where |
michael@0 | 89 | silent failure is the intended behavior (for example, in |
michael@0 | 90 | an out of memory situation in JavaScript, we stop running |
michael@0 | 91 | the script silently and immediately, in hopes of reclaiming |
michael@0 | 92 | enough memory to keep the browser functioning). |
michael@0 | 93 | |
michael@0 | 94 | silentfail-if(condition) This test may fail silently if the condition |
michael@0 | 95 | is met. |
michael@0 | 96 | |
michael@0 | 97 | skip This test should not be run. This is useful when a test fails in a |
michael@0 | 98 | catastrophic way, such as crashing or hanging the browser. Using |
michael@0 | 99 | 'skip' is preferred to simply commenting out the test because we |
michael@0 | 100 | want to report the test failure at the end of the test run. |
michael@0 | 101 | |
michael@0 | 102 | skip-if(condition) If the condition is met, the test is not run. This is |
michael@0 | 103 | useful if, for example, the test crashes only on a |
michael@0 | 104 | particular platform (i.e. it allows us to get test |
michael@0 | 105 | coverage on the other platforms). |
michael@0 | 106 | |
michael@0 | 107 | slow The test may take a long time to run, so run it if slow tests are |
michael@0 | 108 | either enabled or not disabled (test manifest interpreters may |
michael@0 | 109 | choose whether or not to run such tests by default). |
michael@0 | 110 | |
michael@0 | 111 | slow-if(condition) If the condition is met, the test is treated as if |
michael@0 | 112 | 'slow' had been specified. This is useful for tests |
michael@0 | 113 | which are slow only on particular platforms (e.g. a |
michael@0 | 114 | test which exercised out-of-memory behavior might be |
michael@0 | 115 | fast on a 32-bit system but inordinately slow on a |
michael@0 | 116 | 64-bit system). |
michael@0 | 117 | |
michael@0 | 118 | fuzzy(maxDiff, diffCount) |
michael@0 | 119 | This allows a test to pass if the pixel value differences are <= |
michael@0 | 120 | maxDiff and the total number of different pixels is <= diffCount. |
michael@0 | 121 | It can also be used with '!=' to ensure that the difference is |
michael@0 | 122 | greater than maxDiff. |
michael@0 | 123 | |
michael@0 | 124 | fuzzy-if(condition, maxDiff, diffCount) |
michael@0 | 125 | If the condition is met, the test is treated as if 'fuzzy' had been |
michael@0 | 126 | specified. This is useful if there are differences on particular |
michael@0 | 127 | platforms. |
michael@0 | 128 | |
michael@0 | 129 | require-or(cond1&&cond2&&...,fallback) |
michael@0 | 130 | Require some particular setup be performed or environmental |
michael@0 | 131 | condition(s) made true (eg setting debug mode) before the test |
michael@0 | 132 | is run. If any condition is unknown, unimplemented, or fails, |
michael@0 | 133 | revert to the fallback failure-type. |
michael@0 | 134 | Example: require-or(debugMode,skip) |
michael@0 | 135 | |
michael@0 | 136 | asserts(count) |
michael@0 | 137 | Loading the test and reference is known to assert exactly |
michael@0 | 138 | count times. |
michael@0 | 139 | NOTE: An asserts() notation with a non-zero count or maxCount |
michael@0 | 140 | suppresses use of a cached canvas for the test with the |
michael@0 | 141 | annotation. However, if later occurrences of the same test |
michael@0 | 142 | are not annotated, they will use the cached canvas |
michael@0 | 143 | (potentially from the load that asserted). This allows |
michael@0 | 144 | repeated use of the same test or reference to be annotated |
michael@0 | 145 | correctly (which may be particularly useful when the uses are |
michael@0 | 146 | in different subdirectories that can be tested independently), |
michael@0 | 147 | but does not force them to be, nor does it force suppression |
michael@0 | 148 | of caching for a common reference when it is the test that |
michael@0 | 149 | asserts. |
michael@0 | 150 | |
michael@0 | 151 | asserts(minCount-maxCount) |
michael@0 | 152 | Loading the test and reference is known to assert between |
michael@0 | 153 | minCount and maxCount times, inclusive. |
michael@0 | 154 | NOTE: See above regarding canvas caching. |
michael@0 | 155 | |
michael@0 | 156 | asserts-if(condition,count) |
michael@0 | 157 | asserts-if(condition,minCount-maxCount) |
michael@0 | 158 | Same as above, but only if condition is true. |
michael@0 | 159 | |
michael@0 | 160 | Conditions are JavaScript expressions *without spaces* in them. |
michael@0 | 161 | They are evaluated in a sandbox in which a limited set of |
michael@0 | 162 | variables are defined. See the BuildConditionSandbox function in |
michael@0 | 163 | layout/tools/reftest.js for details. |
michael@0 | 164 | |
michael@0 | 165 | Examples of using conditions: |
michael@0 | 166 | fails-if(winWidget) == test reference |
michael@0 | 167 | asserts-if(cocoaWidget,2) load crashtest |
michael@0 | 168 | |
michael@0 | 169 | b. <preference> (optional) is a string of the form |
michael@0 | 170 | |
michael@0 | 171 | pref(<name>,<value>) |
michael@0 | 172 | test-pref(<name>,<value>) |
michael@0 | 173 | ref-pref(<name>,<value>) |
michael@0 | 174 | |
michael@0 | 175 | where <name> is the name of a preference setting, as seen in |
michael@0 | 176 | about:config, and <value> is the value to which this preference should |
michael@0 | 177 | be set. <value> may be a boolean (true/false), an integer, or a |
michael@0 | 178 | quoted string *without spaces*, according to the type of the preference. |
michael@0 | 179 | |
michael@0 | 180 | The preference will be set to the specified value prior to |
michael@0 | 181 | rendering the test and/or reference canvases (pref() applies to |
michael@0 | 182 | both, test-pref() only to the test, and ref-pref() only to the |
michael@0 | 183 | reference), and will be restored afterwards so that following |
michael@0 | 184 | tests are not affected. Note that this feature is only useful for |
michael@0 | 185 | "live" preferences that take effect immediately, without requiring |
michael@0 | 186 | a browser restart. |
michael@0 | 187 | |
michael@0 | 188 | c. <http>, if present, is one of the strings (sans quotes) "HTTP" or |
michael@0 | 189 | "HTTP(..)" or "HTTP(../..)" or "HTTP(../../..)", etc. , indicating that |
michael@0 | 190 | the test should be run over an HTTP server because it requires certain |
michael@0 | 191 | HTTP headers or a particular HTTP status. (Don't use this if your test |
michael@0 | 192 | doesn't require this functionality, because it unnecessarily slows down |
michael@0 | 193 | the test.) |
michael@0 | 194 | |
michael@0 | 195 | With "HTTP", HTTP tests have the restriction that any resource an HTTP |
michael@0 | 196 | test accesses must be accessed using a relative URL, and the test and |
michael@0 | 197 | the resource must be within the directory containing the reftest |
michael@0 | 198 | manifest that describes the test (or within a descendant directory). |
michael@0 | 199 | The variants "HTTP(..)", etc., can be used to relax this restriction by |
michael@0 | 200 | allowing resources in the parent directory, etc. |
michael@0 | 201 | |
michael@0 | 202 | To modify the HTTP status or headers of a resource named FOO, create a |
michael@0 | 203 | sibling file named FOO^headers^ with the following contents: |
michael@0 | 204 | |
michael@0 | 205 | [<http-status>] |
michael@0 | 206 | <http-header>* |
michael@0 | 207 | |
michael@0 | 208 | <http-status> A line of the form "HTTP ###[ <description>]", where |
michael@0 | 209 | ### indicates the desired HTTP status and <description> |
michael@0 | 210 | indicates a desired HTTP status description, if any. |
michael@0 | 211 | If this line is omitted, the default is "HTTP 200 OK". |
michael@0 | 212 | <http-header> A line in standard HTTP header line format, i.e. |
michael@0 | 213 | "Field-Name: field-value". You may not repeat the use |
michael@0 | 214 | of a Field-Name and must coalesce such headers together, |
michael@0 | 215 | and each header must be specified on a single line, but |
michael@0 | 216 | otherwise the format exactly matches that from HTTP |
michael@0 | 217 | itself. |
michael@0 | 218 | |
michael@0 | 219 | HTTP tests may also incorporate SJS files. SJS files provide similar |
michael@0 | 220 | functionality to CGI scripts, in that the response they produce can be |
michael@0 | 221 | dependent on properties of the incoming request. Currently these |
michael@0 | 222 | properties are restricted to method type and headers, but eventually |
michael@0 | 223 | it should be possible to examine data in the body of the request as |
michael@0 | 224 | well when computing the generated response. An SJS file is a JavaScript |
michael@0 | 225 | file with a .sjs extension which defines a global |handleRequest| |
michael@0 | 226 | function (called every time that file is loaded during reftests) in this |
michael@0 | 227 | format: |
michael@0 | 228 | |
michael@0 | 229 | function handleRequest(request, response) |
michael@0 | 230 | { |
michael@0 | 231 | response.setStatusLine(request.httpVersion, 200, "OK"); |
michael@0 | 232 | |
michael@0 | 233 | // You *probably* want this, or else you'll get bitten if you run |
michael@0 | 234 | // reftest multiple times with the same profile. |
michael@0 | 235 | response.setHeader("Cache-Control", "no-cache"); |
michael@0 | 236 | |
michael@0 | 237 | response.write("any ASCII data you want"); |
michael@0 | 238 | |
michael@0 | 239 | var outputStream = response.bodyOutputStream; |
michael@0 | 240 | // ...anything else you want to do, synchronously... |
michael@0 | 241 | } |
michael@0 | 242 | |
michael@0 | 243 | For more details on exactly which functions and properties are available |
michael@0 | 244 | on request/response in handleRequest, see the nsIHttpRe(quest|sponse) |
michael@0 | 245 | definitions in <netwerk/test/httpserver/nsIHttpServer.idl>. |
michael@0 | 246 | |
michael@0 | 247 | d. <type> is one of the following: |
michael@0 | 248 | |
michael@0 | 249 | == The test passes if the images of the two renderings are the |
michael@0 | 250 | SAME. |
michael@0 | 251 | != The test passes if the images of the two renderings are |
michael@0 | 252 | DIFFERENT. |
michael@0 | 253 | load The test passes unconditionally if the page loads. url_ref |
michael@0 | 254 | must be omitted, and the test cannot be marked as fails or |
michael@0 | 255 | random. (Used to test for crashes, hangs, assertions, and |
michael@0 | 256 | leaks.) |
michael@0 | 257 | script The loaded page records the test's pass or failure status |
michael@0 | 258 | in a JavaScript data structure accessible through the following |
michael@0 | 259 | API. |
michael@0 | 260 | |
michael@0 | 261 | getTestCases() returns an array of test result objects |
michael@0 | 262 | representing the results of the tests performed by the page. |
michael@0 | 263 | |
michael@0 | 264 | Each test result object has two methods: |
michael@0 | 265 | |
michael@0 | 266 | testPassed() returns true if the test result object passed, |
michael@0 | 267 | otherwise it returns false. |
michael@0 | 268 | |
michael@0 | 269 | testDescription() returns a string describing the test |
michael@0 | 270 | result. |
michael@0 | 271 | |
michael@0 | 272 | url_ref must be omitted. The test may be marked as fails or |
michael@0 | 273 | random. (Used to test the JavaScript Engine.) |
michael@0 | 274 | |
michael@0 | 275 | e. <url> is either a relative file path or an absolute URL for the |
michael@0 | 276 | test page |
michael@0 | 277 | |
michael@0 | 278 | f. <url_ref> is either a relative file path or an absolute URL for |
michael@0 | 279 | the reference page |
michael@0 | 280 | |
michael@0 | 281 | The only difference between <url> and <url_ref> is that results of |
michael@0 | 282 | the test are reported using <url> only. |
michael@0 | 283 | |
michael@0 | 284 | 3. Specification of a url prefix |
michael@0 | 285 | |
michael@0 | 286 | url-prefix <string> |
michael@0 | 287 | |
michael@0 | 288 | <string> will be prepended to relative <url> and <url_ref> for all following |
michael@0 | 289 | test items in the manifest. |
michael@0 | 290 | |
michael@0 | 291 | <string> will not be prepended to the relative path when including another |
michael@0 | 292 | manifest, e.g. include <relative_path>. |
michael@0 | 293 | |
michael@0 | 294 | <string> will not be prepended to any <url> or <url_ref> matching the pattern |
michael@0 | 295 | /^\w+:/. This will prevent the prefix from being applied to any absolute url |
michael@0 | 296 | containing a protocol such as data:, about:, or http:. |
michael@0 | 297 | |
michael@0 | 298 | While the typical use of url-prefix is expected to be as the first line of |
michael@0 | 299 | a manifest, it is legal to use it anywhere in a manifest. Subsequent uses |
michael@0 | 300 | of url-prefix overwrite any existing values. |
michael@0 | 301 | |
michael@0 | 302 | 4. Specification of default preferences |
michael@0 | 303 | |
michael@0 | 304 | default-preferences <preference>* |
michael@0 | 305 | |
michael@0 | 306 | where <preference> is defined above. |
michael@0 | 307 | |
michael@0 | 308 | The <preference> settings will be used for all following test items in the |
michael@0 | 309 | manifest. |
michael@0 | 310 | |
michael@0 | 311 | If a test item includes its own preference settings, then they will override |
michael@0 | 312 | any settings for preferences of the same names that are set using |
michael@0 | 313 | default-preferences, just as later items within a line override earlier ones. |
michael@0 | 314 | |
michael@0 | 315 | A default-preferences line with no <preference> settings following it will |
michael@0 | 316 | reset the set of default preferences to be empty. |
michael@0 | 317 | |
michael@0 | 318 | As with url-prefix, default-preferences will often be used at the start of a |
michael@0 | 319 | manifest file so that it applies to all test items, but it is legal for |
michael@0 | 320 | default-preferences to appear anywhere in the manifest. A subsequent |
michael@0 | 321 | default-preferences will reset any previous default preference values and |
michael@0 | 322 | overwrite them with the specified <preference> values. |
michael@0 | 323 | |
michael@0 | 324 | This test manifest format could be used by other harnesses, such as ones |
michael@0 | 325 | that do not depend on XUL, or even ones testing other layout engines. |
michael@0 | 326 | |
michael@0 | 327 | Running Tests |
michael@0 | 328 | ============= |
michael@0 | 329 | |
michael@0 | 330 | (If you're not using a DEBUG build, first set browser.dom.window.dump.enabled |
michael@0 | 331 | to true (in about:config, in the profile you'll be using to run the tests). |
michael@0 | 332 | Create the option as a new boolean if it doesn't exist already. If you skip |
michael@0 | 333 | this step you won't get any output in the terminal.) |
michael@0 | 334 | |
michael@0 | 335 | At some point in the future there will hopefully be a cleaner way to do |
michael@0 | 336 | this. For now, go to your object directory, and run (perhaps using |
michael@0 | 337 | MOZ_NO_REMOTE=1 or the -profile <directory> option) |
michael@0 | 338 | |
michael@0 | 339 | ./firefox -reftest /path/to/srcdir/mozilla/layout/reftests/reftest.list > reftest.out |
michael@0 | 340 | |
michael@0 | 341 | and then search/grep reftest.out for "UNEXPECTED". |
michael@0 | 342 | |
michael@0 | 343 | There are two scripts provided to convert the reftest.out to HTML. |
michael@0 | 344 | clean-reftest-output.pl converts reftest.out into simple HTML, stripping |
michael@0 | 345 | lines from the log that aren't relevant. reftest-to-html.pl converts |
michael@0 | 346 | the output into html that makes it easier to visually check for |
michael@0 | 347 | failures. |
michael@0 | 348 | |
michael@0 | 349 | Testable Areas |
michael@0 | 350 | ============== |
michael@0 | 351 | |
michael@0 | 352 | This framework is capable of testing many areas of the layout engine. |
michael@0 | 353 | It is particularly well-suited to testing dynamic change handling (by |
michael@0 | 354 | comparison to the static end-result as a reference) and incremental |
michael@0 | 355 | layout (comparison of a script-interrupted layout to one that was not). |
michael@0 | 356 | However, it is also possible to write tests for many other things that |
michael@0 | 357 | can be described in terms of equivalence, for example: |
michael@0 | 358 | |
michael@0 | 359 | * CSS cascading could be tested by comparing the result of a |
michael@0 | 360 | complicated set of style rules that makes a word green to <span |
michael@0 | 361 | style="color:green">word</span>. |
michael@0 | 362 | |
michael@0 | 363 | * <canvas> compositing operators could be tested by comparing the |
michael@0 | 364 | result of drawing using canvas to a block-level element with the |
michael@0 | 365 | desired color as a CSS background-color. |
michael@0 | 366 | |
michael@0 | 367 | * CSS counters could be tested by comparing the text output by counters |
michael@0 | 368 | with a page containing the text written out |
michael@0 | 369 | |
michael@0 | 370 | * complex margin collapsing could be tested by comparing the complex |
michael@0 | 371 | case to a case where the margin is written out, or where the margin |
michael@0 | 372 | space is created by an element with 'height' and transparent |
michael@0 | 373 | background |
michael@0 | 374 | |
michael@0 | 375 | When it is not possible to test by equivalence, it may be possible to |
michael@0 | 376 | test by non-equivalence. For example, testing justification in cases |
michael@0 | 377 | with more than two words, or more than three different words, is |
michael@0 | 378 | difficult. However, it is simple to test that justified text is at |
michael@0 | 379 | least displayed differently from left-, center-, or right-aligned text. |
michael@0 | 380 | |
michael@0 | 381 | Writing Tests |
michael@0 | 382 | ============= |
michael@0 | 383 | |
michael@0 | 384 | When writing tests for this framework, it is important for the test to |
michael@0 | 385 | depend only on behaviors that are known to be correct and permanent. |
michael@0 | 386 | For example, tests should not depend on default font sizes, default |
michael@0 | 387 | margins of the body element, the default style sheet used for HTML, the |
michael@0 | 388 | default appearance of form controls, or anything else that can be |
michael@0 | 389 | avoided. |
michael@0 | 390 | |
michael@0 | 391 | In general, the best way to achieve this is to make the test and the |
michael@0 | 392 | reference identical in as many aspects as possible. For example: |
michael@0 | 393 | |
michael@0 | 394 | Good test markup: |
michael@0 | 395 | <div style="color:green"><table><tr><td><span>green |
michael@0 | 396 | </span></td></tr></table></div> |
michael@0 | 397 | |
michael@0 | 398 | Good reference markup: |
michael@0 | 399 | <div><table><tr><td><span style="color:green">green |
michael@0 | 400 | </span></td></tr></table></div> |
michael@0 | 401 | |
michael@0 | 402 | BAD reference markup: |
michael@0 | 403 | <!-- 3px matches the default cellspacing and cellpadding --> |
michael@0 | 404 | <div style="color:green; padding: 3px">green |
michael@0 | 405 | </div> |
michael@0 | 406 | |
michael@0 | 407 | BAD test markup: |
michael@0 | 408 | <!-- span doesn't change the positioning, so skip it --> |
michael@0 | 409 | <div style="color:green"><table><tr><td>green |
michael@0 | 410 | </td></tr></table></div> |
michael@0 | 411 | |
michael@0 | 412 | Asynchronous Tests: class="reftest-wait" |
michael@0 | 413 | ======================================== |
michael@0 | 414 | |
michael@0 | 415 | Normally reftest takes a snapshot of the given markup's rendering right |
michael@0 | 416 | after the load event fires for content. If your test needs to postpone |
michael@0 | 417 | the moment the snapshot is taken, it should make sure a class |
michael@0 | 418 | 'reftest-wait' is on the root element by the moment the load event |
michael@0 | 419 | fires. The easiest way to do this is to put it in the markup, e.g.: |
michael@0 | 420 | <html class="reftest-wait"> |
michael@0 | 421 | |
michael@0 | 422 | When your test is ready, you should remove this class from the root |
michael@0 | 423 | element, for example using this code: |
michael@0 | 424 | document.documentElement.className = ""; |
michael@0 | 425 | |
michael@0 | 426 | |
michael@0 | 427 | Note that in layout tests it is often enough to trigger layout using |
michael@0 | 428 | document.body.offsetWidth // HTML example |
michael@0 | 429 | |
michael@0 | 430 | When possible, you should use this technique instead of making your |
michael@0 | 431 | test async. |
michael@0 | 432 | |
michael@0 | 433 | Invalidation Tests: MozReftestInvalidate Event |
michael@0 | 434 | ============================================== |
michael@0 | 435 | |
michael@0 | 436 | When a test (or reference) uses reftest-wait, reftest tracks invalidation |
michael@0 | 437 | via MozAfterPaint and updates the test image in the same way that |
michael@0 | 438 | a regular window would be repainted. Therefore it is possible to test |
michael@0 | 439 | invalidation-related bugs by setting up initial content and then |
michael@0 | 440 | dynamically modifying it before removing reftest-wait. However, it is |
michael@0 | 441 | important to get the timing of these dynamic modifications right so that |
michael@0 | 442 | the test doesn't accidentally pass because a full repaint of the window |
michael@0 | 443 | was already pending. To help with this, reftest fires one MozReftestInvalidate |
michael@0 | 444 | event at the document root element for a reftest-wait test when it is safe to |
michael@0 | 445 | make changes that should test invalidation. The event bubbles up to the |
michael@0 | 446 | document and window so you can set listeners there too. For example, |
michael@0 | 447 | |
michael@0 | 448 | function doTest() { |
michael@0 | 449 | document.body.style.border = ""; |
michael@0 | 450 | document.documentElement.removeAttribute('class'); |
michael@0 | 451 | } |
michael@0 | 452 | document.addEventListener("MozReftestInvalidate", doTest, false); |
michael@0 | 453 | |
michael@0 | 454 | Painting Tests: class="reftest-no-paint" |
michael@0 | 455 | ======================================== |
michael@0 | 456 | |
michael@0 | 457 | If an element shouldn't be painted, set the class "reftest-no-paint" on it |
michael@0 | 458 | when doing an invalidation test. Causing a repaint in your |
michael@0 | 459 | MozReftestInvalidate handler (for example, by changing the body's background |
michael@0 | 460 | colour) will accurately test whether the element is painted. |
michael@0 | 461 | |
michael@0 | 462 | Snapshot The Whole Window: class="reftest-snapshot-all" |
michael@0 | 463 | ======================================================= |
michael@0 | 464 | |
michael@0 | 465 | In a reftest-wait test, to disable testing of invalidation and force the final |
michael@0 | 466 | snapshot to be taken of the whole window, set the "reftest-snapshot-all" |
michael@0 | 467 | class on the root element. |
michael@0 | 468 | |
michael@0 | 469 | Zoom Tests: reftest-zoom="<float>" |
michael@0 | 470 | ================================== |
michael@0 | 471 | |
michael@0 | 472 | When the root element of a test has a "reftest-zoom" attribute, that zoom |
michael@0 | 473 | factor is applied when rendering the test. The reftest document will be |
michael@0 | 474 | 800 device pixels wide by 1000 device pixels high. The reftest harness assumes |
michael@0 | 475 | that the CSS pixel dimensions are 800/zoom and 1000/zoom. For best results |
michael@0 | 476 | therefore, choose zoom factors that do not require rounding when we calculate |
michael@0 | 477 | the number of appunits per device pixel; i.e. the zoom factor should divide 60, |
michael@0 | 478 | so 60/zoom is an integer. |
michael@0 | 479 | |
michael@0 | 480 | Setting Viewport Size: reftest-viewport-w/h="<int>" |
michael@0 | 481 | =================================================== |
michael@0 | 482 | |
michael@0 | 483 | If either of the "reftest-viewport-w" and "reftest-viewport-h" attributes on |
michael@0 | 484 | the root element are non-zero, sets the CSS viewport to the given size in |
michael@0 | 485 | CSS pixels. This does not affect the size of the snapshot that is taken. |
michael@0 | 486 | |
michael@0 | 487 | Setting Async Scroll Mode: reftest-async-scroll attribute |
michael@0 | 488 | ========================================================= |
michael@0 | 489 | |
michael@0 | 490 | If the "reftest-async-scroll" attribute is set on the root element, we try to |
michael@0 | 491 | enable async scrolling for the document. This is unsupported in many |
michael@0 | 492 | configurations. |
michael@0 | 493 | |
michael@0 | 494 | Setting Displayport Dimensions: reftest-displayport-x/y/w/h="<int>" |
michael@0 | 495 | =================================================================== |
michael@0 | 496 | |
michael@0 | 497 | If any of the "reftest-displayport-x", "reftest-displayport-y", |
michael@0 | 498 | "reftest-displayport-w" and "reftest-displayport-h" attributes on the root |
michael@0 | 499 | element are nonzero, sets the displayport dimensions to the given bounds in |
michael@0 | 500 | CSS pixels. This does not affect the size of the snapshot that is taken. |
michael@0 | 501 | |
michael@0 | 502 | When the "reftest-async-scroll" attribute is set on the root element, *all* |
michael@0 | 503 | elements in the document are checked for "reftest-displayport-x/y/w/h" and have |
michael@0 | 504 | displayports set on them when those attributes are present. |
michael@0 | 505 | |
michael@0 | 506 | Testing Async Scrolling: reftest-async-scroll-x/y="<int>" |
michael@0 | 507 | ========================================================= |
michael@0 | 508 | |
michael@0 | 509 | When the "reftest-async-scroll" attribute is set on the root element, for any |
michael@0 | 510 | element where either the "reftest-async-scroll-x" or "reftest-async-scroll-y |
michael@0 | 511 | attributes are nonzero, at the end of the test take the snapshot with the given |
michael@0 | 512 | offset (in CSS pixels) added to the async scroll offset. |
michael@0 | 513 | |
michael@0 | 514 | Printing Tests: class="reftest-print" |
michael@0 | 515 | ===================================== |
michael@0 | 516 | |
michael@0 | 517 | Now that the patch for bug 374050 has landed |
michael@0 | 518 | (https://bugzilla.mozilla.org/show_bug.cgi?id=374050), it is possible to |
michael@0 | 519 | create reftests that run in a paginated context. |
michael@0 | 520 | |
michael@0 | 521 | The page size used is 5in wide and 3in tall (with the default half-inch |
michael@0 | 522 | margins). This is to allow tests to have less text and to make the |
michael@0 | 523 | entire test fit on the screen. |
michael@0 | 524 | |
michael@0 | 525 | There is a layout/reftests/printing directory for printing reftests; however, |
michael@0 | 526 | there is nothing special about this directory. You can put printing reftests |
michael@0 | 527 | anywhere that is appropriate. |
michael@0 | 528 | |
michael@0 | 529 | The suggested first lines for any printing test is |
michael@0 | 530 | <!DOCTYPE html><html class="reftest-print"> |
michael@0 | 531 | <style>html{font-size:12pt}</style> |
michael@0 | 532 | |
michael@0 | 533 | The reftest-print class on the root element triggers the reftest to |
michael@0 | 534 | switch into page mode. Fixing the font size is suggested, although not |
michael@0 | 535 | required, because the pages are a fixed size in inches. The switch to page mode |
michael@0 | 536 | happens on load if the reftest-wait class is not present; otherwise it happens |
michael@0 | 537 | immediately after firing the MozReftestInvalidate event. |
michael@0 | 538 | |
michael@0 | 539 | The underlying layout support for this mode isn't really complete; it |
michael@0 | 540 | doesn't use exactly the same codepath as real print preview/print. In |
michael@0 | 541 | particular, scripting and frames are likely to cause problems; it is untested, |
michael@0 | 542 | though. That said, it should be sufficient for testing layout issues related |
michael@0 | 543 | to pagination. |
michael@0 | 544 | |
michael@0 | 545 | Plugin and IPC Process Crash Tests: class="reftest-expect-process-crash" |
michael@0 | 546 | ======================================================================== |
michael@0 | 547 | |
michael@0 | 548 | If you are running a test that causes an out-of-process plugin or IPC process |
michael@0 | 549 | under Electrolysis to crash as part of a reftest, this will cause process |
michael@0 | 550 | crash minidump files to be left in the profile directory. The test |
michael@0 | 551 | infrastructure that runs the reftests will notice these minidump files and |
michael@0 | 552 | dump out information from them, and these additional error messages in the logs |
michael@0 | 553 | can end up erroneously being associated with other errors from the reftest run. |
michael@0 | 554 | They are also confusing, since the appearance of "PROCESS-CRASH" messages in |
michael@0 | 555 | the test run output can seem like a real problem, when in fact it is the |
michael@0 | 556 | expected behavior. |
michael@0 | 557 | |
michael@0 | 558 | To indicate to the reftest framework that a test is expecting a plugin or |
michael@0 | 559 | IPC process crash, have the test include "reftest-expect-process-crash" as |
michael@0 | 560 | one of the root element's classes by the time the test has finished. This will |
michael@0 | 561 | cause any minidump files that are generated while running the test to be removed |
michael@0 | 562 | and they won't cause any error messages in the test run output. |
michael@0 | 563 | |
michael@0 | 564 | Skip Forcing A Content Process Layer-Tree Update: reftest-no-sync-layers attribute |
michael@0 | 565 | ================================================================================== |
michael@0 | 566 | |
michael@0 | 567 | Normally when an multi-process reftest test ends, we force the content process |
michael@0 | 568 | to push a layer-tree update to the compositor before taking the snapshot. |
michael@0 | 569 | Setting the "reftest-no-sync-layers" attribute on the root element skips this |
michael@0 | 570 | step, enabling testing that layer-tree updates are being correctly generated. |
michael@0 | 571 | However the test must manually wait for a MozAfterPaint event before ending. |