forked from mirrors/gecko-dev
		
	Bug 1356225 - Update web-platform-tests to revision d519fe9011da7cfce7949f7ed826e9759dc5c532, a=testonly
MozReview-Commit-ID: GmGgeZxHy0j --HG-- rename : testing/web-platform/tests/content-security-policy/media-src/media-src-7_1_2.html.sub.headers => testing/web-platform/tests/content-security-policy/media-src/media-src-7_1_2.sub.html.sub.headers rename : testing/web-platform/tests/content-security-policy/media-src/media-src-7_2_2.html.sub.headers => testing/web-platform/tests/content-security-policy/media-src/media-src-7_2_2.sub.html.sub.headers rename : testing/web-platform/tests/content-security-policy/media-src/media-src-7_3_2.html.sub.headers => testing/web-platform/tests/content-security-policy/media-src/media-src-7_3_2.sub.html.sub.headers rename : testing/web-platform/tests/html/browsers/windows/nested-browsing-contexts/test.html => testing/web-platform/tests/html/browsers/windows/nested-browsing-contexts/resources/frameElement-nested-frame.html rename : testing/web-platform/tests/html/browsers/windows/nested-browsing-contexts/testcase3.html => testing/web-platform/tests/html/browsers/windows/nested-browsing-contexts/resources/frameElement-window-post.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationAvailability_onchange-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationAvailability_onchange-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationConnection_onmessage-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationConnection_onmessage-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationConnection_send-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationConnection_send-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_error.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_error.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_onconnectionavailable-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_onconnectionavailable-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_sandboxing_error.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_sandboxing_error.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_sandboxing_success.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_sandboxing_success.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_success.html => testing/web-platform/tests/presentation-api/controlling-ua/PresentationRequest_success.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/defaultRequest_success-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/defaultRequest_success-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/getAvailability.html => testing/web-platform/tests/presentation-api/controlling-ua/getAvailability.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/getAvailability_sandboxing_success.html => testing/web-platform/tests/presentation-api/controlling-ua/getAvailability_sandboxing_success.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_notfound_error.html => testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_notfound_error.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_sandboxing_success.html => testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_sandboxing_success.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_success-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/reconnectToPresentation_success-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_displaynotallowed-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_displaynotallowed-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_displaynotfound-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_displaynotfound-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_error.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_error.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_sandboxing_success-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_sandboxing_success-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_success-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_success-manual.https.html rename : testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_unsettledpromise-manual.html => testing/web-platform/tests/presentation-api/controlling-ua/startNewPresentation_unsettledpromise-manual.https.html rename : testing/web-platform/tests/presentation-api/receiving-ua/idlharness-manual.html => testing/web-platform/tests/presentation-api/receiving-ua/idlharness-manual.https.html rename : testing/web-platform/tests/presentation-api/receiving-ua/support/idlharness_receiving-ua.html => testing/web-platform/tests/presentation-api/receiving-ua/support/idlharness_receiving-ua.https.html rename : testing/web-platform/tests/webdriver/util/http_request.py => testing/web-platform/tests/webdriver/support/http_request.py
This commit is contained in:
		
							parent
							
								
									beabf923ac
								
							
						
					
					
						commit
						1325009ca4
					
				
					 924 changed files with 33612 additions and 6217 deletions
				
			
		
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,2 +1,2 @@ | |||
| local: 5dc5249408ecc0003f0c68d32a8e782dec23fd36 | ||||
| upstream: aef9b4f327326fd32420281f9bc1ca9b60d553b3 | ||||
| local: 0000000000000000000000000000000000000000 | ||||
| upstream: 8181d7f09ee35cb521452bb727a48a1667901afd | ||||
|  |  | |||
							
								
								
									
										6
									
								
								testing/web-platform/tests/.gitmodules
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								testing/web-platform/tests/.gitmodules
									
									
									
									
										vendored
									
									
								
							|  | @ -6,3 +6,9 @@ | |||
| 	path = tools | ||||
| 	url = https://github.com/w3c/wpt-tools.git | ||||
| 	ignore = dirty | ||||
| [submodule "css/tools/apiclient"] | ||||
| 	path = css/tools/apiclient | ||||
| 	url = https://github.com/w3c/csswg-apiclient.git | ||||
| [submodule "css/tools/w3ctestlib"] | ||||
| 	path = css/tools/w3ctestlib | ||||
| 	url = https://github.com/w3c/csswg-w3ctestlib.git | ||||
|  |  | |||
|  | @ -16,16 +16,18 @@ before_install: | |||
| install: | ||||
|   - pip install -U setuptools | ||||
|   - pip install -U requests | ||||
| env:  # required at the top-level for allow_failures to work below | ||||
| matrix: | ||||
|   include: | ||||
|     - os: linux | ||||
|       python: "2.7" | ||||
|       env: | ||||
|         - SCRIPT=ci_lint.sh | ||||
|       env: SCRIPT=ci_lint.sh | ||||
|     - os: linux | ||||
|       python: "2.7" | ||||
|       env: | ||||
|         - SCRIPT=ci_built_diff.sh | ||||
|       env: SCRIPT=ci_built_diff.sh | ||||
|     - os: linux | ||||
|       python: "2.7" | ||||
|       env: SCRIPT=css/build-css-testsuites.sh | ||||
|     - os: linux | ||||
|       python: "2.7" | ||||
|       addons: | ||||
|  | @ -34,8 +36,7 @@ matrix: | |||
|             - libnss3-tools | ||||
|       env: | ||||
|         - secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM=" | ||||
|         - SCRIPT=ci_stability.sh | ||||
|         - PRODUCT=firefox:nightly | ||||
|         - SCRIPT=ci_stability.sh PRODUCT=firefox:nightly | ||||
|     - os: linux | ||||
|       sudo: required | ||||
|       python: "2.7" | ||||
|  | @ -46,8 +47,11 @@ matrix: | |||
|             - fonts-liberation | ||||
|       env: | ||||
|         - secure: "YTSXPwI0DyCA1GhYrLT9KMEV6b7QQKuEeaQgeFDP38OTzJ1+cIj3CC4SRNqbnJ/6SJwPGcdqSxLuV8m4e5HFFnyCcQnJe6h8EMsTehZ7W3j/fP9UYrJqYqvGpe3Vj3xblO5pwBYmq7sg3jAmmuCgAgOW6VGf7cRMucrsmFeo7VM=" | ||||
|         - SCRIPT=ci_stability.sh | ||||
|         - PRODUCT=chrome:unstable | ||||
|         - SCRIPT=ci_stability.sh PRODUCT=chrome:unstable | ||||
|   exclude: | ||||
|     - env:  # exclude empty env from the top-level above | ||||
|   allow_failures: | ||||
|     - env: SCRIPT=css/build-css-testsuites.sh | ||||
| script: | ||||
|   - bash $SCRIPT | ||||
| cache: | ||||
|  |  | |||
							
								
								
									
										58
									
								
								testing/web-platform/tests/2dcontext/imagebitmap/common.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								testing/web-platform/tests/2dcontext/imagebitmap/common.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | |||
| function testCanvasDisplayingPattern(canvas) | ||||
| { | ||||
|     var tolerance = 5; // for creating ImageBitmap from a video, the tolerance needs to be high
 | ||||
|     _assertPixelApprox(canvas, 5,5, 255,0,0,255, "5,5", "255,0,0,255", tolerance); | ||||
|     _assertPixelApprox(canvas, 15,5, 0,255,0,255, "15,5", "0,255,0,255", tolerance); | ||||
|     _assertPixelApprox(canvas, 5,15, 0,0,255,255, "5,15", "0,0,255,255", tolerance); | ||||
|     _assertPixelApprox(canvas, 15,15, 0,0,0,255, "15,15", "0,0,0,255", tolerance); | ||||
| } | ||||
| 
 | ||||
| function testDrawImageBitmap(source) | ||||
| { | ||||
|     var canvas = document.createElement("canvas"); | ||||
|     canvas.width = 20; | ||||
|     canvas.height = 20; | ||||
|     var ctx = canvas.getContext("2d"); | ||||
|     ctx.clearRect(0, 0, canvas.width, canvas.height); | ||||
|     return createImageBitmap(source).then(imageBitmap => { | ||||
|         ctx.drawImage(imageBitmap, 0, 0); | ||||
|         testCanvasDisplayingPattern(canvas); | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| function initializeTestCanvas(testCanvas) | ||||
| { | ||||
|     testCanvas.width = 20; | ||||
|     testCanvas.height = 20; | ||||
|     var testCtx = testCanvas.getContext("2d"); | ||||
|     testCtx.fillStyle = "rgb(255, 0, 0)"; | ||||
|     testCtx.fillRect(0, 0, 10, 10); | ||||
|     testCtx.fillStyle = "rgb(0, 255, 0)"; | ||||
|     testCtx.fillRect(10, 0, 10, 10); | ||||
|     testCtx.fillStyle = "rgb(0, 0, 255)"; | ||||
|     testCtx.fillRect(0, 10, 10, 10); | ||||
|     testCtx.fillStyle = "rgb(0, 0, 0)"; | ||||
|     testCtx.fillRect(10, 10, 10, 10); | ||||
| } | ||||
| 
 | ||||
| function initializeImageData(imgData, width, height) | ||||
| { | ||||
|     for (var i = 0; i < width * height * 4; i+=4) { | ||||
|         imgData.data[i] = 0; | ||||
|         imgData.data[i + 1] = 0; | ||||
|         imgData.data[i + 2] = 0; | ||||
|         imgData.data[i + 3] = 255; //alpha channel: 255
 | ||||
|     } | ||||
|     var halfWidth = width/2; | ||||
|     var halfHeight = height/2; | ||||
|     // initialize to R, G, B, Black, with each one 10*10 pixels
 | ||||
|     for (var i = 0; i < halfHeight; i++) | ||||
|         for (var j = 0; j < halfWidth; j++) | ||||
|             imgData.data[i * width * 4 + j * 4] = 255; | ||||
|     for (var i = 0; i < halfHeight; i++) | ||||
|         for (var j = halfWidth; j < width; j++) | ||||
|             imgData.data[i * width * 4 + j * 4 + 1] = 255; | ||||
|     for (var i = halfHeight; i < height; i++) | ||||
|         for (var j = 0; j < halfWidth; j++) | ||||
|             imgData.data[i * width * 4 + j * 4 + 2] = 255; | ||||
| } | ||||
|  | @ -0,0 +1,75 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <title>createImageBitmap + drawImage test</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="/common/canvas-tests.js"></script> | ||||
| <script src="common.js"></script> | ||||
| <link rel="stylesheet" href="/common/canvas-tests.css"> | ||||
| <body> | ||||
| <script> | ||||
| (function() { | ||||
|     promise_test(function() { | ||||
|         return new Promise(function(resolve, reject) { | ||||
|             var img = new Image(); | ||||
|             img.onload = function() { resolve(img); }; | ||||
|             img.src = "/images/pattern.png"; | ||||
|         }).then(function(img) { | ||||
|             return testDrawImageBitmap(img); | ||||
|         }); | ||||
|     }, "createImageBitmap from a HTMLImageElement, and drawImage on the created ImageBitmap"); | ||||
| 
 | ||||
|     promise_test(function() { | ||||
|         return new Promise(function(resolve, reject) { | ||||
|             var xhr = new XMLHttpRequest(); | ||||
|             xhr.open("GET", '/images/pattern.png'); | ||||
|             xhr.responseType = 'blob'; | ||||
|             xhr.send(); | ||||
|             xhr.onload = function() { | ||||
|                 blob = xhr.response; | ||||
|                 resolve(blob); | ||||
|             }; | ||||
|         }).then(function(blob) { | ||||
|             return testDrawImageBitmap(blob); | ||||
|         }); | ||||
|     }, "createImageBitmap from a Blob, and drawImage on the created ImageBitmap"); | ||||
| 
 | ||||
|     promise_test(function() { | ||||
|         var testCanvas = document.createElement("canvas"); | ||||
|         initializeTestCanvas(testCanvas); | ||||
|         testDrawImageBitmap(testCanvas); | ||||
|     }, "createImageBitmap from a HTMLCanvasElement, and drawImage on the created ImageBitmap"); | ||||
| 
 | ||||
|     promise_test(function() { | ||||
|         var testCanvas = document.createElement("canvas"); | ||||
|         initializeTestCanvas(testCanvas); | ||||
|         return new Promise(function(resolve, reject) { | ||||
|             createImageBitmap(testCanvas).then(function(bitmap) { | ||||
|                 resolve(bitmap); | ||||
|             }); | ||||
|         }).then(function(bitmap) { | ||||
|             return testDrawImageBitmap(bitmap); | ||||
|         }); | ||||
|     }, "createImageBitmap from an ImageBitmap, and drawImage on the created ImageBitmap"); | ||||
| 
 | ||||
|     promise_test(function() { | ||||
|         var imgData = new ImageData(20, 20); | ||||
|         initializeImageData(imgData, 20, 20); | ||||
|         return testDrawImageBitmap(imgData); | ||||
|     }, "createImageBitmap from an ImageData, and drawImage on the created ImageBitmap"); | ||||
| 
 | ||||
|     promise_test(function() { | ||||
|         return new Promise(function(resolve, reject) { | ||||
|             var video = document.createElement("video"); | ||||
|             video.oncanplaythrough = function() { | ||||
|                 resolve(video); | ||||
|             }; | ||||
|             video.src = "/images/pattern.ogv"; | ||||
|         }).then(function(video) { | ||||
|             return testDrawImageBitmap(video); | ||||
|         }); | ||||
|     }, "createImageBitmap from a HTMLVideoElement, and drawImage on the created ImageBitmap"); | ||||
| })(); | ||||
| </script> | ||||
| </body> | ||||
| </html> | ||||
|  | @ -1,14 +1,14 @@ | |||
| <!DOCTYPE html> | ||||
| <!-- DO NOT EDIT! This test has been generated by tools/gentest.py. --> | ||||
| <title>Canvas test: 2d.imageData.create2.round</title> | ||||
| <title>Canvas test: 2d.imageData.create2.double</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="/common/canvas-tests.js"></script> | ||||
| <link rel="stylesheet" href="/common/canvas-tests.css"> | ||||
| <body class="show_output"> | ||||
| 
 | ||||
| <h1>2d.imageData.create2.round</h1> | ||||
| <p class="desc">createImageData(w, h) is rounded the same as getImageData(0, 0, w, h)</p> | ||||
| <h1>2d.imageData.create2.double</h1> | ||||
| <p class="desc">createImageData(w, h) double is converted to long</p> | ||||
| 
 | ||||
| 
 | ||||
| <p class="output">Actual output:</p> | ||||
|  | @ -16,13 +16,15 @@ | |||
| 
 | ||||
| <ul id="d"></ul> | ||||
| <script> | ||||
| var t = async_test("createImageData(w, h) is rounded the same as getImageData(0, 0, w, h)"); | ||||
| var t = async_test("createImageData(w, h) double is converted to long"); | ||||
| _addTest(function(canvas, ctx) { | ||||
| 
 | ||||
| var imgdata1 = ctx.createImageData(10.01, 10.99); | ||||
| var imgdata2 = ctx.getImageData(0, 0, 10.01, 10.99); | ||||
| _assertSame(imgdata1.width, imgdata2.width, "imgdata1.width", "imgdata2.width"); | ||||
| _assertSame(imgdata1.height, imgdata2.height, "imgdata1.height", "imgdata2.height"); | ||||
| var imgdata2 = ctx.createImageData(-10.01, -10.99); | ||||
| _assertSame(imgdata1.width, 10, "imgdata1.width", "10"); | ||||
| _assertSame(imgdata1.height, 10, "imgdata1.height", "10"); | ||||
| _assertSame(imgdata2.width, 10, "imgdata2.width", "10"); | ||||
| _assertSame(imgdata2.height, 10, "imgdata2.height", "10"); | ||||
| 
 | ||||
| 
 | ||||
| }); | ||||
|  | @ -1,35 +0,0 @@ | |||
| <!DOCTYPE html> | ||||
| <!-- DO NOT EDIT! This test has been generated by tools/gentest.py. --> | ||||
| <title>Canvas test: 2d.imageData.create2.tiny</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="/common/canvas-tests.js"></script> | ||||
| <link rel="stylesheet" href="/common/canvas-tests.css"> | ||||
| <body class="show_output"> | ||||
| 
 | ||||
| <h1>2d.imageData.create2.tiny</h1> | ||||
| <p class="desc">createImageData(sw, sh) works for sizes smaller than one pixel</p> | ||||
| 
 | ||||
| 
 | ||||
| <p class="output">Actual output:</p> | ||||
| <canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> | ||||
| 
 | ||||
| <ul id="d"></ul> | ||||
| <script> | ||||
| var t = async_test("createImageData(sw, sh) works for sizes smaller than one pixel"); | ||||
| _addTest(function(canvas, ctx) { | ||||
| 
 | ||||
| var imgdata = ctx.createImageData(0.0001, 0.0001); | ||||
| _assertSame(imgdata.data.length, imgdata.width*imgdata.height*4, "imgdata.data.length", "imgdata.width*imgdata.height*4"); | ||||
| _assertSame(imgdata.width, 1, "imgdata.width", "1"); | ||||
| _assertSame(imgdata.height, 1, "imgdata.height", "1"); | ||||
| var isTransparentBlack = true; | ||||
| for (var i = 0; i < imgdata.data.length; ++i) | ||||
|     if (imgdata.data[i] !== 0) | ||||
|         isTransparentBlack = false; | ||||
| _assert(isTransparentBlack, "isTransparentBlack"); | ||||
| 
 | ||||
| 
 | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
|  | @ -22,6 +22,8 @@ _addTest(function(canvas, ctx) { | |||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.createImageData(10, 0); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.createImageData(0, 10); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.createImageData(0, 0); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.createImageData(0.99, 10); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.createImageData(10, 0.1); }); | ||||
| 
 | ||||
| 
 | ||||
| }); | ||||
|  |  | |||
|  | @ -0,0 +1,32 @@ | |||
| <!DOCTYPE html> | ||||
| <!-- DO NOT EDIT! This test has been generated by tools/gentest.py. --> | ||||
| <title>Canvas test: 2d.imageData.get.double</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="/common/canvas-tests.js"></script> | ||||
| <link rel="stylesheet" href="/common/canvas-tests.css"> | ||||
| <body class="show_output"> | ||||
| 
 | ||||
| <h1>2d.imageData.get.double</h1> | ||||
| <p class="desc">createImageData(w, h) double is converted to long</p> | ||||
| 
 | ||||
| 
 | ||||
| <p class="output">Actual output:</p> | ||||
| <canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> | ||||
| 
 | ||||
| <ul id="d"></ul> | ||||
| <script> | ||||
| var t = async_test("createImageData(w, h) double is converted to long"); | ||||
| _addTest(function(canvas, ctx) { | ||||
| 
 | ||||
| var imgdata1 = ctx.getImageData(0, 0, 10.01, 10.99); | ||||
| var imgdata2 = ctx.getImageData(0, 0, -10.01, -10.99); | ||||
| _assertSame(imgdata1.width, 10, "imgdata1.width", "10"); | ||||
| _assertSame(imgdata1.height, 10, "imgdata1.height", "10"); | ||||
| _assertSame(imgdata2.width, 10, "imgdata2.width", "10"); | ||||
| _assertSame(imgdata2.height, 10, "imgdata2.height", "10"); | ||||
| 
 | ||||
| 
 | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
|  | @ -22,6 +22,10 @@ _addTest(function(canvas, ctx) { | |||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.getImageData(1, 1, 10, 0); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.getImageData(1, 1, 0, 10); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.getImageData(1, 1, 0, 0); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.getImageData(1, 1, 0.1, 10); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.getImageData(1, 1, 10, 0.99); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.getImageData(1, 1, -0.1, 10); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { ctx.getImageData(1, 1, 10, -0.99); }); | ||||
| 
 | ||||
| 
 | ||||
| }); | ||||
|  |  | |||
|  | @ -0,0 +1,34 @@ | |||
| <!DOCTYPE html> | ||||
| <!-- DO NOT EDIT! This test has been generated by tools/gentest.py. --> | ||||
| <title>Canvas test: 2d.imageData.object.ctor.array.bounds</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="/common/canvas-tests.js"></script> | ||||
| <link rel="stylesheet" href="/common/canvas-tests.css"> | ||||
| <body class="show_output"> | ||||
| 
 | ||||
| <h1>2d.imageData.object.ctor.array.bounds</h1> | ||||
| <p class="desc">ImageData has a usable constructor</p> | ||||
| 
 | ||||
| 
 | ||||
| <p class="output">Actual output:</p> | ||||
| <canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> | ||||
| 
 | ||||
| <ul id="d"></ul> | ||||
| <script> | ||||
| var t = async_test("ImageData has a usable constructor"); | ||||
| _addTest(function(canvas, ctx) { | ||||
| 
 | ||||
| _assertDifferent(window.ImageData, undefined, "window.ImageData", "undefined"); | ||||
| 
 | ||||
| assert_throws("INVALID_STATE_ERR", function() { new ImageData(new Uint8ClampedArray(0), 1); }); | ||||
| assert_throws("INVALID_STATE_ERR", function() { new ImageData(new Uint8ClampedArray(3), 1); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { new ImageData(new Uint8ClampedArray(4), 0); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { new ImageData(new Uint8ClampedArray(4), 1, 2); }); | ||||
| assert_throws(new TypeError(), function() { new ImageData(new Uint8Array(8), 1, 2); }); | ||||
| assert_throws(new TypeError(), function() { new ImageData(new Int8Array(8), 1, 2); }); | ||||
| 
 | ||||
| 
 | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
|  | @ -1,14 +1,14 @@ | |||
| <!DOCTYPE html> | ||||
| <!-- DO NOT EDIT! This test has been generated by tools/gentest.py. --> | ||||
| <title>Canvas test: 2d.imageData.get.tiny</title> | ||||
| <title>Canvas test: 2d.imageData.object.ctor.array</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="/common/canvas-tests.js"></script> | ||||
| <link rel="stylesheet" href="/common/canvas-tests.css"> | ||||
| <body class="show_output"> | ||||
| 
 | ||||
| <h1>2d.imageData.get.tiny</h1> | ||||
| <p class="desc">getImageData() works for sizes smaller than one pixel</p> | ||||
| <h1>2d.imageData.object.ctor.array</h1> | ||||
| <p class="desc">ImageData has a usable constructor</p> | ||||
| 
 | ||||
| 
 | ||||
| <p class="output">Actual output:</p> | ||||
|  | @ -16,13 +16,16 @@ | |||
| 
 | ||||
| <ul id="d"></ul> | ||||
| <script> | ||||
| var t = async_test("getImageData() works for sizes smaller than one pixel"); | ||||
| var t = async_test("ImageData has a usable constructor"); | ||||
| _addTest(function(canvas, ctx) { | ||||
| 
 | ||||
| var imgdata = ctx.getImageData(0, 0, 0.0001, 0.0001); | ||||
| _assertSame(imgdata.data.length, imgdata.width*imgdata.height*4, "imgdata.data.length", "imgdata.width*imgdata.height*4"); | ||||
| _assertDifferent(window.ImageData, undefined, "window.ImageData", "undefined"); | ||||
| 
 | ||||
| var array = new Uint8ClampedArray(8); | ||||
| var imgdata = new window.ImageData(array, 1, 2); | ||||
| _assertSame(imgdata.width, 1, "imgdata.width", "1"); | ||||
| _assertSame(imgdata.height, 1, "imgdata.height", "1"); | ||||
| _assertSame(imgdata.height, 2, "imgdata.height", "2"); | ||||
| _assertSame(imgdata.data, array, "imgdata.data", "array"); | ||||
| 
 | ||||
| 
 | ||||
| }); | ||||
|  | @ -1,14 +1,14 @@ | |||
| <!DOCTYPE html> | ||||
| <!-- DO NOT EDIT! This test has been generated by tools/gentest.py. --> | ||||
| <title>Canvas test: 2d.imageData.object.ctor</title> | ||||
| <title>Canvas test: 2d.imageData.object.ctor.size.bounds</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="/common/canvas-tests.js"></script> | ||||
| <link rel="stylesheet" href="/common/canvas-tests.css"> | ||||
| <body class="show_output"> | ||||
| 
 | ||||
| <h1>2d.imageData.object.ctor</h1> | ||||
| <p class="desc">ImageData does not have a usable constructor</p> | ||||
| <h1>2d.imageData.object.ctor.size.bounds</h1> | ||||
| <p class="desc">ImageData has a usable constructor</p> | ||||
| 
 | ||||
| 
 | ||||
| <p class="output">Actual output:</p> | ||||
|  | @ -16,11 +16,13 @@ | |||
| 
 | ||||
| <ul id="d"></ul> | ||||
| <script> | ||||
| var t = async_test("ImageData does not have a usable constructor"); | ||||
| var t = async_test("ImageData has a usable constructor"); | ||||
| _addTest(function(canvas, ctx) { | ||||
| 
 | ||||
| _assertDifferent(window.ImageData, undefined, "window.ImageData", "undefined"); | ||||
| assert_throws(new TypeError(), function() { new window.ImageData(1,1); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { new window.ImageData(0, 0); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { new window.ImageData(0, 1); }); | ||||
| assert_throws("INDEX_SIZE_ERR", function() { new window.ImageData(1, 0); }); | ||||
| 
 | ||||
| 
 | ||||
| }); | ||||
|  | @ -0,0 +1,35 @@ | |||
| <!DOCTYPE html> | ||||
| <!-- DO NOT EDIT! This test has been generated by tools/gentest.py. --> | ||||
| <title>Canvas test: 2d.imageData.object.ctor.size</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="/common/canvas-tests.js"></script> | ||||
| <link rel="stylesheet" href="/common/canvas-tests.css"> | ||||
| <body class="show_output"> | ||||
| 
 | ||||
| <h1>2d.imageData.object.ctor.size</h1> | ||||
| <p class="desc">ImageData has a usable constructor</p> | ||||
| 
 | ||||
| 
 | ||||
| <p class="output">Actual output:</p> | ||||
| <canvas id="c" class="output" width="100" height="50"><p class="fallback">FAIL (fallback content)</p></canvas> | ||||
| 
 | ||||
| <ul id="d"></ul> | ||||
| <script> | ||||
| var t = async_test("ImageData has a usable constructor"); | ||||
| _addTest(function(canvas, ctx) { | ||||
| 
 | ||||
| _assertDifferent(window.ImageData, undefined, "window.ImageData", "undefined"); | ||||
| 
 | ||||
| var imgdata = new window.ImageData(2, 3); | ||||
| _assertSame(imgdata.width, 2, "imgdata.width", "2"); | ||||
| _assertSame(imgdata.height, 3, "imgdata.height", "3"); | ||||
| _assertSame(imgdata.data.length, 2 * 3 * 4, "imgdata.data.length", "2 * 3 * 4"); | ||||
| for (var i = 0; i < imgdata.data.length; ++i) { | ||||
|   _assertSame(imgdata.data[i], 0, "imgdata.data[\""+(i)+"\"]", "0"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
|  | @ -9276,22 +9276,6 @@ | |||
|             isTransparentBlack = false; | ||||
|     @assert isTransparentBlack; | ||||
| 
 | ||||
| - name: 2d.imageData.create2.tiny | ||||
|   desc: createImageData(sw, sh) works for sizes smaller than one pixel | ||||
|   testing: | ||||
|     - 2d.imageData.create2.size | ||||
|     - 2d.imageData.one | ||||
|   code: | | ||||
|     var imgdata = ctx.createImageData(0.0001, 0.0001); | ||||
|     @assert imgdata.data.length === imgdata.width*imgdata.height*4; | ||||
|     @assert imgdata.width === 1; | ||||
|     @assert imgdata.height === 1; | ||||
|     var isTransparentBlack = true; | ||||
|     for (var i = 0; i < imgdata.data.length; ++i) | ||||
|         if (imgdata.data[i] !== 0) | ||||
|             isTransparentBlack = false; | ||||
|     @assert isTransparentBlack; | ||||
| 
 | ||||
| - name: 2d.imageData.create2.negative | ||||
|   desc: createImageData(sw, sh) takes the absolute magnitude of the size arguments | ||||
|   testing: | ||||
|  | @ -9313,6 +9297,8 @@ | |||
|     @assert throws INDEX_SIZE_ERR ctx.createImageData(10, 0); | ||||
|     @assert throws INDEX_SIZE_ERR ctx.createImageData(0, 10); | ||||
|     @assert throws INDEX_SIZE_ERR ctx.createImageData(0, 0); | ||||
|     @assert throws INDEX_SIZE_ERR ctx.createImageData(0.99, 10); | ||||
|     @assert throws INDEX_SIZE_ERR ctx.createImageData(10, 0.1); | ||||
| 
 | ||||
| - name: 2d.imageData.create2.nonfinite | ||||
|   desc: createImageData() throws TypeError if arguments are not finite | ||||
|  | @ -9333,15 +9319,17 @@ | |||
|   code: | | ||||
|     @assert throws TypeError ctx.createImageData(null); | ||||
| 
 | ||||
| - name: 2d.imageData.create2.round | ||||
|   desc: createImageData(w, h) is rounded the same as getImageData(0, 0, w, h) | ||||
| - name: 2d.imageData.create2.double | ||||
|   desc: createImageData(w, h) double is converted to long | ||||
|   testing: | ||||
|     - 2d.imageData.createround | ||||
|     - 2d.imageData.create2.size | ||||
|   code: | | ||||
|     var imgdata1 = ctx.createImageData(10.01, 10.99); | ||||
|     var imgdata2 = ctx.getImageData(0, 0, 10.01, 10.99); | ||||
|     @assert imgdata1.width === imgdata2.width; | ||||
|     @assert imgdata1.height === imgdata2.height; | ||||
|     var imgdata2 = ctx.createImageData(-10.01, -10.99); | ||||
|     @assert imgdata1.width === 10; | ||||
|     @assert imgdata1.height === 10; | ||||
|     @assert imgdata2.width === 10; | ||||
|     @assert imgdata2.height === 10; | ||||
| 
 | ||||
| - name: 2d.imageData.get.basic | ||||
|   desc: getImageData() exists and returns something | ||||
|  | @ -9371,6 +9359,10 @@ | |||
|     @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, 0); | ||||
|     @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0, 10); | ||||
|     @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0, 0); | ||||
|     @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 0.1, 10); | ||||
|     @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, 0.99); | ||||
|     @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, -0.1, 10); | ||||
|     @assert throws INDEX_SIZE_ERR ctx.getImageData(1, 1, 10, -0.99); | ||||
| 
 | ||||
| - name: 2d.imageData.get.nonfinite | ||||
|   desc: getImageData() throws TypeError if arguments are not finite | ||||
|  | @ -9488,15 +9480,17 @@ | |||
|     @assert imgdata2.width > imgdata1.width; | ||||
|     @assert imgdata2.height > imgdata1.height; | ||||
| 
 | ||||
| - name: 2d.imageData.get.tiny | ||||
|   desc: getImageData() works for sizes smaller than one pixel | ||||
| - name: 2d.imageData.get.double | ||||
|   desc: createImageData(w, h) double is converted to long | ||||
|   testing: | ||||
|     - 2d.imageData.one | ||||
|     - 2d.imageData.get.basic | ||||
|   code: | | ||||
|     var imgdata = ctx.getImageData(0, 0, 0.0001, 0.0001); | ||||
|     @assert imgdata.data.length === imgdata.width*imgdata.height*4; | ||||
|     @assert imgdata.width === 1; | ||||
|     @assert imgdata.height === 1; | ||||
|     var imgdata1 = ctx.getImageData(0, 0, 10.01, 10.99); | ||||
|     var imgdata2 = ctx.getImageData(0, 0, -10.01, -10.99); | ||||
|     @assert imgdata1.width === 10; | ||||
|     @assert imgdata1.height === 10; | ||||
|     @assert imgdata2.width === 10; | ||||
|     @assert imgdata2.height === 10; | ||||
| 
 | ||||
| - name: 2d.imageData.get.nonpremul | ||||
|   desc: getImageData() returns non-premultiplied colours | ||||
|  | @ -9664,13 +9658,57 @@ | |||
|     @assert imgdata.data[2] === 0; | ||||
|     @assert imgdata.data[3] === 0; | ||||
| 
 | ||||
| - name: 2d.imageData.object.ctor | ||||
|   desc: ImageData does not have a usable constructor | ||||
| - name: 2d.imageData.object.ctor.size | ||||
|   desc: ImageData has a usable constructor | ||||
|   testing: | ||||
|     - 2d.imageData.type | ||||
|   code: | | ||||
|     @assert window.ImageData !== undefined; | ||||
|     @assert throws TypeError new window.ImageData(1,1); | ||||
| 
 | ||||
|     var imgdata = new window.ImageData(2, 3); | ||||
|     @assert imgdata.width === 2; | ||||
|     @assert imgdata.height === 3; | ||||
|     @assert imgdata.data.length === 2 * 3 * 4; | ||||
|     for (var i = 0; i < imgdata.data.length; ++i) { | ||||
|       @assert imgdata.data[i] === 0; | ||||
|     } | ||||
| 
 | ||||
| - name: 2d.imageData.object.ctor.size.bounds | ||||
|   desc: ImageData has a usable constructor | ||||
|   testing: | ||||
|     - 2d.imageData.type | ||||
|   code: | | ||||
|     @assert window.ImageData !== undefined; | ||||
|     @assert throws INDEX_SIZE_ERR new window.ImageData(0, 0); | ||||
|     @assert throws INDEX_SIZE_ERR new window.ImageData(0, 1); | ||||
|     @assert throws INDEX_SIZE_ERR new window.ImageData(1, 0); | ||||
| 
 | ||||
| - name: 2d.imageData.object.ctor.array | ||||
|   desc: ImageData has a usable constructor | ||||
|   testing: | ||||
|     - 2d.imageData.type | ||||
|   code: | | ||||
|     @assert window.ImageData !== undefined; | ||||
| 
 | ||||
|     var array = new Uint8ClampedArray(8); | ||||
|     var imgdata = new window.ImageData(array, 1, 2); | ||||
|     @assert imgdata.width === 1; | ||||
|     @assert imgdata.height === 2; | ||||
|     @assert imgdata.data === array; | ||||
| 
 | ||||
| - name: 2d.imageData.object.ctor.array.bounds | ||||
|   desc: ImageData has a usable constructor | ||||
|   testing: | ||||
|     - 2d.imageData.type | ||||
|   code: | | ||||
|     @assert window.ImageData !== undefined; | ||||
| 
 | ||||
|     @assert throws INVALID_STATE_ERR new ImageData(new Uint8ClampedArray(0), 1); | ||||
|     @assert throws INVALID_STATE_ERR new ImageData(new Uint8ClampedArray(3), 1); | ||||
|     @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray(4), 0); | ||||
|     @assert throws INDEX_SIZE_ERR new ImageData(new Uint8ClampedArray(4), 1, 2); | ||||
|     @assert throws TypeError new ImageData(new Uint8Array(8), 1, 2); | ||||
|     @assert throws TypeError new ImageData(new Int8Array(8), 1, 2); | ||||
| 
 | ||||
| - name: 2d.imageData.object.set | ||||
|   desc: ImageData.data can be modified | ||||
|  |  | |||
|  | @ -27,3 +27,8 @@ non-infringement, or title; nor that the contents of this repository are | |||
| suitable for any purpose. We make no representations, express or implied, that | ||||
| the content of this repository or the use thereof indicates conformance to a | ||||
| specification. All content is provided as-is to help reach interoperability. | ||||
| 
 | ||||
| Documentation | ||||
| ------------- | ||||
| 
 | ||||
| See [web-platform-tests.org](http://web-platform-tests.org/). | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
|   <title>Historical features</title> | ||||
|   <script src="/resources/testharness.js"></script> | ||||
|   <script src="/resources/testharnessreport.js"></script> | ||||
|   <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> | ||||
|  </head> | ||||
|  <body> | ||||
|   <div id="log"></div> | ||||
|  | @ -48,6 +49,10 @@ | |||
|         assert_false('isClosed' in b, 'isClosed in b'); | ||||
|         assert_false('isClosed' in Blob.prototype, 'isClosed in Blob.prototype'); | ||||
|     }, 'Blob.close() should not be supported'); | ||||
| 
 | ||||
|     // Only add service worker test if service workers are actually supported. | ||||
|     if (navigator.serviceWorker) | ||||
|       service_worker_test('support/historical-serviceworker.js', 'Service worker test setup'); | ||||
|   </script> | ||||
|  </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,5 @@ | |||
| importScripts('/resources/testharness.js'); | ||||
| 
 | ||||
| test(() => { | ||||
|   assert_false('FileReaderSync' in self); | ||||
| }, '"FileReaderSync" should not be supported in service workers'); | ||||
|  | @ -1,4 +1,5 @@ | |||
| <!DOCTYPE html> | ||||
| <meta charset=utf-8> | ||||
| <title>IDBCursor direction - index with keyrange</title> | ||||
| <link rel="author" href="mailto:odinho@opera.com" title="Odin Hørthe Omdal"> | ||||
| <link rel=help href="http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#cursor-iteration-operation"> | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| <!DOCTYPE html> | ||||
| <meta charset=utf-8> | ||||
| <title>IDBCursor direction - object store with keyrange</title> | ||||
| <link rel="author" href="mailto:odinho@opera.com" title="Odin Hørthe Omdal"> | ||||
| <link rel=help href="http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#cursor-iteration-operation"> | ||||
|  |  | |||
|  | @ -0,0 +1,28 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <title>IndexedDB: Test IDBFactory open() error event properties</title> | ||||
| <meta name=help href="https://w3c.github.io/IndexedDB/#dom-idbfactory-open"> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="support.js"></script> | ||||
| <script> | ||||
| 
 | ||||
| async_test(t => { | ||||
|   const dbname = document.location + '-' + t.name; | ||||
|   indexedDB.deleteDatabase(dbname); | ||||
|   const open = indexedDB.open(dbname); | ||||
|   open.onsuccess = t.unreached_func('open should not succeed'); | ||||
|   open.onupgradeneeded = t.step_func(() => { | ||||
|     const tx = open.transaction; | ||||
|     tx.abort(); | ||||
|   }); | ||||
|   open.onerror = t.step_func(e => { | ||||
|     assert_equals(e.target, open, 'event target should be request'); | ||||
|     assert_equals(e.type, 'error', 'Event type should be error'); | ||||
|     assert_true(e.bubbles, 'Event should bubble'); | ||||
|     assert_true(e.cancelable, 'Event should be cancelable'); | ||||
|     t.done(); | ||||
|   }); | ||||
| }, 'Properties of error event from failed open()'); | ||||
| 
 | ||||
| </script> | ||||
|  | @ -0,0 +1,52 @@ | |||
| <!DOCTYPE html> | ||||
| <meta charset=utf-8> | ||||
| <title>IDBObjectStore.createIndex() - AutoIncrement in Compound Index</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="support.js"></script> | ||||
| <script> | ||||
|   indexeddb_test( | ||||
|     function(t, db, txn) { | ||||
|       // No auto-increment | ||||
|       var store = db.createObjectStore("Store1", {keyPath: "id"}); | ||||
|       store.createIndex("CompoundKey", ["num", "id"]); | ||||
| 
 | ||||
|       // Add data | ||||
|       store.put({id: 1, num: 100}); | ||||
|     }, | ||||
|     function(t, db) { | ||||
|       var store = db.transaction("Store1", "readwrite").objectStore("Store1"); | ||||
| 
 | ||||
|       store.openCursor().onsuccess = t.step_func(function(e) { | ||||
|         var item = e.target.result.value; | ||||
|         store.index("CompoundKey").get([item.num, item.id]).onsuccess = t.step_func(function(e) { | ||||
|           assert_equals(e.target.result ? e.target.result.num : null, 100, 'Expected 100.'); | ||||
|           t.done(); | ||||
|         }); | ||||
|       }); | ||||
|     }, | ||||
|     "Explicit Primary Key" | ||||
|   ); | ||||
| 
 | ||||
|   indexeddb_test( | ||||
|     function(t, db, txn) { | ||||
|       // Auto-increment | ||||
|       var store = db.createObjectStore("Store2", {keyPath: "id", autoIncrement: true}); | ||||
|       store.createIndex("CompoundKey", ["num", "id"]); | ||||
| 
 | ||||
|       // Add data | ||||
|       store.put({num: 100}); | ||||
|     }, | ||||
|     function(t, db) { | ||||
|       var store = db.transaction("Store2", "readwrite").objectStore("Store2"); | ||||
|       store.openCursor().onsuccess = t.step_func(function(e) { | ||||
|         var item = e.target.result.value; | ||||
|         store.index("CompoundKey").get([item.num, item.id]).onsuccess = t.step_func(function(e) { | ||||
|           assert_equals(e.target.result ? e.target.result.num : null, 100, 'Expected 100.'); | ||||
|           t.done(); | ||||
|         }); | ||||
|       }); | ||||
|     }, | ||||
|     "Auto-Increment Primary Key" | ||||
|   ); | ||||
| </script> | ||||
							
								
								
									
										196
									
								
								testing/web-platform/tests/IndexedDB/interleaved-cursors.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								testing/web-platform/tests/IndexedDB/interleaved-cursors.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,196 @@ | |||
| <!doctype html> | ||||
| <meta charset="utf-8"> | ||||
| <meta name="timeout" content="long"> | ||||
| <title>IndexedDB: Interleaved iteration of multiple cursors</title> | ||||
| <link rel="author" href="pwnall@chromium.org" title="Victor Costan"> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="support-promises.js"></script> | ||||
| <script> | ||||
| // Number of objects that each iterator goes over. | ||||
| const itemCount = 10; | ||||
| 
 | ||||
| // Ratio of small objects to large objects. | ||||
| const largeObjectRatio = 5; | ||||
| 
 | ||||
| // Size of large objects. This should exceed the size of a block in the storage | ||||
| // method underlying the browser's IndexedDB implementation. For example, this | ||||
| // needs to exceed the LevelDB block size on Chrome, and the SQLite block size | ||||
| // on Firefox. | ||||
| const largeObjectSize = 48 * 1024; | ||||
| 
 | ||||
| function objectKey(cursorIndex, itemIndex) { | ||||
|   return `${cursorIndex}-key-${itemIndex}`; | ||||
| } | ||||
| 
 | ||||
| function objectValue(cursorIndex, itemIndex) { | ||||
|   if ((cursorIndex * itemCount + itemIndex) % largeObjectRatio === 0) { | ||||
|     // We use a typed array (as opposed to a string) because IndexedDB | ||||
|     // implementations may serialize strings using UTF-8 or UTF-16, yielding | ||||
|     // larger IndexedDB entries than we'd expect. It's very unlikely that an | ||||
|     // IndexedDB implementation would use anything other than the raw buffer to | ||||
|     // serialize a typed array. | ||||
|     const buffer = new Uint8Array(largeObjectSize); | ||||
| 
 | ||||
|     // Some IndexedDB implementations, like LevelDB, compress their data blocks | ||||
|     // before storing them to disk. We use a simple 32-bit xorshift PRNG, which | ||||
|     // should be sufficient to foil any fast generic-purpose compression scheme. | ||||
| 
 | ||||
|     // 32-bit xorshift - the seed can't be zero | ||||
|     let state = 1000 + (cursorIndex * itemCount + itemIndex); | ||||
| 
 | ||||
|     for (let i = 0; i < largeObjectSize; ++i) { | ||||
|       state ^= state << 13; | ||||
|       state ^= state >> 17; | ||||
|       state ^= state << 5; | ||||
|       buffer[i] = state & 0xff; | ||||
|     } | ||||
| 
 | ||||
|     return buffer; | ||||
|   } | ||||
|   return [cursorIndex, 'small', itemIndex]; | ||||
| } | ||||
| 
 | ||||
| // Writes the objects to be read by one cursor. Returns a promise that resolves | ||||
| // when the write completes. | ||||
| // | ||||
| // We want to avoid creating a large transaction, because that is outside the | ||||
| // test's scope, and it's a bad practice. So we break up the writes across | ||||
| // multiple transactions. For simplicity, each transaction writes all the | ||||
| // objects that will be read by a cursor. | ||||
| function writeCursorObjects(database, cursorIndex) { | ||||
|   return new Promise((resolve, reject) => { | ||||
|     const transaction = database.transaction('cache', 'readwrite'); | ||||
|     transaction.onabort = () => { reject(transaction.error); }; | ||||
| 
 | ||||
|     const store = transaction.objectStore('cache'); | ||||
|     for (let i = 0; i < itemCount; ++i) { | ||||
|       store.put({ | ||||
|           key: objectKey(cursorIndex, i), value: objectValue(cursorIndex, i)}); | ||||
|     } | ||||
|     transaction.oncomplete = resolve; | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // Returns a promise that resolves when the store has been populated. | ||||
| function populateTestStore(testCase, database, cursorCount) { | ||||
|   let promiseChain = Promise.resolve(); | ||||
| 
 | ||||
|   for (let i = 0; i < cursorCount; ++i) | ||||
|     promiseChain = promiseChain.then(() => writeCursorObjects(database, i)); | ||||
| 
 | ||||
|   return promiseChain; | ||||
| } | ||||
| 
 | ||||
| // Reads cursors in an interleaved fashion, as shown below. | ||||
| // | ||||
| // Given N cursors, each of which points to the beginning of a K-item sequence, | ||||
| // the following accesses will be made. | ||||
| // | ||||
| // OC(i)    = open cursor i | ||||
| // RD(i, j) = read result of cursor i, which should be at item j | ||||
| // CC(i)    = continue cursor i | ||||
| // |        = wait for onsuccess on the previous OC or CC | ||||
| // | ||||
| // OC(1)            | RD(1, 1) OC(2) | RD(2, 1) OC(3) | ... | RD(n-1, 1) CC(n) | | ||||
| // RD(n, 1)   CC(1) | RD(1, 2) CC(2) | RD(2, 2) CC(3) | ... | RD(n-1, 2) CC(n) | | ||||
| // RD(n, 2)   CC(1) | RD(1, 3) CC(2) | RD(2, 3) CC(3) | ... | RD(n-1, 3) CC(n) | | ||||
| // ... | ||||
| // RD(n, k-1) CC(1) | RD(1, k) CC(2) | RD(2, k) CC(3) | ... | RD(n-1, k) CC(n) | | ||||
| // RD(n, k)           done | ||||
| function interleaveCursors(testCase, store, cursorCount) { | ||||
|   return new Promise((resolve, reject) => { | ||||
|     // The cursors used for iteration are stored here so each cursor's onsuccess | ||||
|     // handler can call continue() on the next cursor. | ||||
|     const cursors = []; | ||||
| 
 | ||||
|     // The results of IDBObjectStore.openCursor() calls are stored here so we | ||||
|     // we can change the requests' onsuccess handler after every | ||||
|     // IDBCursor.continue() call. | ||||
|     const requests = []; | ||||
| 
 | ||||
|     const checkCursorState = (cursorIndex, itemIndex) => { | ||||
|       const cursor = cursors[cursorIndex]; | ||||
|       assert_equals(cursor.key, objectKey(cursorIndex, itemIndex)); | ||||
|       assert_equals(cursor.value.key, objectKey(cursorIndex, itemIndex)); | ||||
|       assert_equals( | ||||
|           cursor.value.value.join('-'), | ||||
|           objectValue(cursorIndex, itemIndex).join('-')); | ||||
|     }; | ||||
| 
 | ||||
|     const openCursor = (cursorIndex, callback) => { | ||||
|       const request = store.openCursor( | ||||
|           IDBKeyRange.lowerBound(objectKey(cursorIndex, 0))); | ||||
|       requests[cursorIndex] = request; | ||||
| 
 | ||||
|       request.onsuccess = testCase.step_func(() => { | ||||
|         const cursor = request.result; | ||||
|         cursors[cursorIndex] = cursor; | ||||
|         checkCursorState(cursorIndex, 0); | ||||
|         callback(); | ||||
|       }); | ||||
|       request.onerror = event => reject(request.error); | ||||
|     }; | ||||
| 
 | ||||
|     const readItemFromCursor = (cursorIndex, itemIndex, callback) => { | ||||
|       const request = requests[cursorIndex]; | ||||
|       request.onsuccess = testCase.step_func(() => { | ||||
|         const cursor = request.result; | ||||
|         cursors[cursorIndex] = cursor; | ||||
|         checkCursorState(cursorIndex, itemIndex); | ||||
|         callback(); | ||||
|       }); | ||||
| 
 | ||||
|       const cursor = cursors[cursorIndex]; | ||||
|       cursor.continue(); | ||||
|     }; | ||||
| 
 | ||||
|     // We open all the cursors one at a time, then cycle through the cursors and | ||||
|     // call continue() on each of them. This access pattern causes maximal | ||||
|     // trashing to an LRU cursor cache. Eviction scheme aside, any cache will | ||||
|     // have to evict some cursors, and this access pattern verifies that the | ||||
|     // cache correctly restores the state of evicted cursors. | ||||
|     const steps = []; | ||||
|     for (let cursorIndex = 0; cursorIndex < cursorCount; ++cursorIndex) | ||||
|       steps.push(openCursor.bind(null, cursorIndex)); | ||||
|     for (let itemIndex = 1; itemIndex < itemCount; ++itemIndex) { | ||||
|       for (let cursorIndex = 0; cursorIndex < cursorCount; ++cursorIndex) | ||||
|         steps.push(readItemFromCursor.bind(null, cursorIndex, itemIndex)); | ||||
|     } | ||||
| 
 | ||||
|     const runStep = (stepIndex) => { | ||||
|       if (stepIndex === steps.length) { | ||||
|         resolve(); | ||||
|         return; | ||||
|       } | ||||
|       steps[stepIndex](() => { runStep(stepIndex + 1); }); | ||||
|     }; | ||||
|     runStep(0); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| for (let cursorCount of [1, 10, 100, 500]) { | ||||
|   promise_test(testCase => { | ||||
|     return createDatabase(testCase, (database, transaction) => { | ||||
|       const store = database.createObjectStore('cache', | ||||
|           { keyPath: 'key', autoIncrement: true }); | ||||
|     }).then(database => { | ||||
|       return populateTestStore(testCase, database, cursorCount).then( | ||||
|           () => database); | ||||
|     }).then(database => { | ||||
|       database.close(); | ||||
|     }).then(() => { | ||||
|       return openDatabase(testCase); | ||||
|     }).then(database => { | ||||
|       const transaction = database.transaction('cache', 'readonly'); | ||||
|       transaction.onabort = () => { reject(transaction.error); }; | ||||
| 
 | ||||
|       const store = transaction.objectStore('cache'); | ||||
|       return interleaveCursors(testCase, store, cursorCount).then( | ||||
|           () => database); | ||||
|     }).then(database => { | ||||
|       database.close(); | ||||
|     }); | ||||
|   }, `${cursorCount} cursors`); | ||||
| } | ||||
| </script> | ||||
|  | @ -0,0 +1,52 @@ | |||
| <!doctype html> | ||||
| <meta charset="utf-8"> | ||||
| <meta name="timeout" content="long"> | ||||
| <title>IndexedDB: Parallel iteration of cursors in upgradeneeded</title> | ||||
| <link rel="author" href="pwnall@chromium.org" title="Victor Costan"> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="support-promises.js"></script> | ||||
| <script> | ||||
| 'use strict'; | ||||
| 
 | ||||
| for (let cursorCount of [2, 10, 100, 1000, 10000]) { | ||||
|   promise_test(testCase => { | ||||
|     return createDatabase(testCase, (database, transaction) => { | ||||
|       const store = database.createObjectStore('cache', { keyPath: 'key' }); | ||||
|       store.put({ key: '42' }); | ||||
| 
 | ||||
|       const promises = []; | ||||
| 
 | ||||
|       for (let j = 0; j < 2; j += 1) { | ||||
|         const promise = new Promise((resolve, reject) => { | ||||
|           let request = null; | ||||
|           for (let i = 0; i < cursorCount / 2; i += 1) { | ||||
|             request = store.openCursor(); | ||||
|           } | ||||
| 
 | ||||
|           let continued = false; | ||||
|           request.onsuccess = testCase.step_func(() => { | ||||
|             const cursor = request.result; | ||||
| 
 | ||||
|             if (!continued) { | ||||
|               assert_equals(cursor.key, '42'); | ||||
|               assert_equals(cursor.value.key, '42'); | ||||
|               continued = true; | ||||
|               cursor.continue(); | ||||
|             } else { | ||||
|               assert_equals(cursor, null); | ||||
|               resolve(); | ||||
|             } | ||||
|           }); | ||||
|           request.onerror = () => reject(request.error); | ||||
|         }); | ||||
|         promises.push(promise); | ||||
|       } | ||||
|       return Promise.all(promises); | ||||
|     }).then(database => { | ||||
|       database.close(); | ||||
|     }); | ||||
|   }, `${cursorCount} cursors`); | ||||
| } | ||||
| 
 | ||||
| </script> | ||||
|  | @ -21,7 +21,7 @@ function requestWatcher(testCase, request) { | |||
| // open request.
 | ||||
| //
 | ||||
| // Returns a promise. If the versionchange transaction goes through, the promise
 | ||||
| // resolves to an IndexedDB database that must be closed by the caller. If the
 | ||||
| // resolves to an IndexedDB database that should be closed by the caller. If the
 | ||||
| // versionchange transaction is aborted, the promise resolves to an error.
 | ||||
| function migrateDatabase(testCase, newVersion, migrationCallback) { | ||||
|   return migrateNamedDatabase( | ||||
|  | @ -37,7 +37,7 @@ function migrateDatabase(testCase, newVersion, migrationCallback) { | |||
| // open request.
 | ||||
| //
 | ||||
| // Returns a promise. If the versionchange transaction goes through, the promise
 | ||||
| // resolves to an IndexedDB database that must be closed by the caller. If the
 | ||||
| // resolves to an IndexedDB database that should be closed by the caller. If the
 | ||||
| // versionchange transaction is aborted, the promise resolves to an error.
 | ||||
| function migrateNamedDatabase( | ||||
|     testCase, databaseName, newVersion, migrationCallback) { | ||||
|  | @ -88,10 +88,20 @@ function migrateNamedDatabase( | |||
|       resolve(Promise.resolve(callbackResult).then(() => requestEventPromise)); | ||||
|     }); | ||||
|     request.onerror = event => reject(event.target.error); | ||||
|     request.onsuccess = () => reject(new Error( | ||||
|         'indexedDB.open should not succeed without creating a ' + | ||||
|         'versionchange transaction')); | ||||
|   }).then(event => event.target.result || event.target.error); | ||||
|     request.onsuccess = () => { | ||||
|       const database = request.result; | ||||
|       testCase.add_cleanup(() => { database.close(); }); | ||||
|       reject(new Error( | ||||
|           'indexedDB.open should not succeed without creating a ' + | ||||
|           'versionchange transaction')); | ||||
|     }; | ||||
|   }).then(event => { | ||||
|     const database = event.target.result; | ||||
|     if (database) { | ||||
|       testCase.add_cleanup(() => { database.close(); }); | ||||
|     } | ||||
|     return database || event.target.error; | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // Creates an IndexedDB database whose name is unique for the test case.
 | ||||
|  | @ -100,7 +110,7 @@ function migrateNamedDatabase( | |||
| // given the created database, the versionchange transaction, and the database
 | ||||
| // open request.
 | ||||
| //
 | ||||
| // Returns a promise that resolves to an IndexedDB database. The caller must
 | ||||
| // Returns a promise that resolves to an IndexedDB database. The caller should
 | ||||
| // close the database.
 | ||||
| function createDatabase(testCase, setupCallback) { | ||||
|   return createNamedDatabase(testCase, databaseName(testCase), setupCallback); | ||||
|  | @ -112,21 +122,23 @@ function createDatabase(testCase, setupCallback) { | |||
| // given the created database, the versionchange transaction, and the database
 | ||||
| // open request.
 | ||||
| //
 | ||||
| // Returns a promise that resolves to an IndexedDB database. The caller must
 | ||||
| // Returns a promise that resolves to an IndexedDB database. The caller should
 | ||||
| // close the database.
 | ||||
| function createNamedDatabase(testCase, databaseName, setupCallback) { | ||||
|   const request = indexedDB.deleteDatabase(databaseName); | ||||
|   const eventWatcher = requestWatcher(testCase, request); | ||||
| 
 | ||||
|   return eventWatcher.wait_for('success').then(event => | ||||
|       migrateNamedDatabase(testCase, databaseName, 1, setupCallback)); | ||||
|   return eventWatcher.wait_for('success').then(event => { | ||||
|     testCase.add_cleanup(() => { indexedDB.deleteDatabase(databaseName); }); | ||||
|     return migrateNamedDatabase(testCase, databaseName, 1, setupCallback) | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // Opens an IndexedDB database without performing schema changes.
 | ||||
| //
 | ||||
| // The given version number must match the database's current version.
 | ||||
| //
 | ||||
| // Returns a promise that resolves to an IndexedDB database. The caller must
 | ||||
| // Returns a promise that resolves to an IndexedDB database. The caller should
 | ||||
| // close the database.
 | ||||
| function openDatabase(testCase, version) { | ||||
|   return openNamedDatabase(testCase, databaseName(testCase), version); | ||||
|  | @ -136,12 +148,16 @@ function openDatabase(testCase, version) { | |||
| //
 | ||||
| // The given version number must match the database's current version.
 | ||||
| //
 | ||||
| // Returns a promise that resolves to an IndexedDB database. The caller must
 | ||||
| // Returns a promise that resolves to an IndexedDB database. The caller should
 | ||||
| // close the database.
 | ||||
| function openNamedDatabase(testCase, databaseName, version) { | ||||
|   const request = indexedDB.open(databaseName, version); | ||||
|   const eventWatcher = requestWatcher(testCase, request); | ||||
|   return eventWatcher.wait_for('success').then(event => event.target.result); | ||||
|   return eventWatcher.wait_for('success').then(() => { | ||||
|     const database = request.result; | ||||
|     testCase.add_cleanup(() => { database.close(); }); | ||||
|     return database; | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // The data in the 'books' object store records in the first example of the
 | ||||
|  |  | |||
|  | @ -0,0 +1,68 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <title>IndexedDB: Test error events fired at requests from aborted transaction</title> | ||||
| <meta name=help href="https://w3c.github.io/IndexedDB/#abort-a-transaction"> | ||||
| <meta name=help href="https://w3c.github.io/IndexedDB/#request-construct"> | ||||
| <meta name=help href="https://w3c.github.io/IndexedDB/#transaction-construct"> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="support.js"></script> | ||||
| <script> | ||||
| 
 | ||||
| indexeddb_test( | ||||
|   (t, db) => { | ||||
|     db.createObjectStore('store'); | ||||
|   }, | ||||
|   (t, db) => { | ||||
|     const tx = db.transaction('store'); | ||||
|     const request = tx.objectStore('store').get(0); | ||||
|     tx.abort(); | ||||
|     request.onsuccess = t.unreached_func('request should not succeed'); | ||||
| 
 | ||||
|     let connection_saw_error = false; | ||||
|     let transaction_saw_error = false; | ||||
| 
 | ||||
|     request.onerror = t.step_func(e => { | ||||
|       assert_equals(request.readyState, 'done', | ||||
|                     'Request\'s done flag should be set'); | ||||
|       assert_equals(request.result, undefined, | ||||
|                     'Request\'s result should be undefined'); | ||||
|       assert_equals(request.error.name, 'AbortError', | ||||
|                     'Request\'s error should be AbortError'); | ||||
| 
 | ||||
|       assert_equals(e.target, request, 'event target should be request'); | ||||
|       assert_equals(e.type, 'error', 'Event type should be error'); | ||||
|       assert_true(e.bubbles, 'Event should bubble'); | ||||
|       assert_true(e.cancelable, 'Event should cancelable'); | ||||
| 
 | ||||
|       assert_true(connection_saw_error, | ||||
|                   'Event propagated through connection'); | ||||
|       assert_true(transaction_saw_error, | ||||
|                   'Event propagated through transaction'); | ||||
|       t.done(); | ||||
|     }); | ||||
| 
 | ||||
|     // Event propagates via "get the parent" on request and transaction. | ||||
| 
 | ||||
|     db.addEventListener('error', t.step_func(e => { | ||||
|       connection_saw_error = true; | ||||
|       assert_equals(e.target, request, 'event target should be request'); | ||||
|       assert_equals(e.type, 'error', 'Event type should be error'); | ||||
|       assert_true(e.bubbles, 'Event should bubble'); | ||||
|       assert_true(e.cancelable, 'Event should cancelable'); | ||||
|     }), true); | ||||
| 
 | ||||
|     tx.addEventListener('error', t.step_func(e => { | ||||
|       transaction_saw_error = true; | ||||
|       assert_equals(e.target, request, 'event target should be request'); | ||||
|       assert_equals(e.type, 'error', 'Event type should be error'); | ||||
|       assert_true(e.bubbles, 'Event should bubble'); | ||||
|       assert_true(e.cancelable, 'Event should cancelable'); | ||||
| 
 | ||||
|       assert_true(connection_saw_error, | ||||
|                   'Event propagated through connection'); | ||||
|     }), true); | ||||
|   }, | ||||
|   'Properties of error events fired at requests when aborting a transaction'); | ||||
| 
 | ||||
| </script> | ||||
|  | @ -1,4 +1,4 @@ | |||
| #Dual-License for W3C Test Suites | ||||
| # Dual-License for W3C Test Suites | ||||
| 
 | ||||
| All documents in this Repository are licensed by contributors to be distributed under both the [W3C Test Suite License](#w3c-test-suite-license) and the [W3C 3-clause BSD License](#w3c-3-clause-bsd-license), reproduced below. The choice of license is up to the licensee. For more information, see [Licenses for W3C Test Suites](https://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html) | ||||
| 
 | ||||
|  |  | |||
|  | @ -2,9 +2,7 @@ The web-platform-tests Project [](http://irc.w | |||
| ============================== | ||||
| 
 | ||||
| The web-platform-tests Project is a W3C-coordinated attempt to build a | ||||
| cross-browser testsuite for the Web-platform stack.  However, for mainly | ||||
| historic reasons, the CSS WG testsuite is in a separate repository, | ||||
| [csswg-test](https://github.com/w3c/csswg-test). Writing tests in a way | ||||
| cross-browser testsuite for the Web-platform stack. Writing tests in a way | ||||
| that allows them to be run in all browsers gives browser projects | ||||
| confidence that they are shipping software that is compatible with other | ||||
| implementations, and that later implementations will be compatible with | ||||
|  | @ -110,41 +108,23 @@ Alternatively, you may also use | |||
| in the Windows 10 Anniversary Update build, then access your windows | ||||
| partition from there to launch wptserve. | ||||
| 
 | ||||
| Test Runner | ||||
| =========== | ||||
| 
 | ||||
| There is a test runner that is designed to provide a | ||||
| convenient way to run the web-platform-tests in-browser. It will run | ||||
| testharness.js tests automatically but requires manual work for | ||||
| reftests and manual tests. | ||||
| 
 | ||||
| The runner can be found at `/tools/runner/index.html` on the local | ||||
| server i.e. | ||||
| 
 | ||||
| ``` | ||||
| http://web-platform.test:8000/tools/runner/index.html | ||||
| ``` | ||||
| 
 | ||||
| in the default configuration. The first time you use this it has to | ||||
| generate a manifest of all tests. This may take some time, so please | ||||
| be patient. | ||||
| 
 | ||||
| Publication | ||||
| =========== | ||||
| 
 | ||||
| The master branch is automatically synced to http://w3c-test.org/. | ||||
| 
 | ||||
| Pull requests are automatically mirrored to | ||||
| http://w3c-test.org/submissions/ a few minutes after someone with merge | ||||
| access has added a comment with "LGTM" (or "w3c-test:mirror") to indicate | ||||
| the PR has been checked. | ||||
| Pull requests are | ||||
| [automatically mirrored](http://w3c-test.org/submissions/) except those | ||||
| that modify sensitive resources (such as `.py`). The latter require | ||||
| someone with merge access to comment with "LGTM" or "w3c-test:mirror" to | ||||
| indicate the pull request has been checked. | ||||
| 
 | ||||
| Finding Things | ||||
| ============== | ||||
| 
 | ||||
| Each top-level directory represents a W3C specification: the name | ||||
| matches the shortname used after the canonical address of the said | ||||
| specification under http://www.w3.org/TR/ . | ||||
| Each top-level directory matches the shortname used by a standard, with | ||||
| some exceptions. (Typically the shortname is from the standard's | ||||
| corresponding GitHub repository.) | ||||
| 
 | ||||
| For some of the specifications, the tree under the top-level directory | ||||
| represents the sections of the respective documents, using the section | ||||
|  | @ -185,6 +165,14 @@ The way to contribute is just as usual: | |||
| * Commit locally and push that to your repo. | ||||
| * Send in a pull request based on the above. | ||||
| 
 | ||||
| Issues with web-platform-tests | ||||
| ------------------------------ | ||||
| 
 | ||||
| If you spot an issue with a test and are not comfortable providing a | ||||
| pull request per above to fix it, please | ||||
| [file a new issue](https://github.com/w3c/web-platform-tests/issues/new). | ||||
| Thank you! | ||||
| 
 | ||||
| Lint tool | ||||
| --------- | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,48 @@ | |||
| // Step 1.
 | ||||
| test(function() { | ||||
|     assert_throws("TypeMismatchError", function() { | ||||
|         self.crypto.getRandomValues(new Float32Array(6)) | ||||
|     }, "Float32Array") | ||||
|     assert_throws("TypeMismatchError", function() { | ||||
|         self.crypto.getRandomValues(new Float64Array(6)) | ||||
|     }, "Float64Array") | ||||
| 
 | ||||
|     assert_throws("TypeMismatchError", function() { | ||||
|         self.crypto.getRandomValues(new Float32Array(65537)) | ||||
|     }, "Float32Array (too long)") | ||||
|     assert_throws("TypeMismatchError", function() { | ||||
|         self.crypto.getRandomValues(new Float64Array(65537)) | ||||
|     }, "Float64Array (too long)") | ||||
| }, "Float arrays") | ||||
| 
 | ||||
| var arrays = { | ||||
|     'Int8Array': Int8Array, | ||||
|     'Int16Array': Int16Array, | ||||
|     'Int32Array': Int32Array, | ||||
|     'Uint8Array': Uint8Array, | ||||
|     'Uint8ClampedArray': Uint8ClampedArray, | ||||
|     'Uint16Array': Uint16Array, | ||||
|     'Uint32Array': Uint32Array, | ||||
| }; | ||||
| 
 | ||||
| test(function() { | ||||
|     for (var array in arrays) { | ||||
|         assert_equals(self.crypto.getRandomValues(new arrays[array](8)).constructor, | ||||
|                       arrays[array], "crypto.getRandomValues(new " + array + "(8))") | ||||
|     } | ||||
| }, "Integer array") | ||||
| 
 | ||||
| test(function() { | ||||
|     for (var array in arrays) { | ||||
|         var maxlength = 65536 / (arrays[array].BYTES_PER_ELEMENT); | ||||
|         assert_throws("QuotaExceededError", function() { | ||||
|             self.crypto.getRandomValues(new arrays[array](maxlength + 1)) | ||||
|         }, "crypto.getRandomValues length over 65536") | ||||
|     } | ||||
| }, "Large length") | ||||
| 
 | ||||
| test(function() { | ||||
|     for (var array in arrays) { | ||||
|         assert_true(self.crypto.getRandomValues(new arrays[array](0)).length == 0) | ||||
|     } | ||||
| }, "Null arrays") | ||||
|  | @ -1,50 +0,0 @@ | |||
| function run_test() { | ||||
|     // Step 1.
 | ||||
|     test(function() { | ||||
|         assert_throws("TypeMismatchError", function() { | ||||
|             self.crypto.getRandomValues(new Float32Array(6)) | ||||
|         }, "Float32Array") | ||||
|         assert_throws("TypeMismatchError", function() { | ||||
|             self.crypto.getRandomValues(new Float64Array(6)) | ||||
|         }, "Float64Array") | ||||
| 
 | ||||
|         assert_throws("TypeMismatchError", function() { | ||||
|             self.crypto.getRandomValues(new Float32Array(65537)) | ||||
|         }, "Float32Array (too long)") | ||||
|         assert_throws("TypeMismatchError", function() { | ||||
|             self.crypto.getRandomValues(new Float64Array(65537)) | ||||
|         }, "Float64Array (too long)") | ||||
|     }, "Float arrays") | ||||
| 
 | ||||
|     var arrays = { | ||||
|         'Int8Array': Int8Array, | ||||
|         'Int16Array': Int16Array, | ||||
|         'Int32Array': Int32Array, | ||||
|         'Uint8Array': Uint8Array, | ||||
|         'Uint8ClampedArray': Uint8ClampedArray, | ||||
|         'Uint16Array': Uint16Array, | ||||
|         'Uint32Array': Uint32Array, | ||||
|     }; | ||||
| 
 | ||||
|     test(function() { | ||||
|         for (var array in arrays) { | ||||
|             assert_equals(self.crypto.getRandomValues(new arrays[array](8)).constructor, | ||||
|                           arrays[array], "crypto.getRandomValues(new " + array + "(8))") | ||||
|         } | ||||
|     }, "Integer array") | ||||
| 
 | ||||
|     test(function() { | ||||
|         for (var array in arrays) { | ||||
|             var maxlength = 65536 / (arrays[array].BYTES_PER_ELEMENT); | ||||
|             assert_throws("QuotaExceededError", function() { | ||||
|                 self.crypto.getRandomValues(new arrays[array](maxlength + 1)) | ||||
|             }, "crypto.getRandomValues length over 65536") | ||||
|         } | ||||
|     }, "Large length") | ||||
| 
 | ||||
|     test(function() { | ||||
|         for (var array in arrays) { | ||||
|             assert_true(self.crypto.getRandomValues(new arrays[array](0)).length == 0) | ||||
|         } | ||||
|     }, "Null arrays") | ||||
| } | ||||
|  | @ -1,4 +0,0 @@ | |||
| importScripts("/resources/testharness.js"); | ||||
| importScripts("getRandomValues.js"); | ||||
| run_test(); | ||||
| done(); | ||||
|  | @ -1,12 +0,0 @@ | |||
| <!DOCTYPE HTML> | ||||
| <meta charset=utf-8> | ||||
| <title>WebCryptoAPI: getRandomValues()</title> | ||||
| <link rel="author" title="Sunil Yoo" href="mailto:usuanday83@gmail.com"> | ||||
| <link rel="help" href="https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#dfn-Crypto-method-getRandomValues"> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="getRandomValues.js"></script> | ||||
| <div id="log"></div> | ||||
| <script> | ||||
| run_test(); | ||||
| </script> | ||||
|  | @ -1,4 +1,5 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <title>DOMException-throwing tests</title> | ||||
| <link rel=author title="Aryeh Gregor" href=ayg@aryeh.name> | ||||
| <div id=log></div> | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ test(() => { | |||
|   const client = new XMLHttpRequest | ||||
|   client.open("GET", "resources/header-content-length.asis", false) | ||||
|   client.send() | ||||
|   assert_equals(client.getAllResponseHeaders(), "CONTENT-LENGTH: 0\r\n") | ||||
|   assert_equals(client.getAllResponseHeaders(), "content-length: 0\r\n") | ||||
| }) | ||||
| test(() => { | ||||
|   const client = new XMLHttpRequest | ||||
|  | @ -17,11 +17,11 @@ test(() => { | |||
|   client.setRequestHeader("content-TYPE", "x/x") | ||||
|   client.send() | ||||
|   assert_regexp_match(client.responseText, /content-TYPE/) | ||||
|   assert_regexp_match(client.responseText, /THIS-IS-A-TEST: 1,/) | ||||
|   assert_regexp_match(client.responseText, /THIS-IS-A-TEST: 1, 2/) | ||||
| }) | ||||
| promise_test(() => { | ||||
|   return fetch("resources/echo-headers.py", {headers: [["THIS-is-A-test", 1], ["THIS-IS-A-TEST", 2]] }).then(res => res.text()).then(body => { | ||||
|     assert_regexp_match(body, /THIS-is-A-test: 1/) | ||||
|     assert_regexp_match(body, /THIS-is-A-test: 1, 2/) | ||||
|   }) | ||||
| }) | ||||
| </script> | ||||
|  |  | |||
|  | @ -0,0 +1,56 @@ | |||
| <!doctype html> | ||||
| <title>XMLHttpRequest: open() during abort event - abort() called from upload.onloadstart</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <div id="log"></div> | ||||
| <script> | ||||
| async_test(t => { | ||||
|   let client = new XMLHttpRequest(), | ||||
|       log = [], | ||||
|       lastTest = false, | ||||
|       expected = [ | ||||
|         'readyState before abort() 1', | ||||
|         "upload.onabort - before open() 4", | ||||
|         "readyState after open() 1", | ||||
|         "client.onabort 1", | ||||
|         "client.onloadend 1", | ||||
|         "readyState after abort() 1", | ||||
|         "client.onload 4", | ||||
|         "client.onloadend 4" | ||||
|       ] | ||||
| 
 | ||||
|   client.upload.onloadstart = t.step_func(() => { | ||||
|     log.push('readyState before abort() '+client.readyState) | ||||
|     client.abort() | ||||
|     log.push('readyState after abort() '+client.readyState) | ||||
|   }) | ||||
| 
 | ||||
|   client.upload.onabort = t.step_func(() => { | ||||
|     log.push('upload.onabort - before open() ' + client.readyState) | ||||
|     client.open("GET", "resources/content.py") | ||||
|     log.push('readyState after open() ' + client.readyState) | ||||
|     client.send(null) | ||||
|   }) | ||||
| 
 | ||||
|   client.onabort = t.step_func(() => { | ||||
|     // happens immediately after all of upload.onabort, so readyState is 1 | ||||
|     log.push('client.onabort ' + client.readyState) | ||||
|   }) | ||||
| 
 | ||||
|   client.onloadend = t.step_func(() => { | ||||
|     log.push('client.onloadend ' + client.readyState) | ||||
|     if(lastTest) { | ||||
|       assert_array_equals(log, expected) | ||||
|       t.done() | ||||
|     } | ||||
|     lastTest = true | ||||
|   }) | ||||
| 
 | ||||
|   client.onload = t.step_func(() => { | ||||
|     log.push('client.onload ' + client.readyState) | ||||
|   }) | ||||
| 
 | ||||
|   client.open("POST", "resources/content.py") | ||||
|   client.send("non-empty") | ||||
| }) | ||||
| </script> | ||||
|  | @ -0,0 +1,64 @@ | |||
| <!doctype html> | ||||
| <title>XMLHttpRequest: open() during abort processing - abort() called from onloadstart</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <div id="log"></div> | ||||
| <script> | ||||
| async_test(t => { | ||||
|   let client = new XMLHttpRequest(), | ||||
|       test_state = 1, | ||||
|       log = [], | ||||
|       expected = [ | ||||
|         "onloadstart readyState before abort() 1", | ||||
|         "onreadystatechange readyState before open() 4", | ||||
|         "onreadystatechange readyState after open() 1", | ||||
|         "onloadstart readyState 1", | ||||
|         "upload.onabort 1", | ||||
|         "upload.onloadend 1", | ||||
|         "client.onabort 1", | ||||
|         "readyState after abort() 1", | ||||
|         "client.onload 4" | ||||
|       ] | ||||
| 
 | ||||
|   client.onreadystatechange = t.step_func(() => { | ||||
|     if(test_state === 2){ | ||||
|       test_state = 3 | ||||
|       log.push('onreadystatechange readyState before open() ' + client.readyState) | ||||
|       client.open("GET", "resources/content.py") | ||||
|       log.push('onreadystatechange readyState after open() ' + client.readyState) | ||||
|       client.send(null) | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   client.onloadstart = t.step_func(() => { | ||||
|     if(test_state === 1){ | ||||
|       test_state = 2 | ||||
|       log.push('onloadstart readyState before abort() ' + client.readyState) | ||||
|       client.abort() | ||||
|       log.push('readyState after abort() ' + client.readyState) | ||||
|     }else{ | ||||
|       log.push('onloadstart readyState ' + client.readyState) | ||||
|     } | ||||
|   }) | ||||
| 
 | ||||
|   client.upload.onabort = t.step_func(() => { | ||||
|     log.push('upload.onabort ' + client.readyState) | ||||
|   }) | ||||
| 
 | ||||
|   client.onabort = t.step_func(() => { | ||||
|     log.push('client.onabort ' + client.readyState) | ||||
|   }) | ||||
| 
 | ||||
|   client.upload.onloadend = t.step_func(() => { | ||||
|     log.push('upload.onloadend ' + client.readyState) | ||||
|   }) | ||||
| 
 | ||||
|   client.onload = t.step_func_done(() => { | ||||
|     log.push('client.onload ' + client.readyState) | ||||
|     assert_array_equals(log, expected) | ||||
|   }) | ||||
| 
 | ||||
|   client.open("POST", "resources/content.py") | ||||
|   client.send('abcd') | ||||
| }) | ||||
| </script> | ||||
|  | @ -5,15 +5,14 @@ | |||
|     <title>XMLHttpRequest: redirected worker scripts, origin and referrer</title> | ||||
|     <script src="/resources/testharness.js"></script> | ||||
|     <script src="/resources/testharnessreport.js"></script> | ||||
|     <link rel="help" href="https://xhr.spec.whatwg.org/#the-open()-method" data-tested-assertations="following::OL[1]/LI[3] following::OL[1]/LI[3]/ol[1]/li[1] following::OL[1]/LI[3]/ol[1]/li[2] following::OL[1]/LI[3]/ol[1]/li[3]" /> | ||||
| </head> | ||||
| <body> | ||||
|     <div id="log"></div> | ||||
|     <script type="text/javascript"> | ||||
|         var test = async_test() // This "test" does not actually do any assertations. It's just there to have multiple, separate, asyncronous sub-tests. | ||||
|         var expectations = { | ||||
|             'Referer header': 'referer: '+(location.href.replace(/[^/]*$/, ''))+"resources/workerxhr-origin-referrer.js\n", | ||||
|             'Origin header': 'origin: '+location.protocol+'//'+location.hostname+((location.port === "")?"":":"+location.port)+'\n', | ||||
|             'Referer header': 'Referer: '+(location.href.replace(/[^/]*$/, ''))+"resources/workerxhr-origin-referrer.js\n", | ||||
|             'Origin header': 'Origin: '+location.protocol+'//'+location.hostname+((location.port === "")?"":":"+location.port)+'\n', | ||||
|             'Request URL test' : (location.href.replace(/[^/]*$/, ''))+'resources/requri.py?full' | ||||
|         } | ||||
|         // now start the worker | ||||
|  |  | |||
|  | @ -7,14 +7,8 @@ def main(request, response): | |||
|     response.headers.set('Access-Control-Allow-Methods', 'GET'); | ||||
|     response.headers.set('Access-Control-Allow-Headers', 'authorization, x-user, x-pass'); | ||||
|     response.headers.set('Access-Control-Expose-Headers', 'x-challenge, xhr-user, ses-user'); | ||||
|     auth = imp.load_source("", os.path.join(os.path.abspath(os.curdir), | ||||
|                                             "XMLHttpRequest", | ||||
|                                             "resources", | ||||
|                                             "authentication.py")) | ||||
|     auth = imp.load_source("", os.path.abspath("XMLHttpRequest/resources/authentication.py")) | ||||
|     if request.method == "OPTIONS": | ||||
|         return "" | ||||
|     else: | ||||
|         return auth.main(request, response) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,15 +3,27 @@ def main(request, response): | |||
|     match = request.headers.get("If-None-Match", None) | ||||
|     date = request.GET.first("date", "") | ||||
|     modified = request.headers.get("If-Modified-Since", None) | ||||
|     cors = request.GET.first("cors", None) | ||||
| 
 | ||||
|     if request.method == "OPTIONS": | ||||
|         response.headers.set("Access-Control-Allow-Origin", "*") | ||||
|         response.headers.set("Access-Control-Allow-Headers", "IF-NONE-MATCH") | ||||
|         return "" | ||||
| 
 | ||||
|     if tag: | ||||
|         response.headers.set("ETag", '"%s"' % tag) | ||||
|     elif date: | ||||
|         response.headers.set("Last-Modified", date) | ||||
| 
 | ||||
|     if cors: | ||||
|         response.headers.set("Access-Control-Allow-Origin", "*") | ||||
| 
 | ||||
|     if ((match is not None and match == tag) or | ||||
|         (modified is not None and modified == date)): | ||||
|         response.status = (304, "SUPERCOOL") | ||||
|         return "" | ||||
|     else: | ||||
|         if not cors: | ||||
|             response.headers.set("Access-Control-Allow-Origin", "*") | ||||
|         response.headers.set("Content-Type", "text/plain") | ||||
|         return "MAYBE NOT" | ||||
|  |  | |||
|  | @ -11,6 +11,9 @@ def main(request, response): | |||
|         delay = int(request.GET.first("delay")) | ||||
|         time.sleep(delay) | ||||
| 
 | ||||
|     if "safelist_content_type" in request.GET: | ||||
|         headers.append(("Access-Control-Allow-Headers", "content-type")) | ||||
| 
 | ||||
|     headers.append(("X-Request-Method", request.method)) | ||||
|     headers.append(("X-Request-Query", request.url_parts.query if request.url_parts.query else "NO")) | ||||
|     headers.append(("X-Request-Content-Length", request.headers.get("Content-Length", "NO"))) | ||||
|  |  | |||
|  | @ -3,4 +3,5 @@ import time | |||
| def main(request, response): | ||||
|     delay = float(request.GET.first("ms", 500)) | ||||
|     time.sleep(delay / 1E3); | ||||
|     return [("Content-type", "text/plain")], "TEST_DELAY" | ||||
| 
 | ||||
|     return [("Access-Control-Allow-Origin", "*"), ("Access-Control-Allow-Methods", "YO"), ("Content-type", "text/plain")], "TEST_DELAY" | ||||
|  |  | |||
|  | @ -1,8 +1,14 @@ | |||
| import time | ||||
| 
 | ||||
| def main(request, response): | ||||
|     code = int(request.GET.first("code", 302)) | ||||
|     location = request.GET.first("location", request.url_parts.path +"?followed") | ||||
| 
 | ||||
|     if request.url.endswith("?followed"): | ||||
|     if "delay" in request.GET: | ||||
|         delay = float(request.GET.first("delay")) | ||||
|         time.sleep(delay / 1E3); | ||||
| 
 | ||||
|     if "followed" in request.GET: | ||||
|         return [("Content:Type", "text/plain")], "MAGIC HAPPENED" | ||||
|     else: | ||||
|         return (code, "WEBSRT MARKETING"), [("Location", location)], "TEST" | ||||
|  |  | |||
|  | @ -5,15 +5,11 @@ | |||
|     <script src="/resources/testharness.js"></script> | ||||
|     <script src="/resources/testharnessreport.js"></script> | ||||
|     <script src="/common/utils.js"></script> | ||||
|     <!-- These spec references do not make much sense simply because the spec doesn't say very much about this.. --> | ||||
|     <link rel="help" href="https://xhr.spec.whatwg.org/#the-setrequestheader()-method" data-tested-assertations="following::ol[1]/li[6]" /> | ||||
|     <link rel="help" href="https://xhr.spec.whatwg.org/#the-send()-method" data-tested-assertations="following::code[contains(@title,'http-authorization')]/.." /> | ||||
|   </head> | ||||
|   <body> | ||||
|     <div id="log"></div> | ||||
|     <script> | ||||
|       var test = async_test() | ||||
|       test.step(function() { | ||||
|       async_test(test => { | ||||
|         var client = new XMLHttpRequest(), | ||||
|             urlstart = location.host + location.pathname.replace(/\/[^\/]*$/, '/'), | ||||
|             user = token() | ||||
|  | @ -22,15 +18,11 @@ | |||
|         client.setRequestHeader("x-user", user) | ||||
|         client.setRequestHeader("x-pass", 'pass') | ||||
|         client.setRequestHeader('Authorization', 'Basic ' + btoa(user + ":pass")) | ||||
|         client.onreadystatechange = function () { | ||||
|           if (client.readyState < 4) {return} | ||||
|           test.step( function () { | ||||
|             assert_true(client.responseText == (user + '\npass'), 'responseText should contain the right user and password') | ||||
|         client.onload = test.step_func_done(() => { | ||||
|             assert_equals(client.responseText, user + '\npass', 'responseText should contain the right user and password') | ||||
|             assert_equals(client.status, 200) | ||||
|             assert_equals(client.getResponseHeader('x-challenge'), 'DID-NOT') | ||||
|             test.done() | ||||
|           } ) | ||||
|         } | ||||
|         }) | ||||
|         client.send(null) | ||||
|       }) | ||||
|     </script> | ||||
|  |  | |||
|  | @ -0,0 +1,42 @@ | |||
| <!doctype html> | ||||
| <title>XMLHttpRequest: send() - conditional cross-origin requests</title> | ||||
| <script src=/resources/testharness.js></script> | ||||
| <script src=/resources/testharnessreport.js></script> | ||||
| <script src=/cors/support.js?pipe=sub></script> | ||||
| <div id=log></div> | ||||
| <script> | ||||
| function request(withCORS, desc) { | ||||
|   async_test(t => { | ||||
|     const client = new XMLHttpRequest, | ||||
|           identifier = Math.random(), | ||||
|           cors = withCORS ? "&cors=yes" : "", | ||||
|           url = CROSSDOMAIN + "resources/conditional.py?tag=" + identifier + cors | ||||
|     client.onload = t.step_func(() => { | ||||
|       assert_equals(client.status, 200) | ||||
|       assert_equals(client.statusText, "OK") | ||||
|       assert_equals(client.responseText, "MAYBE NOT") | ||||
| 
 | ||||
|       if(withCORS) { | ||||
|         client.onload = t.step_func_done(() => { | ||||
|           assert_equals(client.status, 304) | ||||
|           assert_equals(client.statusText, "SUPERCOOL") | ||||
|           assert_equals(client.responseText, "") | ||||
|         }) | ||||
|       } else { | ||||
|         client.onload = null | ||||
|         client.onerror = t.step_func_done(() => { | ||||
|           assert_equals(client.status, 0) | ||||
|           assert_equals(client.statusText, "") | ||||
|         }) | ||||
|       } | ||||
|       client.open("GET", url) | ||||
|       client.setRequestHeader("If-None-Match", identifier) | ||||
|       client.send() | ||||
|     }) | ||||
|     client.open("GET", url) | ||||
|     client.send() | ||||
|   }, desc) | ||||
| } | ||||
| request(false, "304 without appropriate CORS header") | ||||
| request(true, "304 with appropriate CORS header") | ||||
| </script> | ||||
|  | @ -1,26 +1,26 @@ | |||
| <!doctype html> | ||||
| <html> | ||||
|   <head> | ||||
|     <title>XMLHttpRequest: send() - unserializable Document</title> | ||||
|     <script src="/resources/testharness.js"></script> | ||||
|     <script src="/resources/testharnessreport.js"></script> | ||||
|     <link rel="help" href="https://xhr.spec.whatwg.org/#dom-XMLHttpRequest-send-document" data-tested-assertations="following::p[3]" /> | ||||
|   </head> | ||||
|   <body> | ||||
|     <div id="log"></div> | ||||
|     <script> | ||||
|       function request_throws(input) { | ||||
|         test(function() { | ||||
|           var client = new XMLHttpRequest() | ||||
|           client.open("POST", "resources/content.py", false) | ||||
|           assert_throws("InvalidStateError", function() { client.send(input) }) | ||||
|         }) | ||||
|       } | ||||
|       var doc = document.implementation.createDocument(null, null, null) | ||||
|       while(doc.childNodes.length) { | ||||
|         doc.removeChild(doc.childNodes[0]) | ||||
|       } | ||||
|       request_throws(doc) | ||||
|     </script> | ||||
|   </body> | ||||
| </html> | ||||
| <title>XMLHttpRequest: send() - Document with serialization errors</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <div id="log"></div> | ||||
| <script> | ||||
| function serialize(input, output) { | ||||
|   async_test(t => { | ||||
|     const client = new XMLHttpRequest | ||||
|     client.open("POST", "resources/content.py") | ||||
|     client.send(input) | ||||
|     client.onload = t.step_func_done(() => { | ||||
|       assert_equals(client.responseText, output) | ||||
|     }) | ||||
|   }, "Serializing documents through XMLHttpRequest: '" + output + "'") | ||||
| } | ||||
| 
 | ||||
| var doc = document.implementation.createDocument(null, null, null) | ||||
| serialize(doc, "") | ||||
| doc.appendChild(doc.createElement("test:test")) | ||||
| serialize(doc, "<test:test/>") | ||||
| doc.childNodes[0].setAttribute("test:test", "gee") | ||||
| serialize(doc, "<test:test test:test=\"gee\"/>") | ||||
| doc.childNodes[0].setAttribute("x", "\uD800") | ||||
| serialize(doc, "<test:test test:test=\"gee\" x=\"\uFFFD\"/>") | ||||
| </script> | ||||
|  |  | |||
|  | @ -5,8 +5,6 @@ | |||
|     <script src="/resources/testharness.js"></script> | ||||
|     <script src="/resources/testharnessreport.js"></script> | ||||
|     <base> | ||||
|     <link rel="help" href="https://xhr.spec.whatwg.org/#cross-origin-request-steps" data-tested-assertations="/following::DL[2]/DT[1] /following::DL[2]/DD[1]" /> | ||||
|     <link rel="help" href="https://xhr.spec.whatwg.org/#cross-origin-request-event-rules" data-tested-assertations="/following::DL[1]/DT[2] /following::DL[1]/DD[2]" /> | ||||
|   </head> | ||||
|   <body> | ||||
|     <div id="log"></div> | ||||
|  | @ -28,6 +26,8 @@ | |||
|       url(host_info.HTTP_REMOTE_ORIGIN) | ||||
|       url("javascript:alert('FAIL')") | ||||
|       url("folder.txt") | ||||
|       url("about:blank") | ||||
|       url("blob:bogusidentifier") | ||||
|     </script> | ||||
|   </body> | ||||
| </html> | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ | |||
|     <title>XMLHttpRequest: send() - Redirect to CORS-enabled resource</title> | ||||
|     <script src="/resources/testharness.js"></script> | ||||
|     <script src="/resources/testharnessreport.js"></script> | ||||
|     <link rel="help" href="https://xhr.spec.whatwg.org/#infrastructure-for-the-send()-method" data-tested-assertations="following::dl[1]/dt[2] following::dl[1]/dd[2]/ol/li[1] following::dl[1]/dd[2]/ol/li[3]" /> | ||||
|   </head> | ||||
|   <body> | ||||
|     <div id="log"></div> | ||||
|  | @ -13,56 +12,76 @@ | |||
|         if (body === null) { | ||||
|           return { body: "", type: "NO" }; | ||||
|         } | ||||
| 
 | ||||
|         if (typeof body == "string") { | ||||
|           return { body: body, type: "text/plain;charset=UTF-8" }; | ||||
|         } | ||||
| 
 | ||||
|         if (body instanceof Uint8Array) { | ||||
|           var arr = Array.prototype.slice.call(body); | ||||
|           return { body: String.fromCharCode.apply(null, arr), type: "NO" } | ||||
|         } | ||||
| 
 | ||||
|         return { body: "EXTRACT NOT IMPLEMENTED", | ||||
|                  type: "EXTRACT NOT IMPLEMENTED" } | ||||
|         return { body: "EXTRACT NOT IMPLEMENTED", type: "EXTRACT NOT IMPLEMENTED" } | ||||
|       } | ||||
| 
 | ||||
|       function redirect(code, name = code, method = "GET", body = null, setExplicitType = true) { | ||||
|         var test = async_test(document.title + " (" + name + ")") | ||||
|         test.step(function() { | ||||
|       function redirect(code, name = code, method = "GET", body = null, explicitType = null, safelistContentType = false) { | ||||
|         async_test(t => { | ||||
|           var client = new XMLHttpRequest() | ||||
|           client.onreadystatechange = function() { | ||||
|             test.step(function() { | ||||
|               if (client.readyState == 4) { | ||||
|                 assert_equals(client.status, 200); | ||||
|                 assert_equals(client.getResponseHeader("x-request-method"), | ||||
|                               method); | ||||
|           client.onreadystatechange = t.step_func(() => { | ||||
|             if (client.readyState == 4) { | ||||
|               if (explicitType !== "application/x-pony" || safelistContentType) { | ||||
|                 var { body: expectedBody, type: expectedType } = extractBody(body); | ||||
|                 if (setExplicitType) { | ||||
|                   expectedType = "application/x-pony"; | ||||
|                 if (explicitType !== null) { | ||||
|                   expectedType = explicitType | ||||
|                 } | ||||
|                 assert_equals(client.getResponseHeader("x-request-content-type"), | ||||
|                               expectedType); | ||||
|                 assert_equals(client.getResponseHeader("x-request-data"), | ||||
|                               expectedBody); | ||||
|                 test.done(); | ||||
|                 if (((code === "301" || code === "302") && method === "POST") || code === "303") { | ||||
|                   method = "GET" | ||||
|                   expectedBody = "" | ||||
|                 } | ||||
|                 assert_equals(client.status, 200); | ||||
|                 assert_equals(client.getResponseHeader("x-request-method"), method); | ||||
|                 assert_equals(client.getResponseHeader("x-request-content-type"), expectedType); | ||||
|                 assert_equals(client.getResponseHeader("x-request-data"), expectedBody); | ||||
|               } else { | ||||
|                 // "application/x-pony" is not safelisted by corsenabled.py -> network error | ||||
|                 assert_equals(client.status, 0) | ||||
|                 assert_equals(client.statusText, "") | ||||
|                 assert_equals(client.responseText, "") | ||||
|                 assert_equals(client.responseXML, null) | ||||
|               } | ||||
|             }) | ||||
|               t.done(); | ||||
|             } | ||||
|           }) | ||||
|           let safelist = "" | ||||
|           if (safelistContentType) { | ||||
|             safelist = "?safelist_content_type" | ||||
|           } | ||||
|           client.open(method, "resources/redirect.py?location="+encodeURIComponent("http://www2."+location.host+(location.pathname.replace(/[^\/]+$/, ''))+'resources/corsenabled.py')+"&code=" + code) | ||||
|           if (setExplicitType) { | ||||
|             client.setRequestHeader("Content-Type", "application/x-pony") | ||||
|           client.open(method, "resources/redirect.py?location="+encodeURIComponent("http://www2."+location.host+(location.pathname.replace(/[^\/]+$/, ''))+'resources/corsenabled.py')+safelist+"&code=" + code) | ||||
|           if (explicitType !== null) { | ||||
|             client.setRequestHeader("Content-Type", explicitType) | ||||
|           } | ||||
|           client.send(body) | ||||
|         }) | ||||
|         }, document.title + " (" + name + ")") | ||||
|       } | ||||
|       redirect("301") | ||||
|       redirect("301", "301 GET with explicit Content-Type", "GET", null, "application/x-pony") | ||||
|       redirect("301", "301 GET with explicit Content-Type safelisted", "GET", null, "application/x-pony", true) | ||||
|       redirect("302") | ||||
|       redirect("303") | ||||
|       redirect("303", "303 LALA with string and explicit Content-Type safelisted", "LALA", "test", "application/x-pony", true) | ||||
|       redirect("307") | ||||
|       redirect("307", "307 post with null", "POST", null, false); | ||||
|       redirect("307", "307 post with string", "POST", "hello", false); | ||||
|       redirect("307", "307 post with typed array", "POST", new Uint8Array([65, 66, 67]), false); | ||||
|       redirect("307", "307 post with null", "POST", null) | ||||
|       redirect("307", "307 post with string", "POST", "hello") | ||||
|       redirect("307", "307 post with typed array", "POST", new Uint8Array([65, 66, 67])) | ||||
|       redirect("301", "301 POST with string and explicit Content-Type", "POST", "yoyo", "application/x-pony") | ||||
|       redirect("301", "301 POST with string and explicit Content-Type safelisted", "POST", "yoyo", "application/x-pony", true) | ||||
|       redirect("302", "302 POST with string and explicit Content-Type", "POST", "yoyo", "application/x-pony") | ||||
|       redirect("307", "307 POST with string and explicit Content-Type", "POST", "yoyo", "application/x-pony") | ||||
|       redirect("307", "307 FOO with string and explicit Content-Type", "FOO", "yoyo", "application/x-pony") | ||||
|       redirect("308", "308 POST with string and explicit Content-Type", "POST", "yoyo", "application/x-pony") | ||||
|       redirect("308", "308 FOO with string and explicit Content-Type", "FOO", "yoyo", "application/x-pony") | ||||
|       redirect("308", "308 FOO with string and explicit Content-Type text/plain", "FOO", "yoyo", "text/plain") | ||||
|       redirect("308", "308 FOO with string and explicit Content-Type multipart/form-data", "FOO", "yoyo", "multipart/form-data") | ||||
|       redirect("308", "308 FOO with string and explicit Content-Type safelisted", "FOO", "yoyo", "application/thunderstorm", true) | ||||
|       redirect("307", "307 POST with string and explicit Content-Type safelisted", "POST", "yoyo", "application/thunderstorm", true) | ||||
|     </script> | ||||
|   </body> | ||||
| </html> | ||||
|  |  | |||
|  | @ -1,9 +1,6 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
|     <!-- This behaviour is not explicitly spelled out in the spec. | ||||
|     It does say "queue tasks" under the "if the synchronous flag is unset" header in point 10 of the "send" algorithm.. --> | ||||
|     <link rel="help" href="https://xhr.spec.whatwg.org/#the-send()-method" data-tested-assertations="following-sibling::ol/li[10]/dl/dd/dl/dd[2]/p[3]" /> | ||||
|     <script src="/resources/testharness.js"></script> | ||||
|     <script src="/resources/testharnessreport.js"></script> | ||||
|     <title>XMLHttpRequest: sync requests should block events on pending async requests</title> | ||||
|  | @ -22,7 +19,7 @@ | |||
|         { | ||||
|             var xhr_async = new XMLHttpRequest() | ||||
|             xhr_async.open('GET', 'resources/delay.py?ms=1000', true) // first launch an async request, completes in 1 second | ||||
|             xhr_async.onreadystatechange = t.step_func(() => { | ||||
|             xhr_async.onreadystatechange = test.step_func(() => { | ||||
|                 actual.push('async ' + xhr_async.readyState) | ||||
|                 if(xhr_async.readyState === 4 && actual.indexOf('sync 4')>-1){ | ||||
|                     VerifyResult() | ||||
|  | @ -33,7 +30,7 @@ | |||
|             test.step_timeout(() => { | ||||
|                 var xhr_sync = new XMLHttpRequest(); | ||||
|                 xhr_sync.open('GET', 'resources/delay.py?ms=2000', false) // here's a sync request that will take 2 seconds to finish | ||||
|                 xhr_sync.onreadystatechange = t.step_func(() => { | ||||
|                 xhr_sync.onreadystatechange = test.step_func(() => { | ||||
|                     actual.push('sync ' + xhr_sync.readyState) | ||||
|                     if(xhr_sync.readyState === 4 && actual.indexOf('async 4')>-1){ | ||||
|                         VerifyResult() | ||||
|  |  | |||
|  | @ -15,7 +15,6 @@ function encode(n) { | |||
|   return "%" + (s.length === 2 ? s : '0' + s); | ||||
| } | ||||
| 
 | ||||
| function run_test() { | ||||
|   var tests = []; | ||||
|   var overall_test = async_test("Overall fetch with URLSearchParams"); | ||||
|   for (var i = 0; i < NUM_TESTS; i++) { | ||||
|  | @ -45,4 +44,3 @@ function run_test() { | |||
|     usp.append("a" + i, String.fromCharCode(i)); | ||||
|   } | ||||
|   x.send(usp) | ||||
| } | ||||
|  | @ -1,10 +0,0 @@ | |||
| <!DOCTYPE html> | ||||
| <meta charset=utf-8> | ||||
| <title>XMLHttpRequest.send(URLSearchParams)</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="send-usp.js"></script> | ||||
| <div id="log"></div> | ||||
| <script> | ||||
| run_test(); | ||||
| </script> | ||||
|  | @ -1,4 +0,0 @@ | |||
| importScripts("/resources/testharness.js"); | ||||
| importScripts("send-usp.js"); | ||||
| run_test(); | ||||
| done(); | ||||
|  | @ -2,7 +2,7 @@ | |||
| <title>XMLHttpRequest: template element parsing</title> | ||||
| <script src=/resources/testharness.js></script> | ||||
| <script src=/resources/testharnessreport.js></script> | ||||
| <div id=log> | ||||
| <div id=log></div> | ||||
| <script> | ||||
| async_test(t => { | ||||
|   const client = new XMLHttpRequest | ||||
|  |  | |||
|  | @ -0,0 +1,29 @@ | |||
| <!doctype html> | ||||
| <title>XMLHttpRequest: timeout, redirects, and CORS preflights</title> | ||||
| <script src=/resources/testharness.js></script> | ||||
| <script src=/resources/testharnessreport.js></script> | ||||
| <script src=/common/get-host-info.sub.js></script> | ||||
| <div id=log></div> | ||||
| <script> | ||||
| async_test(t => { | ||||
|   const client = new XMLHttpRequest | ||||
|   client.open("GET", "resources/redirect.py?delay=500&location=delay.py") // 500 + 500 = 1000 | ||||
|   client.timeout = 1000 | ||||
|   client.send() | ||||
|   client.ontimeout = t.step_func_done(() => { | ||||
|     assert_equals(client.readyState, 4) | ||||
|   }) | ||||
|   client.onload = t.unreached_func("load event fired") | ||||
| }, "Redirects should not reset the timer") | ||||
| 
 | ||||
| async_test(t => { | ||||
|   const client = new XMLHttpRequest | ||||
|   client.open("YO", get_host_info().HTTP_REMOTE_ORIGIN + "/XMLHttpRequest/resources/delay.py") | ||||
|   client.timeout = 1000 | ||||
|   client.send() | ||||
|   client.ontimeout = t.step_func_done(() => { | ||||
|     assert_equals(client.readyState, 4) | ||||
|   }) | ||||
|   client.onload = t.unreached_func("load event fired") | ||||
| }, "CORS preflights should not reset the timer") | ||||
| </script> | ||||
							
								
								
									
										2
									
								
								testing/web-platform/tests/background-fetch/OWNERS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								testing/web-platform/tests/background-fetch/OWNERS
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | |||
| @beverloo | ||||
| @jakearchibald | ||||
|  | @ -0,0 +1,15 @@ | |||
| <!doctype html> | ||||
| <meta charset="utf-8"> | ||||
| <title>Background Fetch API IDL tests</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> | ||||
| 
 | ||||
| <h1>idlharness test</h1> | ||||
| <p>This test validates the WebIDL included in the Background Fetch API (Service Workers).</p> | ||||
| 
 | ||||
| <script> | ||||
| 'use strict'; | ||||
| 
 | ||||
| service_worker_test('interfaces.worker.js', 'Service Worker-scoped tests.'); | ||||
| </script> | ||||
							
								
								
									
										26
									
								
								testing/web-platform/tests/background-fetch/interfaces.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								testing/web-platform/tests/background-fetch/interfaces.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | |||
| <!doctype html> | ||||
| <meta charset="utf-8"> | ||||
| <title>Background Fetch API IDL tests</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script src="/resources/WebIDLParser.js"></script> | ||||
| <script src="/resources/idlharness.js"></script> | ||||
| 
 | ||||
| <h1>idlharness test</h1> | ||||
| <p>This test validates the WebIDL included in the Background Fetch API (Documents).</p> | ||||
| 
 | ||||
| <script> | ||||
| 'use strict'; | ||||
| 
 | ||||
| promise_test(function() { | ||||
|   return fetch('interfaces.idl') | ||||
|     .then(response => response.text()) | ||||
|     .then(idls => { | ||||
|       var idlArray = new IdlArray(); | ||||
|       idlArray.add_untested_idls('interface ServiceWorkerRegistration {};'); | ||||
|       idlArray.add_untested_idls('[Exposed=ServiceWorker] interface ServiceWorkerGlobalScope {};'); | ||||
|       idlArray.add_idls(idls); | ||||
|       idlArray.test(); | ||||
|     }); | ||||
| }, 'Exposed interfaces in a Document.'); | ||||
| </script> | ||||
							
								
								
									
										115
									
								
								testing/web-platform/tests/background-fetch/interfaces.idl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								testing/web-platform/tests/background-fetch/interfaces.idl
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,115 @@ | |||
| // 3.1. Extensions to ServiceWorkerRegistration | ||||
| 
 | ||||
| partial interface ServiceWorkerRegistration { | ||||
|   readonly attribute BackgroundFetchManager backgroundFetch; | ||||
| }; | ||||
| 
 | ||||
| // 3.2. BackgroundFetchManager | ||||
| 
 | ||||
| [Exposed=(Window,Worker)] | ||||
| interface BackgroundFetchManager { | ||||
|   Promise<BackgroundFetchRegistration> fetch(DOMString tag, (RequestInfo or sequence<RequestInfo>) requests, optional BackgroundFetchOptions options); | ||||
|   Promise<BackgroundFetchRegistration?> get(DOMString tag); | ||||
|   Promise<FrozenArray<DOMString>> getTags(); | ||||
|   // TODO: in future this should become an async iterator for BackgroundFetchRegistration objects | ||||
| }; | ||||
| 
 | ||||
| dictionary BackgroundFetchOptions { | ||||
|   sequence<IconDefinition> icons; | ||||
|   DOMString title; | ||||
|   long totalDownloadSize; | ||||
| }; | ||||
| 
 | ||||
| // This is taken from https://w3c.github.io/manifest/#icons-member. | ||||
| // This definition should probably be moved somewhere more general. | ||||
| dictionary IconDefinition { | ||||
|   DOMString src; | ||||
|   DOMString sizes; | ||||
|   DOMString type; | ||||
| }; | ||||
| 
 | ||||
| // 3.3. BackgroundFetchRegistration | ||||
| 
 | ||||
| [Exposed=(Window,Worker)] | ||||
| interface BackgroundFetchRegistration { | ||||
|   readonly attribute DOMString tag; | ||||
|   readonly attribute FrozenArray<IconDefinition> icons; | ||||
|   readonly attribute long totalDownloadSize; | ||||
|   readonly attribute DOMString title; | ||||
|   readonly attribute FrozenArray<BackgroundFetchActiveFetches> fetches; | ||||
| 
 | ||||
|   void abort(); | ||||
| }; | ||||
| 
 | ||||
| [Exposed=(Window,Worker)] | ||||
| interface BackgroundFetchFetches { | ||||
|   readonly attribute Request request; | ||||
| }; | ||||
| 
 | ||||
| [Exposed=(Window,Worker)] | ||||
| interface BackgroundFetchActiveFetches : BackgroundFetchFetches { | ||||
|   readonly attribute Promise<Response> responseReady; | ||||
|   // TODO: this will include fetch controller/observer objects | ||||
| }; | ||||
| 
 | ||||
| // 3.4. Events | ||||
| 
 | ||||
| partial interface ServiceWorkerGlobalScope { | ||||
|   attribute EventHandler onbackgroundfetched; | ||||
|   attribute EventHandler onbackgroundfetchfail; | ||||
|   attribute EventHandler onbackgroundfetchabort; | ||||
|   attribute EventHandler onbackgroundfetchclick; | ||||
| }; | ||||
| 
 | ||||
| // 3.4.1. BackgroundFetchEvent | ||||
| 
 | ||||
| [Constructor(DOMString type, BackgroundFetchEventInit init), Exposed=ServiceWorker] | ||||
| interface BackgroundFetchEvent : ExtendableEvent { | ||||
|   readonly attribute DOMString tag; | ||||
| }; | ||||
| 
 | ||||
| dictionary BackgroundFetchEventInit : ExtendableEventInit { | ||||
|   required DOMString tag; | ||||
| }; | ||||
| 
 | ||||
| // 3.4.2. BackgroundFetchEndEvent | ||||
| 
 | ||||
| [Constructor(DOMString type, BackgroundFetchEndEventInit init), Exposed=ServiceWorker] | ||||
| interface BackgroundFetchEndEvent : BackgroundFetchEvent { | ||||
|   readonly attribute FrozenArray<BackgroundFetchSettledFetches> completeFetches; | ||||
| 
 | ||||
|   Promise<void> updateUI(DOMString title); | ||||
| }; | ||||
| 
 | ||||
| dictionary BackgroundFetchEndEventInit : BackgroundFetchEventInit { | ||||
|   required BackgroundFetchSettledFetches completeFetches; | ||||
| }; | ||||
| 
 | ||||
| [Exposed=ServiceWorker] | ||||
| interface BackgroundFetchSettledFetches : BackgroundFetchFetches { | ||||
|   readonly attribute Response? response; | ||||
| }; | ||||
| 
 | ||||
| // 3.4.3. BackgroundFetchFailEvent | ||||
| 
 | ||||
| [Constructor(DOMString type, BackgroundFetchEndEventInit init), Exposed=ServiceWorker] | ||||
| interface BackgroundFetchFailEvent : BackgroundFetchEndEvent { | ||||
|   readonly attribute FrozenArray<BackgroundFetchSettledFetches> failedFetches; | ||||
| }; | ||||
| 
 | ||||
| dictionary BackgroundFetchFailEventInit : BackgroundFetchEndEventInit { | ||||
|   required BackgroundFetchSettledFetches failedFetches; | ||||
| }; | ||||
| 
 | ||||
| // 3.4.4. BackgroundFetchClickEvent | ||||
| 
 | ||||
| [Constructor(DOMString type, BackgroundFetchEndEventInit init), Exposed=ServiceWorker] | ||||
| interface BackgroundFetchClickEvent : BackgroundFetchEvent { | ||||
|   readonly attribute BackgroundFetchState state; | ||||
| }; | ||||
| 
 | ||||
| dictionary BackgroundFetchClickEventInit : BackgroundFetchEventInit { | ||||
|   required BackgroundFetchState state; | ||||
| }; | ||||
| 
 | ||||
| enum BackgroundFetchState { "pending", "succeeded", "failed" }; | ||||
|  | @ -0,0 +1,16 @@ | |||
| 'use strict'; | ||||
| 
 | ||||
| importScripts('/resources/testharness.js'); | ||||
| importScripts('/resources/WebIDLParser.js', '/resources/idlharness.js'); | ||||
| 
 | ||||
| promise_test(function() { | ||||
|   return fetch('interfaces.idl') | ||||
|     .then(response => response.text()) | ||||
|     .then(idls => { | ||||
|       var idlArray = new IdlArray(); | ||||
|       idlArray.add_untested_idls('interface ServiceWorkerRegistration {};'); | ||||
|       idlArray.add_untested_idls('[Exposed=ServiceWorker] interface ServiceWorkerGlobalScope {};'); | ||||
|       idlArray.add_idls(idls); | ||||
|       idlArray.test(); | ||||
|     }); | ||||
| }, 'Exposed interfaces in a Service Worker.'); | ||||
|  | @ -1,147 +0,0 @@ | |||
| 'use strict'; | ||||
| 
 | ||||
| // Bluetooth UUID constants:
 | ||||
| // Services:
 | ||||
| var blocklist_test_service_uuid = "611c954a-263b-4f4a-aab6-01ddb953f985"; | ||||
| var request_disconnection_service_uuid = "01d7d889-7451-419f-aeb8-d65e7b9277af"; | ||||
| // Characteristics:
 | ||||
| var blocklist_exclude_reads_characteristic_uuid = "bad1c9a2-9a5b-4015-8b60-1579bbbf2135"; | ||||
| var request_disconnection_characteristic_uuid = "01d7d88a-7451-419f-aeb8-d65e7b9277af"; | ||||
| // Descriptors:
 | ||||
| var blocklist_exclude_reads_descriptor_uuid = "aaaaaaaa-aaaa-1181-0510-810819516110"; | ||||
| var blocklist_descriptor_uuid = "07711111-6104-0970-7011-1107105110aaa"; | ||||
| var characteristic_user_description_uuid = "00002901-0000-1000-8000-00805f9b34fb"; | ||||
| 
 | ||||
| // Bluetooth Adapter types:
 | ||||
| var adapter_type = { | ||||
|     not_present: 'NotPresentAdapter', | ||||
|     not_powered: 'NotPoweredAdapter', | ||||
|     empty: 'EmptyAdapter', | ||||
|     heart_rate: 'HeartRateAdapter', | ||||
|     two_heart_rate: 'TwoHeartRateServicesAdapter', | ||||
|     empty_name_heart_rate: 'EmptyNameHeartRateAdapter', | ||||
|     no_name_heart_rate: 'NoNameHeartRateAdapter', | ||||
|     glucose_heart_rate: 'GlucoseHeartRateAdapter', | ||||
|     unicode_device: 'UnicodeDeviceAdapter', | ||||
|     blocklist: 'BlocklistTestAdapter', | ||||
|     missing_characteristic_heart_rate: 'MissingCharacteristicHeartRateAdapter', | ||||
|     missing_service_heart_rate: 'MissingServiceHeartRateAdapter', | ||||
|     missing_descriptor_heart_rate: 'MissingDescriptorHeartRateAdapter' | ||||
| }; | ||||
| 
 | ||||
| var mock_device_name = { | ||||
|     heart_rate: 'Heart Rate Device', | ||||
|     glucose: 'Glucose Device' | ||||
| }; | ||||
| 
 | ||||
| var wrong = { | ||||
|     name: 'wrong_name', | ||||
|     service: 'wrong_service' | ||||
| }; | ||||
| 
 | ||||
| // Sometimes we need to test that using either the name, alias, or UUID
 | ||||
| // produces the same result. The following objects help us do that.
 | ||||
| var generic_access = { | ||||
|     alias: 0x1800, | ||||
|     name: 'generic_access', | ||||
|     uuid: '00001800-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var device_name = { | ||||
|     alias: 0x2a00, | ||||
|     name: 'gap.device_name', | ||||
|     uuid: '00002a00-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var reconnection_address = { | ||||
|     alias: 0x2a03, | ||||
|     name: 'gap.reconnection_address', | ||||
|     uuid: '00002a03-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var heart_rate = { | ||||
|     alias: 0x180d, | ||||
|     name: 'heart_rate', | ||||
|     uuid: '0000180d-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var heart_rate_measurement = { | ||||
|     alias: 0x2a37, | ||||
|     name: 'heart_rate_measurement', | ||||
|     uuid: '00002a37-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var body_sensor_location = { | ||||
|     alias: 0x2a38, | ||||
|     name: 'body_sensor_location', | ||||
|     uuid: '00002a38-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var glucose = { | ||||
|     alias: 0x1808, | ||||
|     name: 'glucose', | ||||
|     uuid: '00001808-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var battery_service = { | ||||
|     alias: 0x180f, | ||||
|     name: 'battery_service', | ||||
|     uuid: '0000180f-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var battery_level = { | ||||
|     alias: 0x2a19, | ||||
|     name: 'battery_level', | ||||
|     uuid: '00002a19-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var tx_power = { | ||||
|     alias: 0x1804, | ||||
|     name: 'tx_power', | ||||
|     uuid: '00001804-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var human_interface_device = { | ||||
|     alias: 0x1812, | ||||
|     name: 'human_interface_device', | ||||
|     uuid: '00001812-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var device_information = { | ||||
|     alias: 0x180a, | ||||
|     name: 'device_information', | ||||
|     uuid: '0000180a-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var peripherial_privacy_flag = { | ||||
|     alias: 0x2a02, | ||||
|     name: 'gap.peripheral_privacy_flag', | ||||
|     uuid: '00002a02-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var serial_number_string = { | ||||
|     alias: 0x2a25, | ||||
|     name: 'serial_number_string', | ||||
|     uuid: '00002a25-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var client_characteristic_configuration = { | ||||
|     alias: 0x2902, | ||||
|     name: 'gatt.client_characteristic_configuration', | ||||
|     uuid: '00002902-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| var number_of_digitals = { | ||||
|     alias: 0x2909, | ||||
|     name: 'number_of_digitals', | ||||
|     uuid: '00002909-0000-1000-8000-00805f9b34fb' | ||||
| }; | ||||
| 
 | ||||
| // Helper function for converting strings to an array of bytes.
 | ||||
| function asciiToDecimal(bytestr) { | ||||
|     var result = []; | ||||
|     for(var i = 0; i < bytestr.length; i++) { | ||||
|         result[i] = bytestr.charCodeAt(i) ; | ||||
|     } | ||||
|     return result; | ||||
| } | ||||
							
								
								
									
										19
									
								
								testing/web-platform/tests/bluetooth/idl-Bluetooth.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								testing/web-platform/tests/bluetooth/idl-Bluetooth.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | |||
| <!DOCTYPE html> | ||||
| <title>Bluetooth interface</title> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script> | ||||
| 'use strict'; | ||||
| 
 | ||||
| test(() => { | ||||
|   assert_throws(null, () => new Bluetooth(), | ||||
|                 'the constructor should not be callable with "new"'); | ||||
|   assert_throws(null, () => Bluetooth(), | ||||
|                 'the constructor should not be callable'); | ||||
| 
 | ||||
|   // Bluetooth implements BluetoothDiscovery; | ||||
|   assert_true('requestDevice' in navigator.bluetooth); | ||||
|   assert_equals(navigator.bluetooth.requestDevice.length, 0); | ||||
| }, 'Bluetooth IDL test'); | ||||
| 
 | ||||
| </script> | ||||
|  | @ -311,7 +311,8 @@ def get_git_cmd(repo_path): | |||
|     def git(cmd, *args): | ||||
|         full_cmd = ["git", cmd] + list(args) | ||||
|         try: | ||||
|             return subprocess.check_output(full_cmd, cwd=repo_path, stderr=subprocess.STDOUT) | ||||
|             logger.debug(" ".join(full_cmd)) | ||||
|             return subprocess.check_output(full_cmd, cwd=repo_path, stderr=subprocess.STDOUT).strip() | ||||
|         except subprocess.CalledProcessError as e: | ||||
|             logger.error("Git command exited with status %i" % e.returncode) | ||||
|             logger.error(e.output) | ||||
|  | @ -363,10 +364,9 @@ class pwd(object): | |||
|         self.old_dir = None | ||||
| 
 | ||||
| 
 | ||||
| def fetch_wpt_master(user): | ||||
|     """Fetch the master branch via git.""" | ||||
| def fetch_wpt(user, *args): | ||||
|     git = get_git_cmd(wpt_root) | ||||
|     git("fetch", "https://github.com/%s/web-platform-tests.git" % user, "master:master") | ||||
|     git("fetch", "https://github.com/%s/web-platform-tests.git" % user, *args) | ||||
| 
 | ||||
| 
 | ||||
| def get_sha1(): | ||||
|  | @ -390,12 +390,44 @@ def install_wptrunner(): | |||
|     call("pip", "install", wptrunner_root) | ||||
| 
 | ||||
| 
 | ||||
| def get_files_changed(): | ||||
| def get_branch_point(user): | ||||
|     git = get_git_cmd(wpt_root) | ||||
|     if os.environ.get("TRAVIS_PULL_REQUEST", "false") != "false": | ||||
|         # This is a PR, so the base branch is in TRAVIS_BRANCH | ||||
|         branch_point = os.environ.get("TRAVIS_COMMIT_RANGE").split(".", 1)[0] | ||||
|         branch_point = git("rev-parse", branch_point) | ||||
|     else: | ||||
|         # Otherwise we aren't on a PR, so we try to find commits that are only in the | ||||
|         # current branch c.f. | ||||
|         # http://stackoverflow.com/questions/13460152/find-first-ancestor-commit-in-another-branch | ||||
|         head = git("rev-parse", "HEAD") | ||||
|         # To do this we need all the commits in the local copy | ||||
|         fetch_wpt(user, "--unshallow", "+refs/heads/*:refs/remotes/origin/*") | ||||
|         not_heads = [item for item in git("rev-parse", "--not", "--all").split("\n") | ||||
|                      if not head in item] | ||||
|         commits = git("rev-list", "HEAD", *not_heads).split("\n") | ||||
|         first_commit = commits[-1] | ||||
|         branch_point = git("rev-parse", first_commit + "^") | ||||
|         # The above can produce a too-early commit if we are e.g. on master and there are | ||||
|         # preceding changes that were rebased and so aren't on any other branch. To avoid | ||||
|         # this issue we check for the later of the above branch point and the merge-base | ||||
|         # with master | ||||
|         merge_base = git("merge-base", "HEAD", "origin/master") | ||||
|         if (branch_point != merge_base and | ||||
|             not git("log", "--oneline", "%s..%s" % (merge_base, branch_point)).strip()): | ||||
|             logger.debug("Using merge-base as the branch point") | ||||
|             branch_point = merge_base | ||||
|         else: | ||||
|             logger.debug("Using first commit on another branch as the branch point") | ||||
| 
 | ||||
|     logger.debug("Branch point from master: %s" % branch_point) | ||||
|     return branch_point | ||||
| 
 | ||||
| 
 | ||||
| def get_files_changed(branch_point): | ||||
|     """Get and return files changed since current branch diverged from master.""" | ||||
|     root = os.path.abspath(os.curdir) | ||||
|     git = get_git_cmd(wpt_root) | ||||
|     branch_point = git("merge-base", "HEAD", "master").strip() | ||||
|     logger.debug("Branch point from master: %s" % branch_point) | ||||
|     files = git("diff", "--name-only", "-z", "%s.." % branch_point) | ||||
|     if not files: | ||||
|         return [] | ||||
|  | @ -557,7 +589,7 @@ def process_results(log, iterations): | |||
|     results = handler.results | ||||
|     for test_name, test in results.iteritems(): | ||||
|         if is_inconsistent(test["status"], iterations): | ||||
|             inconsistent.append((test_name, None, test["status"], None)) | ||||
|             inconsistent.append((test_name, None, test["status"], [])) | ||||
|         for subtest_name, subtest in test["subtests"].iteritems(): | ||||
|             if is_inconsistent(subtest["status"], iterations): | ||||
|                 inconsistent.append((test_name, subtest_name, subtest["status"], subtest["messages"])) | ||||
|  | @ -584,7 +616,7 @@ def markdown_adjust(s): | |||
|     s = s.replace('\t', u'\\t') | ||||
|     s = s.replace('\n', u'\\n') | ||||
|     s = s.replace('\r', u'\\r') | ||||
|     s = s.replace('`',  u'\\`') | ||||
|     s = s.replace('`',  u'') | ||||
|     return s | ||||
| 
 | ||||
| 
 | ||||
|  | @ -726,14 +758,16 @@ def main(): | |||
|             logger.critical("Unrecognised browser %s" % browser_name) | ||||
|             return 1 | ||||
| 
 | ||||
|         fetch_wpt_master(args.user) | ||||
|         fetch_wpt(args.user, "master:master") | ||||
| 
 | ||||
|         head_sha1 = get_sha1() | ||||
|         logger.info("Testing web-platform-tests at revision %s" % head_sha1) | ||||
| 
 | ||||
|         branch_point = get_branch_point(args.user) | ||||
| 
 | ||||
|         # For now just pass the whole list of changed files to wptrunner and | ||||
|         # assume that it will run everything that's actually a test | ||||
|         files_changed = get_files_changed() | ||||
|         files_changed = get_files_changed(branch_point) | ||||
| 
 | ||||
|         if not files_changed: | ||||
|             logger.info("No files changed") | ||||
|  |  | |||
|  | @ -2,4 +2,3 @@ set -ex | |||
| 
 | ||||
| ./manifest | ||||
| ./lint | ||||
| ./diff-manifest.py | ||||
|  |  | |||
							
								
								
									
										116
									
								
								testing/web-platform/tests/common/PrefixedLocalStorage.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								testing/web-platform/tests/common/PrefixedLocalStorage.js
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,116 @@ | |||
| /** | ||||
|  * Supports pseudo-"namespacing" localStorage for a given test | ||||
|  * by generating and using a unique prefix for keys. Why trounce on other | ||||
|  * tests' localStorage items when you can keep it "separated"? | ||||
|  * | ||||
|  * PrefixedLocalStorageTest: Instantiate in testharness.js tests to generate | ||||
|  *   a new unique-ish prefix | ||||
|  * PrefixedLocalStorageResource: Instantiate in supporting test resource | ||||
|  *   files to use/share a prefix generated by a test. | ||||
|  */ | ||||
| var PrefixedLocalStorage = function () { | ||||
|   this.prefix = ''; // Prefix for localStorage keys
 | ||||
|   this.param = 'prefixedLocalStorage'; // Param to use in querystrings
 | ||||
| }; | ||||
| 
 | ||||
| PrefixedLocalStorage.prototype.clear = function () { | ||||
|   if (this.prefix === '') { return; } | ||||
|   Object.keys(localStorage).forEach(sKey => { | ||||
|     if (sKey.indexOf(this.prefix) === 0) { | ||||
|       localStorage.removeItem(sKey); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Append/replace prefix parameter and value in URI querystring | ||||
|  * Use to generate URLs to resource files that will share the prefix. | ||||
|  */ | ||||
| PrefixedLocalStorage.prototype.url = function (uri) { | ||||
|   function updateUrlParameter (uri, key, value) { | ||||
|     var i         = uri.indexOf('#'); | ||||
|     var hash      = (i === -1) ? '' : uri.substr(i); | ||||
|     uri           = (i === -1) ? uri : uri.substr(0, i); | ||||
|     var re        = new RegExp(`([?&])${key}=.*?(&|$)`, 'i'); | ||||
|     var separator = uri.indexOf('?') !== -1 ? '&' : '?'; | ||||
|     uri = (uri.match(re)) ? uri.replace(re, `$1${key}=${value}$2`) : | ||||
|       `${uri}${separator}${key}=${value}`; | ||||
|     return uri + hash; | ||||
|   } | ||||
|   return updateUrlParameter(uri, this.param, this.prefix); | ||||
| }; | ||||
| 
 | ||||
| PrefixedLocalStorage.prototype.prefixedKey = function (baseKey) { | ||||
|   return `${this.prefix}${baseKey}`; | ||||
| }; | ||||
| 
 | ||||
| PrefixedLocalStorage.prototype.setItem = function (baseKey, value) { | ||||
|   localStorage.setItem(this.prefixedKey(baseKey), value); | ||||
| }; | ||||
| 
 | ||||
| /** | ||||
|  * Listen for `storage` events pertaining to a particular key, | ||||
|  * prefixed with this object's prefix. Ignore when value is being set to null | ||||
|  * (i.e. removeItem). | ||||
|  */ | ||||
| PrefixedLocalStorage.prototype.onSet = function (baseKey, fn) { | ||||
|   window.addEventListener('storage', e => { | ||||
|     var match = this.prefixedKey(baseKey); | ||||
|     if (e.newValue !== null && e.key.indexOf(match) === 0) { | ||||
|       fn.call(this, e); | ||||
|     } | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| /***************************************************************************** | ||||
|  * Use in a testharnessjs test to generate a new key prefix. | ||||
|  * async_test(t => { | ||||
|  *   var prefixedStorage = new PrefixedLocalStorageTest(); | ||||
|  *   t.add_cleanup(() => prefixedStorage.cleanup()); | ||||
|  *   /... | ||||
|  * }); | ||||
|  */ | ||||
| var PrefixedLocalStorageTest = function () { | ||||
|   PrefixedLocalStorage.call(this); | ||||
|   this.prefix = `${document.location.pathname}-${Math.random()}-${Date.now()}-`; | ||||
| }; | ||||
| PrefixedLocalStorageTest.prototype = Object.create(PrefixedLocalStorage.prototype); | ||||
| PrefixedLocalStorageTest.prototype.constructor = PrefixedLocalStorageTest; | ||||
| 
 | ||||
| /** | ||||
|  * Use in a cleanup function to clear out prefixed entries in localStorage | ||||
|  */ | ||||
| PrefixedLocalStorageTest.prototype.cleanup = function () { | ||||
|   this.setItem('closeAll', 'true'); | ||||
|   this.clear(); | ||||
| }; | ||||
| 
 | ||||
| /***************************************************************************** | ||||
|  * Use in test resource files to share a prefix generated by a | ||||
|  * PrefixedLocalStorageTest. Will look in URL querystring for prefix. | ||||
|  * Setting `close_on_cleanup` opt truthy will make this script's window listen | ||||
|  * for storage `closeAll` event from controlling test and close itself. | ||||
|  * | ||||
|  * var PrefixedLocalStorageResource({ close_on_cleanup: true }); | ||||
|  */ | ||||
| var PrefixedLocalStorageResource = function (options) { | ||||
|   PrefixedLocalStorage.call(this); | ||||
|   this.options = Object.assign({}, { | ||||
|     close_on_cleanup: false | ||||
|   }, options || {}); | ||||
|   // Check URL querystring for prefix to use
 | ||||
|   var regex = new RegExp(`[?&]${this.param}(=([^&#]*)|&|#|$)`), | ||||
|     results = regex.exec(document.location.href); | ||||
|   if (results && results[2]) { | ||||
|     this.prefix = results[2]; | ||||
|   } | ||||
|   // Optionally have this window close itself when the PrefixedLocalStorageTest
 | ||||
|   // sets a `closeAll` item.
 | ||||
|   if (this.options.close_on_cleanup) { | ||||
|     this.onSet('closeAll', () => { | ||||
|       window.close(); | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
| PrefixedLocalStorageResource.prototype = Object.create(PrefixedLocalStorage.prototype); | ||||
| PrefixedLocalStorageResource.prototype.constructor = PrefixedLocalStorageResource; | ||||
							
								
								
									
										8
									
								
								testing/web-platform/tests/common/domain-setter.sub.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								testing/web-platform/tests/common/domain-setter.sub.html
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| <!DOCTYPE html> | ||||
| <meta charset="utf-8"> | ||||
| <title>A page that will likely be same-origin-domain but not same-origin</title> | ||||
| 
 | ||||
| <script> | ||||
| "use strict"; | ||||
| document.domain = "{{host}}"; | ||||
| </script> | ||||
|  | @ -0,0 +1,57 @@ | |||
| self.testSettingImmutablePrototypeToNewValueOnly = | ||||
|   (prefix, target, newValue, newValueString, { isSameOriginDomain }) => { | ||||
|   test(() => { | ||||
|     assert_throws(new TypeError, () => { | ||||
|       Object.setPrototypeOf(target, newValue); | ||||
|     }); | ||||
|   }, `${prefix}: setting the prototype to ${newValueString} via Object.setPrototypeOf should throw a TypeError`); | ||||
| 
 | ||||
|   let dunderProtoError = "SecurityError"; | ||||
|   let dunderProtoErrorName = "\"SecurityError\" DOMException"; | ||||
|   if (isSameOriginDomain) { | ||||
|     dunderProtoError = new TypeError(); | ||||
|     dunderProtoErrorName = "TypeError"; | ||||
|   } | ||||
| 
 | ||||
|   test(() => { | ||||
|     assert_throws(dunderProtoError, function() { | ||||
|       target.__proto__ = newValue; | ||||
|     }); | ||||
|   }, `${prefix}: setting the prototype to ${newValueString} via __proto__ should throw a ${dunderProtoErrorName}`); | ||||
| 
 | ||||
|   test(() => { | ||||
|     assert_false(Reflect.setPrototypeOf(target, newValue)); | ||||
|   }, `${prefix}: setting the prototype to ${newValueString} via Reflect.setPrototypeOf should return false`); | ||||
| }; | ||||
| 
 | ||||
| self.testSettingImmutablePrototype = | ||||
|   (prefix, target, originalValue, { isSameOriginDomain }, newValue = {}, newValueString = "an empty object") => { | ||||
|   testSettingImmutablePrototypeToNewValueOnly(prefix, target, newValue, newValueString, { isSameOriginDomain }); | ||||
| 
 | ||||
|   const originalValueString = originalValue === null ? "null" : "its original value"; | ||||
| 
 | ||||
|   test(() => { | ||||
|     assert_equals(Object.getPrototypeOf(target), originalValue); | ||||
|   }, `${prefix}: the prototype must still be ${originalValueString}`); | ||||
| 
 | ||||
|   test(() => { | ||||
|     Object.setPrototypeOf(target, originalValue); | ||||
|   }, `${prefix}: setting the prototype to ${originalValueString} via Object.setPrototypeOf should not throw`); | ||||
| 
 | ||||
|   if (isSameOriginDomain) { | ||||
|     test(() => { | ||||
|       target.__proto__ = originalValue; | ||||
|     }, `${prefix}: setting the prototype to ${originalValueString} via __proto__ should not throw`); | ||||
|   } else { | ||||
|     test(() => { | ||||
|       assert_throws("SecurityError", function() { | ||||
|         target.__proto__ = newValue; | ||||
|       }); | ||||
|     }, `${prefix}: setting the prototype to ${originalValueString} via __proto__ should throw a "SecurityError" since ` + | ||||
|        `it ends up in CrossOriginGetOwnProperty`); | ||||
|   } | ||||
| 
 | ||||
|   test(() => { | ||||
|     assert_true(Reflect.setPrototypeOf(target, originalValue)); | ||||
|   }, `${prefix}: setting the prototype to ${originalValueString} via Reflect.setPrototypeOf should return true`); | ||||
| }; | ||||
|  | @ -89,7 +89,7 @@ | |||
|     "html/attributes/lang/extlang-bad-novalid.html": "Bad value \u201cbat-smg\u201d for attribute \u201clang\u201d on element \u201cbody\u201d: Bad language tag: Bad extlang subtag \u201csmg\u201d.", | ||||
|     "html/attributes/lang/xmllang-different-value-novalid.html": "When the attribute \u201cxml:lang\u201d in no namespace is specified, the element must also have the attribute \u201clang\u201d present with the same value.", | ||||
|     "html/attributes/lang/xmllang-only-novalid.html": "When the attribute \u201cxml:lang\u201d in no namespace is specified, the element must also have the attribute \u201clang\u201d present with the same value.", | ||||
|     "html/attributes/role/unrecognized-role-name-novalid.html": "Discarding unrecognized tokens \u201cswitch\u201d, \u201cinput\u201d from value of attribute \u201crole\u201d. Browsers ignore any token that is not a defined ARIA non-abstract role.", | ||||
|     "html/attributes/role/unrecognized-role-name-novalid.html": "Discarding unrecognized token \u201cinput\u201d from value of attribute \u201crole\u201d. Browsers ignore any token that is not a defined ARIA non-abstract role.", | ||||
|     "html/attributes/spellcheck/value-bad-novalid.html": "Bad value \u201cbadvalue\u201d for attribute \u201cspellcheck\u201d on element \u201cp\u201d.", | ||||
|     "html/elements/a/href/fragment-backslash-novalid.html": "Bad value \u201c#\\\u201d for attribute \u201chref\u201d on element \u201ca\u201d: Bad URL: Illegal character in fragment: \u201c\\\u201d is not allowed.", | ||||
|     "html/elements/a/href/fragment-contains-hash-novalid.html": "Bad value \u201chttp://foo/path#f#g\u201d for attribute \u201chref\u201d on element \u201ca\u201d: Bad URL: Illegal character in fragment: \u201c#\u201d is not allowed.", | ||||
|  | @ -2435,7 +2435,7 @@ | |||
|     "xhtml/elements/keygen/361-novalid.xhtml": "The \u201ckeygen\u201d element is obsolete. ", | ||||
|     "xhtml/elements/keygen/keygen-novalid.xhtml": "The \u201ckeygen\u201d element is obsolete. ", | ||||
|     "xhtml/elements/link/001-novalid.xhtml": "Element \u201clink\u201d is missing required attribute \u201chref\u201d.", | ||||
|     "xhtml/elements/menu/001-haswarn.xhtml": "The \u201cmenu\u201d element is not supported in all browsers. Please be sure to test, and consider using a polyfill.", | ||||
|     "xhtml/elements/menu/001-haswarn.xhtml": "The \u201ccontextmenu\u201d attribute is not supported in all browsers. Please be sure to test, and consider using a polyfill.", | ||||
|     "xhtml/elements/menu/001-novalid.xhtml": "The \u201ccontextmenu\u201d attribute must refer to a \u201cmenu\u201d element.", | ||||
|     "xhtml/elements/meter/010-novalid.xhtml": "The value of the \u201cmin\u201d attribute must be less than or equal to the value of the \u201cvalue\u201d attribute.", | ||||
|     "xhtml/elements/meter/011-novalid.xhtml": "Element \u201cmeter\u201d is missing required attribute \u201cvalue\u201d.", | ||||
|  |  | |||
|  | @ -0,0 +1,23 @@ | |||
| <!DOCTYPE html> | ||||
| <html> | ||||
| <head> | ||||
| <title>Console Count - Logging Manual Test</title> | ||||
| <meta name="author" title="Dominic Farolino" href="mailto:domfarolino@gmail.com"> | ||||
| <meta name="assert" content="Console count method default parameter should work"> | ||||
| <link rel="help" href="https://console.spec.whatwg.org/#count"> | ||||
| </head> | ||||
| <body> | ||||
| <p>Open the console inside the developer tools. It should contain four lines whose contents are:</p> | ||||
| <p><code>default: 1</code></p> | ||||
| <p><code>default: 2</code></p> | ||||
| <p><code>default: 3</code></p> | ||||
| <p><code>default: 4</code></p> | ||||
| 
 | ||||
| <script> | ||||
| console.count(); | ||||
| console.count(undefined); | ||||
| console.count("default"); | ||||
| console.count({toString() {return "default"}}); | ||||
| </script> | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,9 @@ | |||
| "use strict"; | ||||
| 
 | ||||
| test(() => { | ||||
|   assert_equals(console.timeline, undefined, "console.timeline should be undefined"); | ||||
| }, "'timeline' function should not exist on the console object"); | ||||
| 
 | ||||
| test(() => { | ||||
|   assert_equals(console.timelineEnd, undefined, "console.timelineEnd should be undefined"); | ||||
| }, "'timelineEnd' function should not exist on the console object"); | ||||
|  | @ -0,0 +1,80 @@ | |||
| <!DOCTYPE HTML> | ||||
| <html> | ||||
| 
 | ||||
| <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <title>base-uri works correctly inside a sandboxed iframe.</title> | ||||
|     <script src='/resources/testharness.js'></script> | ||||
|     <script src='/resources/testharnessreport.js'></script> | ||||
| 
 | ||||
|     <!-- CSP served: base-uri 'self' --> | ||||
| </head> | ||||
| 
 | ||||
| <body> | ||||
|     <h1>base-uri works correctly inside a sandboxed iframe.</h1> | ||||
|     <div id='log'></div> | ||||
| 
 | ||||
|     <script> | ||||
|         window.addEventListener('securitypolicyviolation', function(e) { | ||||
|             assert_unreached('No CSP violation report has fired.'); | ||||
|         }); | ||||
| 
 | ||||
|         async_test(function(t) { | ||||
|             var i = document.createElement('iframe'); | ||||
|             i.sandbox = 'allow-scripts'; | ||||
|             i.style.display = 'none'; | ||||
|             i.srcdoc = ` | ||||
|             <script> | ||||
|               window.addEventListener('securitypolicyviolation', function() { | ||||
|                 top.postMessage('FAIL', '*'); | ||||
|               }); | ||||
|             </sc` + `ript> | ||||
|             <base href="{{location[scheme]}}://{{domains[]}}:{{ports[http][0]}}/base/"> | ||||
|             <script> | ||||
|               top.postMessage(document.baseURI, '*'); | ||||
|             </sc` + `ript>`; | ||||
| 
 | ||||
|             window.addEventListener('message', t.step_func(function(e) { | ||||
|                 if (e.source === i.contentWindow) { | ||||
|                     assert_equals(e.data, location.origin + '/base/'); | ||||
|                     t.done(); | ||||
|                 } | ||||
|             })); | ||||
| 
 | ||||
|             document.body.appendChild(i); | ||||
|         }, 'base-uri \'self\' works with same-origin sandboxed iframes.'); | ||||
| 
 | ||||
|         async_test(function(t) { | ||||
|             var i = document.createElement('iframe'); | ||||
|             i.sandbox = 'allow-scripts'; | ||||
|             i.style.display = 'none'; | ||||
|             i.srcdoc = ` | ||||
|             <script> | ||||
|               window.addEventListener('securitypolicyviolation', | ||||
|                 function(violation) { | ||||
|                   if (violation.blockedURI !== '{{location[scheme]}}://{{domains[www2]}}:{{ports[http][0]}}/base/' || violation.effectiveDirective !== 'base-uri') { | ||||
|                       top.postMessage('FAIL'); | ||||
|                       return; | ||||
|                   } | ||||
|                   top.postMessage(document.baseURI, '*'); | ||||
|               }); | ||||
|             </sc` + `ript> | ||||
|             <base href="{{location[scheme]}}://{{domains[www2]}}:{{ports[http][0]}}/base/"> | ||||
|             <script> | ||||
|               top.postMessage(document.baseURI, '*'); | ||||
|             </sc` + `ript>`; | ||||
| 
 | ||||
|             window.addEventListener('message', t.step_func(function(e) { | ||||
|                 if (e.source === i.contentWindow) { | ||||
|                     assert_equals(e.data, location.href); | ||||
|                     t.done(); | ||||
|                 } | ||||
|             })); | ||||
| 
 | ||||
|             document.body.appendChild(i); | ||||
|         }, 'base-uri \'self\' blocks foreign-origin sandboxed iframes.'); | ||||
|     </script> | ||||
| 
 | ||||
| </body> | ||||
| 
 | ||||
| </html> | ||||
|  | @ -0,0 +1,5 @@ | |||
| Expires: Mon, 26 Jul 1997 05:00:00 GMT | ||||
| Cache-Control: no-store, no-cache, must-revalidate | ||||
| Cache-Control: post-check=0, pre-check=0, false | ||||
| Pragma: no-cache | ||||
| Content-Security-Policy: base-uri 'self' | ||||
|  | @ -0,0 +1,16 @@ | |||
| <!DOCTYPE html> | ||||
| <meta http-equiv="Content-Security-Policy" content="connect-src 'self'"> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script> | ||||
|     async_test(t => { | ||||
|       document.addEventListener("securitypolicyviolation", t.step_func_done(e => { | ||||
|         if (e.blockedURI != "http://{{domains[www]}}:{{ports[http][0]}}/common/text-plain.txt") | ||||
|             return; | ||||
| 
 | ||||
|         assert_equals(e.violatedDirective, "connect-src"); | ||||
|       })); | ||||
| 
 | ||||
|       assert_true(navigator.sendBeacon("http://{{domains[www]}}:{{ports[http][0]}}/common/text-plain.txt")); | ||||
|     }, "sendBeacon should not throw."); | ||||
| </script> | ||||
|  | @ -0,0 +1,61 @@ | |||
| <!DOCTYPE html> | ||||
| <meta http-equiv="Content-Security-Policy" content="connect-src 'self'"> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script> | ||||
|     async_test(t => { | ||||
|       var errorEvent = false; | ||||
|       var cspEvent = false; | ||||
| 
 | ||||
|       var es = new EventSource("http://{{domains[www]}}:{{ports[http][0]}}/common/text-plain.txt"); | ||||
|       es.onerror = t.step_func(e => { | ||||
|         assert_equals(es.readyState, EventSource.CLOSED); | ||||
| 
 | ||||
|         assert_false(errorEvent); | ||||
|         errorEvent = true; | ||||
|         if (cspEvent) | ||||
|             t.done(); | ||||
|       }); | ||||
| 
 | ||||
|       document.addEventListener("securitypolicyviolation", t.step_func(e => { | ||||
|         if (e.blockedURI != "http://{{domains[www]}}:{{ports[http][0]}}/common/text-plain.txt") | ||||
|             return; | ||||
| 
 | ||||
|         assert_equals(es.readyState, EventSource.CLOSED); | ||||
|         assert_equals(e.violatedDirective, "connect-src"); | ||||
| 
 | ||||
|         assert_false(cspEvent); | ||||
|         cspEvent = true; | ||||
|         if (errorEvent) | ||||
|             t.done(); | ||||
|       })); | ||||
|     }, "EventSource should fire onerror."); | ||||
| 
 | ||||
|     async_test(t => { | ||||
|       var errorEvent = false; | ||||
|       var cspEvent = false; | ||||
| 
 | ||||
|       var es = new EventSource("http://{{domains[www]}}:{{ports[http][0]}}/common/text-plain.txt"); | ||||
|       es.onerror = t.step_func(e => { | ||||
|         assert_equals(es.readyState, EventSource.CLOSED); | ||||
| 
 | ||||
|         assert_false(errorEvent); | ||||
|         errorEvent = true; | ||||
|         if (cspEvent) | ||||
|             t.done(); | ||||
|       }); | ||||
| 
 | ||||
|       document.addEventListener("securitypolicyviolation", t.step_func(e => { | ||||
|         if (e.blockedURI != "http://{{domains[www]}}:{{ports[http][0]}}/common/text-plain.txt") | ||||
|             return; | ||||
| 
 | ||||
|         assert_equals(es.readyState, EventSource.CLOSED); | ||||
|         assert_equals(e.violatedDirective, "connect-src"); | ||||
| 
 | ||||
|         assert_false(cspEvent); | ||||
|         cspEvent = true; | ||||
|         if (errorEvent) | ||||
|             t.done(); | ||||
|       })); | ||||
|     }, "EventSource should fire onerror."); | ||||
| 
 | ||||
|  | @ -0,0 +1,34 @@ | |||
| <!DOCTYPE html> | ||||
| <meta http-equiv="Content-Security-Policy" content="connect-src 'self'"> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script> | ||||
|     async_test(t => { | ||||
|       var errorEvent = false; | ||||
|       var cspEvent = false; | ||||
| 
 | ||||
|       var ws = new WebSocket("ws://{{domains[www]}}:{{ports[ws][0]}}/echo"); | ||||
|       ws.onopen = t.unreached_func("open should not fire."); | ||||
|       ws.onerror = t.step_func(e => { | ||||
|         assert_equals(ws.readyState, WebSocket.CLOSED); | ||||
| 
 | ||||
|         assert_false(errorEvent); | ||||
|         errorEvent = true; | ||||
|         if (cspEvent) | ||||
|             t.done(); | ||||
|       }); | ||||
| 
 | ||||
|       document.addEventListener("securitypolicyviolation", t.step_func(e => { | ||||
|         if (e.blockedURI != "ws://{{domains[www]}}:{{ports[ws][0]}}") | ||||
|             return; | ||||
| 
 | ||||
|         assert_equals(ws.readyState, WebSocket.CLOSED); | ||||
|         assert_equals(e.violatedDirective, "connect-src"); | ||||
| 
 | ||||
|         assert_false(cspEvent); | ||||
|         cspEvent = true; | ||||
|         if (errorEvent) | ||||
|             t.done(); | ||||
|       })); | ||||
|     }, "WebSocket should fire error event."); | ||||
| </script> | ||||
|  | @ -0,0 +1,69 @@ | |||
| <!DOCTYPE html> | ||||
| <meta http-equiv="Content-Security-Policy" content="connect-src 'self'"> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| <script> | ||||
|     async_test(t => { | ||||
|       var errorEvent = false; | ||||
|       var cspEvent = false; | ||||
| 
 | ||||
|       var xhr = new XMLHttpRequest; | ||||
|       xhr.open("GET", "http://{{domains[www]}}:{{ports[http][0]}}/common/text-plain.txt"); | ||||
|       xhr.onload = t.unreached_func("Load should not fire."); | ||||
|       xhr.onerror = t.step_func(e => { | ||||
|         assert_equals(xhr.readyState, XMLHttpRequest.DONE); | ||||
| 
 | ||||
|         assert_false(errorEvent); | ||||
|         errorEvent = true; | ||||
|         if (cspEvent) | ||||
|             t.done(); | ||||
|       }); | ||||
| 
 | ||||
|       document.addEventListener("securitypolicyviolation", t.step_func(e => { | ||||
|         if (e.blockedURI != "http://{{domains[www]}}:{{ports[http][0]}}/common/text-plain.txt") | ||||
|             return; | ||||
| 
 | ||||
|         assert_equals(xhr.readyState, XMLHttpRequest.DONE); | ||||
|         assert_equals(e.violatedDirective, "connect-src"); | ||||
| 
 | ||||
|         assert_false(cspEvent); | ||||
|         cspEvent = true; | ||||
|         if (errorEvent) | ||||
|             t.done(); | ||||
|       })); | ||||
| 
 | ||||
|       xhr.send(); | ||||
|     }, "XHR should fire onerror."); | ||||
| 
 | ||||
|     async_test(t => { | ||||
|       var errorEvent = false; | ||||
|       var cspEvent = false; | ||||
| 
 | ||||
|       var xhr = new XMLHttpRequest; | ||||
|       xhr.open("GET", "/common/redirect-opt-in.py?status=307&location=http://{{domains[www]}}:{{ports[http][0]}}/common/text-plain.txt"); | ||||
|       xhr.onload = t.unreached_func("Load should not fire."); | ||||
|       xhr.onerror = t.step_func(e => { | ||||
|         assert_equals(xhr.readyState, XMLHttpRequest.DONE); | ||||
| 
 | ||||
|         assert_false(errorEvent); | ||||
|         errorEvent = true; | ||||
|         if (cspEvent) | ||||
|             t.done(); | ||||
|       }); | ||||
| 
 | ||||
|       document.addEventListener("securitypolicyviolation", t.step_func(e => { | ||||
|         if (e.blockedURI != "http://{{domains[www]}}:{{ports[http][0]}}") | ||||
|             return; | ||||
| 
 | ||||
|         assert_equals(xhr.readyState, XMLHttpRequest.DONE); | ||||
|         assert_equals(e.violatedDirective, "connect-src"); | ||||
| 
 | ||||
|         assert_false(cspEvent); | ||||
|         cspEvent = true; | ||||
|         if (errorEvent) | ||||
|             t.done(); | ||||
|       })); | ||||
| 
 | ||||
|       xhr.send(); | ||||
|     }, "XHR should fire onerror after a redirect."); | ||||
| </script> | ||||
|  | @ -1,6 +0,0 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <title>csp font-src: blacklisted</title> | ||||
| <link href="fonts.css" rel="stylesheet" type="text/css"> | ||||
|           | ||||
| <p>The test passes if the line above are boxes in the test and glyphs in the reference.</p> | ||||
|  | @ -1,9 +0,0 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <meta http-equiv="Content-Security-Policy" content="font-src 'none'"> | ||||
| <title>csp font-src: blacklisted</title> | ||||
| <link rel="mismatch" href="font-blacklisted-ref.html"> | ||||
| <link rel="help" href="https://www.w3.org/TR/CSP2/#directive-font-src"> | ||||
| <link href="fonts.css" rel="stylesheet" type="text/css"> | ||||
|           | ||||
| <p>The test passes if the line above are boxes in the test and glyphs in the reference.</p> | ||||
|  | @ -0,0 +1,23 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <meta http-equiv="Content-Security-Policy" content="font-src {{domains[www1]}}:{{ports[http][0]}}"> | ||||
| <head> | ||||
|   <title>Test font loads if it matches font-src.</title> | ||||
|   <script src='/resources/testharness.js'></script> | ||||
|   <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|   <div id="log"/> | ||||
|   <script> | ||||
|     async_test(function(t) { | ||||
|       document.addEventListener("securitypolicyviolation", t.unreached_func("Loading allowed fonts should not trigger a violation.")); | ||||
|       var link = document.createElement('link'); | ||||
|       link.rel="preload"; | ||||
|       link.as="font"; | ||||
|       link.href="http://{{domains[www1]}}:{{ports[http][0]}}/content-security-policy/support/Ahem.ttf"; | ||||
|       link.onload = t.step_func_done(); | ||||
|       link.onerror = t.unreached_func("Should have loaded the font."); | ||||
|       document.getElementsByTagName('head')[0].appendChild(link); | ||||
|     }, "Test font loads if it matches font-src."); | ||||
|   </script> | ||||
| </body> | ||||
|  | @ -0,0 +1,22 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <meta http-equiv="Content-Security-Policy" content="font-src {{domains[www1]}}:{{ports[http][0]}}"> | ||||
| <head> | ||||
|   <title>Test font does not load if it does not match font-src.</title> | ||||
|   <script src='/resources/testharness.js'></script> | ||||
|   <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|   <div id="log"/> | ||||
|   <script> | ||||
|     async_test(function(t) { | ||||
|       var link = document.createElement('link'); | ||||
|       link.rel="preload"; | ||||
|       link.as="font"; | ||||
|       link.href="http://{{domains[www2]}}:{{ports[http][0]}}/content-security-policy/support/Ahem.ttf"; | ||||
|       link.onload = t.unreached_func("Should not have loaded the font."); | ||||
|       link.onerror = t.step_func_done(); | ||||
|       document.getElementsByTagName('head')[0].appendChild(link); | ||||
|     }, "Test font does not load if it does not match font-src."); | ||||
|   </script> | ||||
| </body> | ||||
|  | @ -0,0 +1,22 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <meta http-equiv="Content-Security-Policy" content="font-src 'none'"> | ||||
| <head> | ||||
|   <title>Test font does not load if it does not match font-src.</title> | ||||
|   <script src='/resources/testharness.js'></script> | ||||
|   <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|   <div id="log"/> | ||||
|   <script> | ||||
|     async_test(function(t) { | ||||
|       var link = document.createElement('link'); | ||||
|       link.rel="preload"; | ||||
|       link.as="font"; | ||||
|       link.href="http://{{domains[www]}}:{{ports[http][0]}}/content-security-policy/support/Ahem.ttf"; | ||||
|       link.onload = t.unreached_func("Should not have loaded the font."); | ||||
|       link.onerror = t.step_func_done(); | ||||
|       document.getElementsByTagName('head')[0].appendChild(link); | ||||
|     }, "Test font does not load if it does not match font-src."); | ||||
|   </script> | ||||
| </body> | ||||
|  | @ -0,0 +1,23 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <meta http-equiv="Content-Security-Policy" content="font-src 'self'"> | ||||
| <head> | ||||
|   <title>Test font loads if it matches font-src.</title> | ||||
|   <script src='/resources/testharness.js'></script> | ||||
|   <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|   <div id="log"/> | ||||
|   <script> | ||||
|     async_test(function(t) { | ||||
|       document.addEventListener("securitypolicyviolation", t.unreached_func("Loading allowed fonts should not trigger a violation.")); | ||||
|       var link = document.createElement('link'); | ||||
|       link.rel="preload"; | ||||
|       link.as="font"; | ||||
|       link.href="/content-security-policy/support/Ahem.ttf"; | ||||
|       link.onload = t.step_func_done(); | ||||
|       link.onerror = t.unreached_func("Should have loaded the font."); | ||||
|       document.getElementsByTagName('head')[0].appendChild(link); | ||||
|     }, "Test font loads if it matches font-src."); | ||||
|   </script> | ||||
| </body> | ||||
|  | @ -0,0 +1,25 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <meta http-equiv="Content-Security-Policy" content="font-src 'none'"> | ||||
| <head> | ||||
|   <title>Test font does not load if it does not match font-src.</title> | ||||
|   <script src='/resources/testharness.js'></script> | ||||
|   <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|   <div id="log"/> | ||||
|   <script> | ||||
|     async_test(function(t) { | ||||
|       var link = document.createElement('link'); | ||||
|       link.rel="stylesheet"; | ||||
|       link.type="text/css"; | ||||
|       link.href="/content-security-policy/support/fonts.css"; | ||||
|       // The stylesheet should stil load, even though the font contained does not | ||||
|       link.onerror = t.unreached_func("Should have loaded the stylesheet."); | ||||
|       document.addEventListener("securitypolicyviolation", t.step_func_done(function(e) { | ||||
|         assert_equals(e.violatedDirective, "font-src"); | ||||
|       })); | ||||
|       document.getElementsByTagName('head')[0].appendChild(link); | ||||
|     }, "Test font does not load if it does not match font-src."); | ||||
|   </script> | ||||
| </body> | ||||
|  | @ -1,6 +0,0 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <title>csp font-src: whitelisted</title> | ||||
| <link href="fonts.css" rel="stylesheet" type="text/css"> | ||||
|           | ||||
| <p>The test passes if the line above shows the same glyphs in the reference.</p> | ||||
|  | @ -1,9 +0,0 @@ | |||
| <!doctype html> | ||||
| <meta charset=utf-8> | ||||
| <meta http-equiv="Content-Security-Policy" content="font-src 'self'"> | ||||
| <title>csp font-src: whitelisted</title> | ||||
| <link rel="match" href="font-whitelisted-ref.html"> | ||||
| <link rel="help" href="https://www.w3.org/TR/CSP2/#directive-font-src"> | ||||
| <link href="fonts.css" rel="stylesheet" type="text/css"> | ||||
|           | ||||
| <p>The test passes if the line above shows the same glyphs in the reference.</p> | ||||
|  | @ -1,8 +0,0 @@ | |||
| @font-face { | ||||
|   font-family: 'Halflings'; | ||||
|   src:  url('/tools/runner/fonts/glyphicons-halflings-regular.woff') format('woff'); | ||||
| } | ||||
| 
 | ||||
| body { | ||||
|     font-family: 'Halflings', Fallback, sans-serif; | ||||
| } | ||||
|  | @ -1,46 +0,0 @@ | |||
| <!DOCTYPE HTML> | ||||
| <html> | ||||
| <head> | ||||
|     <title>img element src attribute must match src list.</title> | ||||
|     <script src='/resources/testharness.js'></script> | ||||
|     <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|     <h1>img element src attribute must match src list.</h1> | ||||
|     <p> | ||||
|     <div id='log'></div> | ||||
| 
 | ||||
|     <script type="text/javascript"> | ||||
|       var t1 = async_test("img-src for relative path should load."); | ||||
|       var t2 = async_test("img-src from unapproved domains should not load"); | ||||
|       var t3 = async_test("img-src from approved domains should load"); | ||||
|     </script> | ||||
| 
 | ||||
|     <img src='/content-security-policy/support/pass.png' | ||||
|     onerror='t1.step(function() { assert_unreached("The img should have loaded."); t1.done() });' | ||||
|     onload='t1.done();'> | ||||
| 
 | ||||
|     <img src='http://www1.web-platform.test/content-security-policy/support/fail.png' | ||||
|     onerror='t2.done();' | ||||
|     onload='t2.step(function() { assert_unreached("Image from unapproved domain was loaded."); t2.done()} );'> | ||||
| 
 | ||||
|     <div id='t3'></div> | ||||
| 
 | ||||
|     <script> | ||||
|       var t3img = document.createElement('img'); | ||||
|       t3img.onerror = function() {t3.step(function() { assert_unreached(); t3.done();})} | ||||
|       t3img.onload = function() {t3.done();} | ||||
|       t3img.src = location.protocol + '//www.' + location.hostname + ':' + location.port + | ||||
|            '/content-security-policy/support/pass.png'; | ||||
|       var t3div = document.getElementById('t3'); | ||||
|       t3div.appendChild(t3img); | ||||
| 
 | ||||
|       var report = document.createElement('script'); | ||||
|       report.src = '../support/checkReport.sub.js?reportField=violated-directive&reportValue=img-src%20%27self%27%20www.' + location.hostname + (location.port ? ':' + location.port : ''); | ||||
|       t3div.appendChild(report); | ||||
| 
 | ||||
|     </script> | ||||
| 
 | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
|  | @ -1,6 +0,0 @@ | |||
| Expires: Mon, 26 Jul 1997 05:00:00 GMT | ||||
| Cache-Control: no-store, no-cache, must-revalidate | ||||
| Cache-Control: post-check=0, pre-check=0, false | ||||
| Pragma: no-cache | ||||
| Set-Cookie: img-src-4_1={{$id:uuid()}}; Path=/content-security-policy/img-src/ | ||||
| Content-Security-Policy: img-src 'self' www.{{host}}:{{ports[http][0]}};  report-uri  ../support/report.py?op=put&reportID={{$id}} | ||||
|  | @ -0,0 +1,35 @@ | |||
| <!DOCTYPE HTML> | ||||
| <meta http-equiv="Content-Security-Policy" content="img-src 'self' {{domains[www]}}:{{ports[http][0]}}"> | ||||
| <html> | ||||
| <head> | ||||
|     <title>img element src attribute must match src list.</title> | ||||
|     <script src='/resources/testharness.js'></script> | ||||
|     <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|     <div id='log'/> | ||||
| 
 | ||||
|     <script> | ||||
|       async_test(function(t) { | ||||
|         i = new Image(); | ||||
|         i.onload = t.step_func_done(); | ||||
|         i.onerror = t.unreached_func("The img should have loaded"); | ||||
|         i.src = '/content-security-policy/support/pass.png'; | ||||
|       }, "img-src for relative path should load"); | ||||
| 
 | ||||
|       async_test(function(t) { | ||||
|         i = new Image(); | ||||
|         i.onload = t.unreached_func("Image from unapproved domain was loaded."); | ||||
|         i.onerror = t.step_func_done(); | ||||
|         i.src = 'http://{{domains[www1]}}/content-security-policy/support/fail.png'; | ||||
|       }, "img-src from unapproved domains should not load"); | ||||
| 
 | ||||
|       async_test(function(t) { | ||||
|         i = new Image(); | ||||
|         i.onload = t.step_func_done(); | ||||
|         i.onerror = t.unreached_func("The img should have loaded"); | ||||
|         i.src = location.protocol + '//{{domains[www]}}:{{ports[http][0]}}/content-security-policy/support/pass.png'; | ||||
|       }, "img-src from approved domains should load"); | ||||
|     </script> | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,20 @@ | |||
| <!DOCTYPE html> | ||||
| <meta http-equiv="Content-Security-Policy" content="img-src *.{{host}}:{{ports[http][0]}}"> | ||||
| <html> | ||||
| <head> | ||||
|     <title>img-src with full host and wildcard blocks correctly.</title> | ||||
|     <script src='/resources/testharness.js'></script> | ||||
|     <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|     <div id='log'/> | ||||
| 
 | ||||
|     <script> | ||||
|       var t1 = async_test("img src does not match full host and wildcard csp directive"); | ||||
|     </script> | ||||
|     <img src='http://{{host}}:{{ports[http][0]}}/content-security-policy/support/fail.png' | ||||
|          onload='t1.step(function() { assert_unreached("Image should have loaded"); t1.done(); });' | ||||
|          onerror='t1.done();'> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,20 @@ | |||
| <!DOCTYPE html> | ||||
| <meta http-equiv="Content-Security-Policy" content="img-src *.{{host}}:{{ports[http][0]}}"> | ||||
| <html> | ||||
| <head> | ||||
|     <title>img-src works correctly with partial host wildcard.</title> | ||||
|     <script src='/resources/testharness.js'></script> | ||||
|     <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|     <div id='log'/> | ||||
| 
 | ||||
|     <script> | ||||
|       var t1 = async_test("img src matches correctly partial wildcard host csp directive"); | ||||
|     </script> | ||||
|     <img src='http://{{domains[www]}}:{{ports[http][0]}}/content-security-policy/support/pass.png' | ||||
|          onload='t1.done();' | ||||
|          onerror='t1.step(function() { assert_unreached("Image should have loaded"); t1.done(); });'> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,20 @@ | |||
| <!DOCTYPE html> | ||||
| <meta http-equiv="Content-Security-Policy" content="img-src 'none';"> | ||||
| <html> | ||||
| <head> | ||||
|     <title>img element src attribute must match src list.</title> | ||||
|     <script src='/resources/testharness.js'></script> | ||||
|     <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|     <div id='log'/> | ||||
| 
 | ||||
|     <script> | ||||
|       var t1 = async_test("img-src with 'none' source should not match"); | ||||
|     </script> | ||||
|     <img src='/content-security-policy/support/fail.png' | ||||
|          onload='t1.step(function() { assert_unreached("Image should not have loaded"); t1.done(); });' | ||||
|          onerror='t1.done();'> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,20 @@ | |||
| <!DOCTYPE HTML> | ||||
| <meta http-equiv="Content-Security-Policy" content="img-src http://www.{{host}}:*"> | ||||
| <html> | ||||
| <head> | ||||
|     <title>img-src works correctly with port wildcard source</title> | ||||
|     <script src='/resources/testharness.js'></script> | ||||
|     <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|     <div id='log'/> | ||||
| 
 | ||||
|     <script> | ||||
|       var t1 = async_test("img-src with wildcard port should match any port"); | ||||
|     </script> | ||||
|     <img src='http://{{domains[www]}}:{{ports[http][0]}}/content-security-policy/support/pass.png' | ||||
|          onload='t1.done();' | ||||
|          onerror='t1.step(function() { assert_unreached("Image should have loaded."); t1.done()} );'> | ||||
| 
 | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,40 @@ | |||
| <!DOCTYPE html> | ||||
| <meta http-equiv="Content-Security-Policy" content="img-src *;"> | ||||
| <html> | ||||
| <head> | ||||
|     <title>img element src attribute must match src list.</title> | ||||
|     <script src='/resources/testharness.js'></script> | ||||
|     <script src='/resources/testharnessreport.js'></script> | ||||
| </head> | ||||
| <body> | ||||
|     <div id='log'/> | ||||
| 
 | ||||
|     <script> | ||||
|       var t1 = async_test("img-src with wildcard should match all"); | ||||
|     </script> | ||||
|     <img src='/content-security-policy/support/pass.png' | ||||
|          onload='t1.done();' | ||||
|          onerror='t1.step(function() { assert_unreached("Image should have loaded"); t1.done(); });'> | ||||
| 
 | ||||
|     <script> | ||||
|       async_test(function(t) { | ||||
| 
 | ||||
|         var pngBase64 = "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAIAAAD/gAIDAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAnklEQVR42u3QMQEAAAgDoGlyo1vBzwciUJlw1ApkyZIlS5YsBbJkyZIlS5YCWbJkyZIlS4EsWbJkyZKlQJYsWbJkyVIgS5YsWbJkKZAlS5YsWbIUyJIlS5YsWQpkyZIlS5YsBbJkyZIlS5YCWbJkyZIlS4EsWbJkyZKlQJYsWbJkyVIgS5YsWbJkKZAlS5YsWbIUyJIlS5YsWQpkyfq2MosBSIeKONMAAAAASUVORK5CYII="; | ||||
| 
 | ||||
|         blobContents = [atob(pngBase64)]; | ||||
|         blob = new Blob(blobContents, {type: "image/png"}); | ||||
|         img = document.createElement("img"); | ||||
|         img.onerror = function (e) { | ||||
|           t.done(); | ||||
|         }; | ||||
|         img.onload = function () { | ||||
|           assert_unreached("Should not load blob img"); | ||||
|           t.done(); | ||||
|         }; | ||||
|         blobURL = window.URL.createObjectURL(blob); | ||||
|         img.src = blobURL; | ||||
| 
 | ||||
|       },"img-src with wildcard should not match blob"); | ||||
|     </script> | ||||
| </body> | ||||
| </html> | ||||
|  | @ -0,0 +1,44 @@ | |||
| <!DOCTYPE html> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| 
 | ||||
| <meta http-equiv="content-security-policy" content="connect-src 'self'"> | ||||
| <script> | ||||
|   // External URLs inherit policy. | ||||
|   fetch_tests_from_worker(new Worker("./support/connect-src-self.sub.js")); | ||||
|   fetch_tests_from_worker(new Worker("./support/connect-src-self.sub.js?pipe=sub|header(Content-Security-Policy,connect-src 'none')")); | ||||
|   fetch_tests_from_worker(new Worker("./support/connect-src-self.sub.js?pipe=sub|header(Content-Security-Policy,connect-src *)")); | ||||
|   fetch_tests_from_worker(new Worker("./support/connect-src-self.sub.js?pipe=sub|header(Content-Security-Policy,default-src 'none')")); | ||||
|   fetch_tests_from_worker(new Worker("./support/connect-src-self.sub.js?pipe=sub|header(Content-Security-Policy,default-src *)")); | ||||
| 
 | ||||
|   async_test(t => { | ||||
|     fetch("./support/connect-src-self.sub.js") | ||||
|       .then(r => r.blob()) | ||||
|       .then(b => { | ||||
|         // 'blob:' URLs inherit policy. | ||||
|         var u = URL.createObjectURL(b); | ||||
|         fetch_tests_from_worker(new Worker(u)); | ||||
| 
 | ||||
|         if (!window.webkitRequestFileSystem) | ||||
|           return t.done(); | ||||
| 
 | ||||
| 
 | ||||
|         // 'filesystem:' urls inherit policy. | ||||
|         window.webkitRequestFileSystem(window.TEMPORARY, 1024*1024, fs => { | ||||
|           fs.root.getFile('dedicated-inheritance-worker.js', { create: true }, entry => { | ||||
|             entry.createWriter(w => { | ||||
|               w.onwriteend = _ => { | ||||
|                 var u = entry.toURL(); | ||||
|                 fetch_tests_from_worker(new Worker(u)); | ||||
| 
 | ||||
|                 // explicit_done: yay. | ||||
|                 t.done(); | ||||
|               }; | ||||
|               w.onerror = _ => t.unreached_func(); | ||||
|               w.write(b); | ||||
|             }); | ||||
|           }); | ||||
|         }); | ||||
|     }); | ||||
|   }, "Filesystem and blob."); | ||||
| </script> | ||||
|  | @ -0,0 +1,44 @@ | |||
| <!DOCTYPE html> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| 
 | ||||
| <meta http-equiv="content-security-policy" content="script-src 'self' 'nonce-a' blob: filesystem:"> | ||||
| <script nonce="a"> | ||||
|   // External URLs inherit policy: the header delivered with the script resource is ignored. | ||||
|   fetch_tests_from_worker(new Worker("./support/script-src-self.sub.js")); | ||||
|   fetch_tests_from_worker(new Worker("./support/script-src-self.sub.js?pipe=sub|header(Content-Security-Policy,script-src 'none')")); | ||||
|   fetch_tests_from_worker(new Worker("./support/script-src-self.sub.js?pipe=sub|header(Content-Security-Policy,script-src *)")); | ||||
|   fetch_tests_from_worker(new Worker("./support/script-src-self.sub.js?pipe=sub|header(Content-Security-Policy,default-src 'none')")); | ||||
|   fetch_tests_from_worker(new Worker("./support/script-src-self.sub.js?pipe=sub|header(Content-Security-Policy,default-src *)")); | ||||
| 
 | ||||
|   async_test(t => { | ||||
|     fetch("./support/script-src-self.sub.js") | ||||
|       .then(r => r.blob()) | ||||
|       .then(b => { | ||||
|         // 'blob:' URLs inherit policy. | ||||
|         var u = URL.createObjectURL(b); | ||||
|         fetch_tests_from_worker(new Worker(u)); | ||||
| 
 | ||||
|         if (!window.webkitRequestFileSystem) | ||||
|           return t.done(); | ||||
| 
 | ||||
| 
 | ||||
|         // 'filesystem:' urls inherit policy. | ||||
|         window.webkitRequestFileSystem(window.TEMPORARY, 1024*1024, fs => { | ||||
|           fs.root.getFile('dedicated-script-worker.js', { create: true }, entry => { | ||||
|             entry.createWriter(w => { | ||||
|               w.onwriteend = _ => { | ||||
|                 var u = entry.toURL(); | ||||
|                 fetch_tests_from_worker(new Worker(u)); | ||||
| 
 | ||||
|                 // explicit_done: yay. | ||||
|                 t.done(); | ||||
|               }; | ||||
|               w.onerror = _ => t.unreached_func(); | ||||
|               w.write(b); | ||||
|             }); | ||||
|           }); | ||||
|         }); | ||||
|     }); | ||||
|   }, "Filesystem and blob."); | ||||
| </script> | ||||
|  | @ -0,0 +1,11 @@ | |||
| <!DOCTYPE html> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| 
 | ||||
| <meta http-equiv="content-security-policy" content="connect-src 'self'"> | ||||
| <script> | ||||
|   // SharedWorkers do not inherit policy. | ||||
|   fetch_tests_from_worker(new SharedWorker("./support/connect-src-allow.sub.js")); | ||||
|   fetch_tests_from_worker(new SharedWorker("./support/connect-src-self.sub.js?pipe=sub|header(Content-Security-Policy,connect-src 'self')")); | ||||
|   fetch_tests_from_worker(new SharedWorker("./support/connect-src-self.sub.js?pipe=sub|header(Content-Security-Policy,default-src 'self')")); | ||||
| </script> | ||||
|  | @ -0,0 +1,11 @@ | |||
| <!DOCTYPE html> | ||||
| <script src="/resources/testharness.js"></script> | ||||
| <script src="/resources/testharnessreport.js"></script> | ||||
| 
 | ||||
| <meta http-equiv="content-security-policy" content="script-src 'self' 'nonce-a' blob: filesystem:"> | ||||
| <script nonce="a"> | ||||
|   // SharedWorker URLs do not inherit policy. | ||||
|   fetch_tests_from_worker(new SharedWorker("./support/script-src-allow.sub.js")); | ||||
|   fetch_tests_from_worker(new SharedWorker("./support/script-src-self.sub.js?pipe=sub|header(Content-Security-Policy,script-src 'self'")); | ||||
|   fetch_tests_from_worker(new SharedWorker("./support/script-src-self.sub.js?pipe=sub|header(Content-Security-Policy,default-src 'self'")); | ||||
| </script> | ||||
|  | @ -0,0 +1,53 @@ | |||
| importScripts("{{location[server]}}/resources/testharness.js"); | ||||
| importScripts("{{location[server]}}/content-security-policy/support/testharness-helper.js"); | ||||
| 
 | ||||
| // Same-origin
 | ||||
| async_test(t => { | ||||
|   var url = "{{location[server]}}/content-security-policy/support/resource.py?same-origin-fetch"; | ||||
|   assert_no_csp_event_for_url(t, url); | ||||
| 
 | ||||
|   fetch(url) | ||||
|     .then(t.step_func_done(r => assert_equals(r.status, 200))); | ||||
| }, "Same-origin 'fetch()' in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| async_test(t => { | ||||
|   var url = "{{location[server]}}/content-security-policy/support/resource.py?same-origin-xhr"; | ||||
|   assert_no_csp_event_for_url(t, url); | ||||
| 
 | ||||
|   var xhr = new XMLHttpRequest(); | ||||
|   xhr.open("GET", url); | ||||
|   xhr.onload = t.step_func_done(); | ||||
|   xhr.onerror = t.unreached_func(); | ||||
|   xhr.send(); | ||||
| }, "Same-origin XHR in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| // Cross-origin
 | ||||
| async_test(t => { | ||||
|   var url = "http://{{domains[www]}}:{{ports[http][1]}}/content-security-policy/support/resource.py?cross-origin-fetch"; | ||||
|   assert_no_csp_event_for_url(t, url); | ||||
| 
 | ||||
|   fetch(url) | ||||
|     .then(t.step_func_done(r => assert_equals(r.status, 200))); | ||||
| }, "Cross-origin 'fetch()' in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| async_test(t => { | ||||
|   var url = "http://{{domains[www]}}:{{ports[http][1]}}/content-security-policy/support/resource.py?cross-origin-xhr"; | ||||
|   assert_no_csp_event_for_url(t, url); | ||||
| 
 | ||||
|   var xhr = new XMLHttpRequest(); | ||||
|   xhr.open("GET", url); | ||||
|   xhr.onload = t.step_func_done(); | ||||
|   xhr.onerror = t.unreached_func(); | ||||
|   xhr.send(); | ||||
| }, "Cross-origin XHR in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| // Same-origin redirecting to cross-origin
 | ||||
| async_test(t => { | ||||
|   var url = "{{location[server]}}/common/redirect-opt-in.py?status=307&location=http://{{domains[www]}}:{{ports[http][1]}}/content-security-policy/support/resource.py?cross-origin-fetch"; | ||||
|   assert_no_csp_event_for_url(t, url); | ||||
| 
 | ||||
|   fetch(url) | ||||
|     .then(t.step_func_done(r => assert_equals(r.status, 200))); | ||||
| }, "Same-origin => cross-origin 'fetch()' in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| done(); | ||||
|  | @ -0,0 +1,59 @@ | |||
| importScripts("{{location[server]}}/resources/testharness.js"); | ||||
| importScripts("{{location[server]}}/content-security-policy/support/testharness-helper.js"); | ||||
| 
 | ||||
| // Same-origin
 | ||||
| async_test(t => { | ||||
|   var url = "{{location[server]}}/common/text-plain.txt?same-origin-fetch"; | ||||
|   assert_no_csp_event_for_url(t, url); | ||||
| 
 | ||||
|   fetch(url) | ||||
|     .then(t.step_func_done(r => assert_equals(r.status, 200))); | ||||
| }, "Same-origin 'fetch()' in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| async_test(t => { | ||||
|   var url = "{{location[server]}}/common/text-plain.txt?same-origin-xhr"; | ||||
|   assert_no_csp_event_for_url(t, url); | ||||
| 
 | ||||
|   var xhr = new XMLHttpRequest(); | ||||
|   xhr.open("GET", url); | ||||
|   xhr.onload = t.step_func_done(); | ||||
|   xhr.onerror = t.unreached_func(); | ||||
|   xhr.send(); | ||||
| }, "Same-origin XHR in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| // Cross-origin
 | ||||
| async_test(t => { | ||||
|   var url = "http://{{domains[www]}}:{{ports[http][1]}}/common/text-plain.txt?cross-origin-fetch"; | ||||
| 
 | ||||
|   Promise.all([ | ||||
|     // TODO(mkwst): A 'securitypolicyviolation' event should fire.
 | ||||
|     fetch(url) | ||||
|       .catch(t.step_func(e => assert_true(e instanceof TypeError))) | ||||
|   ]).then(t.step_func_done()); | ||||
| }, "Cross-origin 'fetch()' in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| async_test(t => { | ||||
|   var url = "http://{{domains[www]}}:{{ports[http][1]}}/common/text-plain.txt?cross-origin-xhr"; | ||||
| 
 | ||||
|   Promise.all([ | ||||
|     // TODO(mkwst): A 'securitypolicyviolation' event should fire.
 | ||||
|     new Promise((resolve, reject) => { | ||||
|       var xhr = new XMLHttpRequest(); | ||||
|       xhr.open("GET", url); | ||||
|       xhr.onload = t.step_func(_ => reject("xhr.open should have thrown.")); | ||||
|       xhr.onerror = t.step_func(resolve); | ||||
|       xhr.send(); | ||||
|     }) | ||||
|   ]).then(t.step_func_done()); | ||||
| }, "Cross-origin XHR in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| // Same-origin redirecting to cross-origin
 | ||||
| async_test(t => { | ||||
|   var url = "{{location[server]}}/common/redirect-opt-in.py?status=307&location=http://{{domains[www]}}:{{ports[http][1]}}/common/text-plain.txt?cross-origin-fetch"; | ||||
| 
 | ||||
|   // TODO(mkwst): A 'securitypolicyviolation' event should fire.
 | ||||
|   fetch(url) | ||||
|     .catch(t.step_func_done(e => assert_true(e instanceof TypeError))) | ||||
| }, "Same-origin => cross-origin 'fetch()' in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| done(); | ||||
|  | @ -0,0 +1,18 @@ | |||
| importScripts("{{location[server]}}/resources/testharness.js"); | ||||
| 
 | ||||
| test(t => { | ||||
|   importScripts("http://{{domains[www]}}:{{ports[http][1]}}/content-security-policy/support/testharness-helper.js"); | ||||
| }, "Cross-origin `importScripts()` not blocked in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| test(t => { | ||||
|   assert_equals(2, eval("1+1")); | ||||
|   assert_equals(2, (new Function("return 1+1;"))()); | ||||
| }, "`eval()` not blocked in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| async_test(t => { | ||||
|   self.callback = t.step_func_done(); | ||||
| 
 | ||||
|   setTimeout("self.callback();", 1); | ||||
| }, "`setTimeout([string])` not blocked in " + self.location.protocol + self.location.search); | ||||
| 
 | ||||
| done(); | ||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
		Reference in a new issue
	
	 James Graham
						James Graham