- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / test / data / extensions / platform_apps / web_view / shim / main.js
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 var util = {};
6 var embedder = {};
7 embedder.baseGuestURL = '';
8 embedder.emptyGuestURL = '';
9 embedder.windowOpenGuestURL = '';
10 embedder.noReferrerGuestURL = '';
11 embedder.redirectGuestURL = '';
12 embedder.redirectGuestURLDest = '';
13 embedder.closeSocketURL = '';
14 embedder.tests = {};
15
16 embedder.setUp_ = function(config) {
17   embedder.baseGuestURL = 'http://localhost:' + config.testServer.port;
18   embedder.emptyGuestURL = embedder.baseGuestURL +
19       '/extensions/platform_apps/web_view/shim/empty_guest.html';
20   embedder.windowOpenGuestURL = embedder.baseGuestURL +
21       '/extensions/platform_apps/web_view/shim/guest.html';
22   embedder.noReferrerGuestURL = embedder.baseGuestURL +
23       '/extensions/platform_apps/web_view/shim/guest_noreferrer.html';
24   embedder.redirectGuestURL = embedder.baseGuestURL + '/server-redirect';
25   embedder.redirectGuestURLDest = embedder.baseGuestURL +
26       '/extensions/platform_apps/web_view/shim/guest_redirect.html';
27   embedder.closeSocketURL = embedder.baseGuestURL + '/close-socket';
28 };
29
30 window.runTest = function(testName) {
31   if (!embedder.test.testList[testName]) {
32     console.log('Incorrect testName: ' + testName);
33     embedder.test.fail();
34     return;
35   }
36
37   // Run the test.
38   embedder.test.testList[testName]();
39 };
40
41 // Creates a <webview> tag in document.body and returns the reference to it.
42 // It also sets a dummy src. The dummy src is significant because this makes
43 // sure that the <object> shim is created (asynchronously at this point) for the
44 // <webview> tag. This makes the <webview> tag ready for add/removeEventListener
45 // calls.
46 util.createWebViewTagInDOM = function(partitionName) {
47   var webview = document.createElement('webview');
48   webview.style.width = '300px';
49   webview.style.height = '200px';
50   var urlDummy = 'data:text/html,<body>Initial dummy guest</body>';
51   webview.setAttribute('src', urlDummy);
52   webview.setAttribute('partition', partitionName);
53   document.body.appendChild(webview);
54   return webview;
55 };
56
57 embedder.test = {};
58 embedder.test.succeed = function() {
59   chrome.test.sendMessage('DoneShimTest.PASSED');
60 };
61
62 embedder.test.fail = function() {
63   chrome.test.sendMessage('DoneShimTest.FAILED');
64 };
65
66 embedder.test.assertEq = function(a, b) {
67   if (a != b) {
68     console.log('assertion failed: ' + a + ' != ' + b);
69     embedder.test.fail();
70   }
71 };
72
73 embedder.test.assertTrue = function(condition) {
74   if (!condition) {
75     console.log('assertion failed: true != ' + condition);
76     embedder.test.fail();
77   }
78 };
79
80 embedder.test.assertFalse = function(condition) {
81   if (condition) {
82     console.log('assertion failed: false != ' + condition);
83     embedder.test.fail();
84   }
85 };
86
87 // Tests begin.
88
89 // This test verifies that if a browser plugin is in autosize mode before
90 // navigation then the guest starts auto-sized.
91 function testAutosizeBeforeNavigation() {
92   var webview = document.createElement('webview');
93
94   webview.setAttribute('autosize', 'true');
95   webview.setAttribute('minwidth', 200);
96   webview.setAttribute('maxwidth', 210);
97   webview.setAttribute('minheight', 100);
98   webview.setAttribute('maxheight', 110);
99
100   webview.addEventListener('sizechanged', function(e) {
101     embedder.test.assertEq(0, e.oldWidth);
102     embedder.test.assertEq(0, e.oldHeight);
103     embedder.test.assertTrue(e.newWidth >= 200 && e.newWidth <= 210);
104     embedder.test.assertTrue(e.newHeight >= 100 && e.newHeight <= 110);
105     embedder.test.succeed();
106   });
107
108   webview.setAttribute('src', 'data:text/html,webview test sizechanged event');
109   document.body.appendChild(webview);
110 }
111
112 // Makes sure 'sizechanged' event is fired only if autosize attribute is
113 // specified.
114 // After loading <webview> without autosize attribute and a size, say size1,
115 // we set autosize attribute and new min size with size2. We would get (only
116 // one) sizechanged event with size1 as old size and size2 as new size.
117 function testAutosizeAfterNavigation() {
118   var webview = document.createElement('webview');
119
120   var step = 1;
121   var sizeChangeHandler = function(e) {
122     switch (step) {
123       case 1:
124         // This would be triggered after we set autosize attribute.
125         embedder.test.assertEq(50, e.oldWidth);
126         embedder.test.assertEq(100, e.oldHeight);
127         embedder.test.assertTrue(e.newWidth >= 60 && e.newWidth <= 70);
128         embedder.test.assertTrue(e.newHeight >= 110 && e.newHeight <= 120);
129
130         // Remove autosize attribute and expect webview to return to its
131         // original size.
132         webview.removeAttribute('autosize');
133         break;
134       case 2:
135         // Expect 50x100.
136         embedder.test.assertEq(50, e.newWidth);
137         embedder.test.assertEq(100, e.newHeight);
138
139         embedder.test.succeed();
140         break;
141       default:
142         window.console.log('Unexpected sizechanged event, step = ' + step);
143         embedder.test.fail();
144         break;
145     }
146
147     ++step;
148   };
149
150   webview.addEventListener('sizechanged', sizeChangeHandler);
151
152   webview.addEventListener('loadstop', function(e) {
153     webview.setAttribute('autosize', true);
154     webview.setAttribute('minwidth', 60);
155     webview.setAttribute('maxwidth', 70);
156     webview.setAttribute('minheight', 110);
157     webview.setAttribute('maxheight', 120);
158   });
159
160   webview.style.width = '50px';
161   webview.style.height = '100px';
162   webview.setAttribute('src', 'data:text/html,webview test sizechanged event');
163   document.body.appendChild(webview);
164 }
165
166 // This test verifies that autosize works when some of the parameters are unset.
167 function testAutosizeWithPartialAttributes() {
168   window.console.log('testAutosizeWithPartialAttributes');
169   var webview = document.createElement('webview');
170
171   var step = 1;
172   var sizeChangeHandler = function(e) {
173     window.console.log('sizeChangeHandler, new: ' +
174                        e.newWidth + ' X ' + e.newHeight);
175     switch (step) {
176       case 1:
177         // Expect 300x200.
178         embedder.test.assertEq(300, e.newWidth);
179         embedder.test.assertEq(200, e.newHeight);
180
181         // Change the min size to cause a relayout.
182         webview.minwidth = 500;
183         break;
184       case 2:
185         embedder.test.assertTrue(e.newWidth >= webview.minwidth);
186         embedder.test.assertTrue(e.newWidth <= webview.maxwidth);
187
188         // Tests when minwidth > maxwidth, minwidth = maxwidth.
189         // i.e. minwidth is essentially 700.
190         webview.minwidth = 800;
191         break;
192       case 3:
193         // Expect 700X?
194         embedder.test.assertEq(700, e.newWidth);
195         embedder.test.assertTrue(e.newHeight >= 200);
196         embedder.test.assertTrue(e.newHeight <= 600);
197
198         embedder.test.succeed();
199         break;
200       default:
201         window.console.log('Unexpected sizechanged event, step = ' + step);
202         embedder.test.fail();
203         break;
204     }
205
206     ++step;
207   };
208
209   webview.addEventListener('sizechanged', sizeChangeHandler);
210
211   webview.addEventListener('loadstop', function(e) {
212     webview.minwidth = 300;
213     webview.maxwidth = 700;
214     webview.minheight = 200;
215     webview.maxheight = 600;
216     webview.autosize = true;
217   });
218
219   webview.style.width = '640px';
220   webview.style.height = '480px';
221   webview.setAttribute('src', 'data:text/html,webview check autosize');
222   document.body.appendChild(webview);
223 }
224
225 // This test verifies that all autosize attributes can be removed
226 // without crashing the plugin, or throwing errors.
227 function testAutosizeRemoveAttributes() {
228   var webview = document.createElement('webview');
229
230   var step = 1;
231   var sizeChangeHandler = function(e) {
232     switch (step) {
233       case 1:
234         // This is the sizechanged event for autosize.
235
236         // Remove attributes.
237         webview.removeAttribute('minwidth');
238         webview.removeAttribute('maxwidth');
239         webview.removeAttribute('minheight');
240         webview.removeAttribute('maxheight');
241         webview.removeAttribute('autosize');
242
243         // We'd get one more sizechanged event after we turn off
244         // autosize.
245         webview.style.width = '500px';
246         webview.style.height = '500px';
247         break;
248       case 2:
249         embedder.test.succeed();
250         break;
251     }
252
253     ++step;
254   };
255
256   webview.addEventListener('loadstop', function(e) {
257     webview.minwidth = 300;
258     webview.maxwidth = 700;
259     webview.minheight = 600;
260     webview.maxheight = 400;
261     webview.autosize = true;
262   });
263
264   webview.addEventListener('sizechanged', sizeChangeHandler);
265
266   webview.style.width = '640px';
267   webview.style.height = '480px';
268   webview.setAttribute('src', 'data:text/html,webview check autosize');
269   document.body.appendChild(webview);
270 }
271
272 function testAPIMethodExistence() {
273   var apiMethodsToCheck = [
274     'back',
275     'canGoBack',
276     'canGoForward',
277     'forward',
278     'getProcessId',
279     'go',
280     'reload',
281     'stop',
282     'terminate'
283   ];
284   var webview = document.createElement('webview');
285   webview.setAttribute('partition', arguments.callee.name);
286   webview.addEventListener('loadstop', function(e) {
287     for (var i = 0; i < apiMethodsToCheck.length; ++i) {
288       embedder.test.assertEq('function',
289                            typeof webview[apiMethodsToCheck[i]]);
290     }
291
292     // Check contentWindow.
293     embedder.test.assertEq('object', typeof webview.contentWindow);
294     embedder.test.assertEq('function',
295                          typeof webview.contentWindow.postMessage);
296     embedder.test.succeed();
297   });
298   webview.setAttribute('src', 'data:text/html,webview check api');
299   document.body.appendChild(webview);
300 }
301
302 // This test verifies that the loadstop event fires when loading a webview
303 // accessible resource from a partition that is privileged.
304 function testChromeExtensionURL() {
305   var localResource = chrome.runtime.getURL('guest.html');
306   var webview = document.createElement('webview');
307   // foobar is a privileged partition according to the manifest file.
308   webview.partition = 'foobar';
309   webview.addEventListener('loadabort', function(e) {
310     embedder.test.fail();
311   });
312   webview.addEventListener('loadstop', function(e) {
313     embedder.test.succeed();
314   });
315   webview.setAttribute('src', localResource);
316   document.body.appendChild(webview);
317 }
318
319 // This test verifies that the loadstop event fires when loading a webview
320 // accessible resource from a partition that is privileged if the src URL
321 // is not fully qualified.
322 function testChromeExtensionRelativePath() {
323   var webview = document.createElement('webview');
324   // foobar is a privileged partition according to the manifest file.
325   webview.partition = 'foobar';
326   webview.addEventListener('loadabort', function(e) {
327     embedder.test.fail();
328   });
329   webview.addEventListener('loadstop', function(e) {
330     embedder.test.succeed();
331   });
332   webview.setAttribute('src', 'guest.html');
333   document.body.appendChild(webview);
334 }
335
336 // This tests verifies that webview fires a loadabort event instead of crashing
337 // the browser if we attempt to navigate to a chrome-extension: URL with an
338 // extension ID that does not exist.
339 function testInvalidChromeExtensionURL() {
340   var invalidResource = 'chrome-extension://abc123/guest.html';
341   var webview = document.createElement('webview');
342   // foobar is a privileged partition according to the manifest file.
343   webview.partition = 'foobar';
344   webview.addEventListener('loadabort', function(e) {
345     embedder.test.succeed();
346   });
347   webview.setAttribute('src', invalidResource);
348   document.body.appendChild(webview);
349 }
350
351 function testWebRequestAPIExistence() {
352   var apiPropertiesToCheck = [
353     'onBeforeRequest',
354     'onBeforeSendHeaders',
355     'onSendHeaders',
356     'onHeadersReceived',
357     'onAuthRequired',
358     'onBeforeRedirect',
359     'onResponseStarted',
360     'onCompleted',
361     'onErrorOccurred'
362   ];
363   var webview = document.createElement('webview');
364   webview.setAttribute('partition', arguments.callee.name);
365   webview.addEventListener('loadstop', function(e) {
366     for (var i = 0; i < apiPropertiesToCheck.length; ++i) {
367       embedder.test.assertEq('object',
368                              typeof webview[apiPropertiesToCheck[i]]);
369       embedder.test.assertEq(
370           'function', typeof webview[apiPropertiesToCheck[i]].addListener);
371       embedder.test.assertEq(webview[apiPropertiesToCheck[i]],
372                              webview.request[apiPropertiesToCheck[i]]);
373     }
374
375     embedder.test.succeed();
376   });
377   webview.setAttribute('src', 'data:text/html,webview check api');
378   document.body.appendChild(webview);
379 }
380
381 // This test verifies that the loadstart, loadstop, and exit events fire as
382 // expected.
383 function testEventName() {
384   var webview = document.createElement('webview');
385   webview.setAttribute('partition', arguments.callee.name);
386
387   webview.addEventListener('loadstart', function(evt) {
388     embedder.test.assertEq('loadstart', evt.type);
389   });
390
391   webview.addEventListener('loadstop', function(evt) {
392     embedder.test.assertEq('loadstop', evt.type);
393     webview.terminate();
394   });
395
396   webview.addEventListener('exit', function(evt) {
397     embedder.test.assertEq('exit', evt.type);
398     embedder.test.succeed();
399   });
400
401   webview.setAttribute('src', 'data:text/html,trigger navigation');
402   document.body.appendChild(webview);
403 }
404
405 function testOnEventProperties() {
406   var sequence = ['first', 'second', 'third', 'fourth'];
407   var webview = document.createElement('webview');
408   function createHandler(id) {
409     return function(e) {
410       embedder.test.assertEq(id, sequence.shift());
411     };
412   }
413
414   webview.addEventListener('loadstart', createHandler('first'));
415   webview.addEventListener('loadstart', createHandler('second'));
416   webview.onloadstart = createHandler('third');
417   webview.addEventListener('loadstart', createHandler('fourth'));
418   webview.addEventListener('loadstop', function(evt) {
419     embedder.test.assertEq(0, sequence.length);
420
421     // Test that setting another 'onloadstart' handler replaces the previous
422     // handler.
423     sequence = ['first', 'second', 'fourth'];
424     webview.onloadstart = function() {
425       embedder.test.assertEq(0, sequence.length);
426       embedder.test.succeed();
427     };
428
429     webview.setAttribute('src', 'data:text/html,next navigation');
430   });
431
432   webview.setAttribute('src', 'data:text/html,trigger navigation');
433   document.body.appendChild(webview);
434 }
435
436 // Tests that the 'loadprogress' event is triggered correctly.
437 function testLoadProgressEvent() {
438   var webview = document.createElement('webview');
439   var progress = 0;
440
441   webview.addEventListener('loadstop', function(evt) {
442     embedder.test.assertEq(1, progress);
443     embedder.test.succeed();
444   });
445
446   webview.addEventListener('loadprogress', function(evt) {
447     progress = evt.progress;
448   });
449
450   webview.setAttribute('src', 'data:text/html,trigger navigation');
451   document.body.appendChild(webview);
452 }
453
454 // This test registers two listeners on an event (loadcommit) and removes
455 // the <webview> tag when the first listener fires.
456 // Current expected behavior is that the second event listener will still
457 // fire without crashing.
458 function testDestroyOnEventListener() {
459   var webview = util.createWebViewTagInDOM(arguments.callee.name);
460   var url = 'data:text/html,<body>Destroy test</body>';
461
462   var loadCommitCount = 0;
463   function loadCommitCommon(e) {
464     embedder.test.assertEq('loadcommit', e.type);
465     if (url != e.url)
466       return;
467     ++loadCommitCount;
468     if (loadCommitCount == 1) {
469       setTimeout(function() {
470         embedder.test.succeed();
471       }, 0);
472     } else if (loadCommitCount > 2) {
473       embedder.test.fail();
474     }
475   };
476
477   // The test starts from here, by setting the src to |url|.
478   webview.addEventListener('loadcommit', function(e) {
479     webview.parentNode.removeChild(webview);
480     loadCommitCommon(e);
481   });
482   webview.addEventListener('loadcommit', function(e) {
483     loadCommitCommon(e);
484   });
485   webview.setAttribute('src', url);
486 }
487
488 // This test registers two event listeners on a same event (loadcommit).
489 // Each of the listener tries to change some properties on the event param,
490 // which should not be possible.
491 function testCannotMutateEventName() {
492   var webview = util.createWebViewTagInDOM(arguments.callee.name);
493   var url = 'data:text/html,<body>Two</body>';
494
495   var loadCommitACalled = false;
496   var loadCommitBCalled = false;
497
498   var maybeFinishTest = function(e) {
499     if (loadCommitACalled && loadCommitBCalled) {
500       embedder.test.assertEq('loadcommit', e.type);
501       embedder.test.succeed();
502     }
503   };
504
505   var onLoadCommitA = function(e) {
506     if (e.url == url) {
507       embedder.test.assertEq('loadcommit', e.type);
508       embedder.test.assertTrue(e.isTopLevel);
509       embedder.test.assertFalse(loadCommitACalled);
510       loadCommitACalled = true;
511       // Try mucking with properities inside |e|.
512       e.type = 'modified';
513       maybeFinishTest(e);
514     }
515   };
516   var onLoadCommitB = function(e) {
517     if (e.url == url) {
518       embedder.test.assertEq('loadcommit', e.type);
519       embedder.test.assertTrue(e.isTopLevel);
520       embedder.test.assertFalse(loadCommitBCalled);
521       loadCommitBCalled = true;
522       // Try mucking with properities inside |e|.
523       e.type = 'modified';
524       maybeFinishTest(e);
525     }
526   };
527
528   // The test starts from here, by setting the src to |url|. Event
529   // listener registration works because we already have a (dummy) src set
530   // on the <webview> tag.
531   webview.addEventListener('loadcommit', onLoadCommitA);
532   webview.addEventListener('loadcommit', onLoadCommitB);
533   webview.setAttribute('src', url);
534 }
535
536 // This test verifies that setting the partition attribute after the src has
537 // been set raises an exception.
538 function testPartitionRaisesException() {
539   var webview = document.createElement('webview');
540   webview.setAttribute('partition', arguments.callee.name);
541   webview.setAttribute('src', 'data:text/html,trigger navigation');
542   document.body.appendChild(webview);
543   setTimeout(function() {
544     try {
545       webview.partition = 'illegal';
546       embedder.test.fail();
547     } catch (e) {
548       embedder.test.succeed();
549     }
550   }, 0);
551 }
552
553 function testExecuteScriptFail() {
554   var webview = document.createElement('webview');
555   document.body.appendChild(webview);
556   setTimeout(function() {
557     try {
558     webview.executeScript(
559       {code:'document.body.style.backgroundColor = "red";'},
560       function(results) {
561         embedder.test.fail();
562       });
563     } catch (e) {
564       embedder.test.succeed();
565     }
566   }, 0);
567 }
568
569 function testExecuteScript() {
570   var webview = document.createElement('webview');
571   webview.setAttribute('partition', arguments.callee.name);
572   webview.addEventListener('loadstop', function() {
573     webview.executeScript(
574       {code:'document.body.style.backgroundColor = "red";'},
575       function(results) {
576         embedder.test.assertEq(1, results.length);
577         embedder.test.assertEq('red', results[0]);
578         embedder.test.succeed();
579       });
580   });
581   webview.setAttribute('src', 'data:text/html,trigger navigation');
582   document.body.appendChild(webview);
583 }
584
585 // This test calls terminate() on guest after it has already been
586 // terminated. This makes sure we ignore the call gracefully.
587 function testTerminateAfterExit() {
588   var webview = document.createElement('webview');
589   webview.setAttribute('partition', arguments.callee.name);
590   var loadstopSucceedsTest = false;
591   webview.addEventListener('loadstop', function(evt) {
592     embedder.test.assertEq('loadstop', evt.type);
593     if (loadstopSucceedsTest) {
594       embedder.test.succeed();
595       return;
596     }
597
598     webview.terminate();
599   });
600
601   webview.addEventListener('exit', function(evt) {
602     embedder.test.assertEq('exit', evt.type);
603     // Call terminate again.
604     webview.terminate();
605     // Load another page. The test would pass when loadstop is called on
606     // this second page. This would hopefully catch if call to
607     // webview.terminate() caused a browser crash.
608     setTimeout(function() {
609       loadstopSucceedsTest = true;
610       webview.setAttribute('src', 'data:text/html,test second page');
611     }, 0);
612   });
613
614   webview.setAttribute('src', 'data:text/html,test terminate() crash.');
615   document.body.appendChild(webview);
616 }
617
618 // This test verifies that multiple consecutive changes to the <webview> src
619 // attribute will cause a navigation.
620 function testNavOnConsecutiveSrcAttributeChanges() {
621   var testPage1 = 'data:text/html,test page 1';
622   var testPage2 = 'data:text/html,test page 2';
623   var testPage3 = 'data:text/html,test page 3';
624   var webview = new WebView();
625   webview.partition = arguments.callee.name;
626   var loadCommitCount = 0;
627   webview.addEventListener('loadcommit', function(e) {
628     if (e.url == testPage3) {
629       embedder.test.succeed();
630     }
631     loadCommitCount++;
632     if (loadCommitCount > 3) {
633       embedder.test.fail();
634     }
635   });
636   document.body.appendChild(webview);
637   webview.src = testPage1;
638   webview.src = testPage2;
639   webview.src = testPage3;
640 }
641
642 // This test verifies that we can set the <webview> src multiple times and the
643 // changes will cause a navigation.
644 function testNavOnSrcAttributeChange() {
645   var testPage1 = 'data:text/html,test page 1';
646   var testPage2 = 'data:text/html,test page 2';
647   var testPage3 = 'data:text/html,test page 3';
648   var tests = [testPage1, testPage2, testPage3];
649   var webview = new WebView();
650   webview.partition = arguments.callee.name;
651   var loadCommitCount = 0;
652   webview.addEventListener('loadcommit', function(evt) {
653     var success = tests.indexOf(evt.url) > -1;
654     embedder.test.assertTrue(success);
655     ++loadCommitCount;
656     if (loadCommitCount == tests.length) {
657       embedder.test.succeed();
658     } else if (loadCommitCount > tests.length) {
659       embedder.test.fail();
660     } else {
661       webview.src = tests[loadCommitCount];
662     }
663   });
664   webview.src = tests[0];
665   document.body.appendChild(webview);
666 }
667
668 // This test verifies that assigning the src attribute the same value it had
669 // prior to a crash spawns off a new guest process.
670 function testAssignSrcAfterCrash() {
671   var webview = document.createElement('webview');
672   webview.setAttribute('partition', arguments.callee.name);
673   var terminated = false;
674   webview.addEventListener('loadstop', function(evt) {
675     if (!terminated) {
676       webview.terminate();
677       return;
678     }
679     // The guest has recovered after being terminated.
680     embedder.test.succeed();
681   });
682   webview.addEventListener('exit', function(evt) {
683     terminated = true;
684     webview.setAttribute('src', 'data:text/html,test page');
685   });
686   webview.setAttribute('src', 'data:text/html,test page');
687   document.body.appendChild(webview);
688 }
689
690 // This test verifies that <webview> reloads the page if the src attribute is
691 // assigned the same value.
692 function testReassignSrcAttribute() {
693   var dataUrl = 'data:text/html,test page';
694   var webview = new WebView();
695   webview.partition = arguments.callee.name;
696
697   var loadStopCount = 0;
698   webview.addEventListener('loadstop', function(evt) {
699     embedder.test.assertEq(dataUrl, webview.getAttribute('src'));
700     ++loadStopCount;
701     console.log('[' + loadStopCount + '] loadstop called');
702     if (loadStopCount == 3) {
703       embedder.test.succeed();
704     } else if (loadStopCount > 3) {
705       embedder.test.fail();
706     } else {
707       webview.src = dataUrl;
708     }
709   });
710   webview.src = dataUrl;
711   document.body.appendChild(webview);
712 }
713
714 // This test verifies that <webview> restores the src attribute if it is
715 // removed after navigation.
716 function testRemoveSrcAttribute() {
717   var dataUrl = 'data:text/html,test page';
718   var webview = document.createElement('webview');
719   webview.setAttribute('partition', arguments.callee.name);
720   var terminated = false;
721   webview.addEventListener('loadstop', function(evt) {
722     webview.removeAttribute('src');
723     setTimeout(function() {
724       embedder.test.assertEq(dataUrl, webview.getAttribute('src'));
725       embedder.test.succeed();
726     }, 0);
727   });
728   webview.setAttribute('src', dataUrl);
729   document.body.appendChild(webview);
730 }
731
732 // This test verifies that it is not possible to instantiate a browser plugin
733 // directly within an app.
734 function testBrowserPluginNotAllowed() {
735   var container = document.getElementById('object-container');
736   if (!container) {
737     embedder.test.fail('Container for object not found.');
738     return;
739   }
740   container.innerHTML = '<object type="application/browser-plugin"' +
741       ' id="object-plugin"' +
742       ' src="data:text/html,<body>You should not see this</body>">' +
743       '</object>';
744   var objectElement = document.getElementById('object-plugin');
745   // Check that bindings are not registered.
746   embedder.test.assertTrue(
747       objectElement['-internal-attach'] === undefined);
748   embedder.test.succeed();
749 }
750
751 function testPluginLoadPermission() {
752   var pluginIdentifier = 'unknown platform';
753   if (navigator.platform.match(/linux/i))
754     pluginIdentifier = 'libppapi_tests.so';
755   else if (navigator.platform.match(/win32/i))
756     pluginIdentifier = 'ppapi_tests.dll';
757   else if (navigator.platform.match(/mac/i))
758     pluginIdentifier = 'ppapi_tests.plugin';
759
760   var webview = document.createElement('webview');
761   webview.addEventListener('permissionrequest', function(e) {
762     e.preventDefault();
763     embedder.test.assertEq('loadplugin', e.permission);
764     embedder.test.assertEq(pluginIdentifier, e.name);
765     embedder.test.assertEq(pluginIdentifier, e.identifier);
766     embedder.test.assertEq('function', typeof e.request.allow);
767     embedder.test.assertEq('function', typeof e.request.deny);
768     embedder.test.succeed();
769   });
770   webview.setAttribute('src', 'data:text/html,<body>' +
771                               '<embed type="application/x-ppapi-tests">' +
772                               '</embed></body>');
773   document.body.appendChild(webview);
774 }
775
776 // This test verifies that new window attachment functions as expected.
777 function testNewWindow() {
778   var webview = document.createElement('webview');
779   webview.addEventListener('newwindow', function(e) {
780     e.preventDefault();
781     var newwebview = document.createElement('webview');
782     newwebview.addEventListener('loadstop', function(evt) {
783       // If the new window finishes loading, the test is successful.
784       embedder.test.succeed();
785     });
786     document.body.appendChild(newwebview);
787     // Attach the new window to the new <webview>.
788     e.window.attach(newwebview);
789   });
790   webview.setAttribute('src', embedder.windowOpenGuestURL);
791   document.body.appendChild(webview);
792 }
793
794 // This test verifies "first-call-wins" semantics. That is, the first call
795 // to perform an action on the new window takes the action and all
796 // subsequent calls throw an exception.
797 function testNewWindowTwoListeners() {
798   var webview = document.createElement('webview');
799   var error = false;
800   webview.addEventListener('newwindow', function(e) {
801     e.preventDefault();
802     var newwebview = document.createElement('webview');
803     document.body.appendChild(newwebview);
804     try {
805       e.window.attach(newwebview);
806     } catch (err) {
807       embedder.test.fail();
808     }
809   });
810   webview.addEventListener('newwindow', function(e) {
811     e.preventDefault();
812     try {
813       e.window.discard();
814     } catch (err) {
815       embedder.test.succeed();
816     }
817   });
818   webview.setAttribute('src', embedder.windowOpenGuestURL);
819   document.body.appendChild(webview);
820 }
821
822 // This test verifies that the attach can be called inline without
823 // preventing default.
824 function testNewWindowNoPreventDefault() {
825   var webview = document.createElement('webview');
826   webview.addEventListener('newwindow', function(e) {
827     var newwebview = document.createElement('webview');
828     document.body.appendChild(newwebview);
829     // Attach the new window to the new <webview>.
830     try {
831       e.window.attach(newwebview);
832       embedder.test.succeed();
833     } catch (err) {
834       embedder.test.fail();
835     }
836   });
837   webview.setAttribute('src', embedder.windowOpenGuestURL);
838   document.body.appendChild(webview);
839 }
840
841 function testNewWindowNoReferrerLink() {
842   var webview = document.createElement('webview');
843   webview.addEventListener('newwindow', function(e) {
844     e.preventDefault();
845     var newwebview = document.createElement('webview');
846     newwebview.addEventListener('loadstop', function(evt) {
847       // If the new window finishes loading, the test is successful.
848       embedder.test.succeed();
849     });
850     document.body.appendChild(newwebview);
851     // Attach the new window to the new <webview>.
852     e.window.attach(newwebview);
853   });
854   webview.setAttribute('src', embedder.noReferrerGuestURL);
855   document.body.appendChild(webview);
856 }
857
858 // This test verifies that the load event fires when the a new page is
859 // loaded.
860 // TODO(fsamuel): Add a test to verify that subframe loads within a guest
861 // do not fire the 'contentload' event.
862 function testContentLoadEvent() {
863   var webview = document.createElement('webview');
864   webview.addEventListener('contentload', function(e) {
865     embedder.test.succeed();
866   });
867   webview.setAttribute('src', 'data:text/html,trigger navigation');
868   document.body.appendChild(webview);
869 }
870
871 // This test verifies that the WebRequest API onBeforeRequest event fires on
872 // webview.
873 function testWebRequestAPI() {
874   var webview = new WebView();
875   webview.request.onBeforeRequest.addListener(function(e) {
876     embedder.test.succeed();
877   }, { urls: ['<all_urls>']}) ;
878   webview.src = embedder.windowOpenGuestURL;
879   document.body.appendChild(webview);
880 }
881
882 // This test verifies that the WebRequest API onBeforeRequest event fires on
883 // clients*.google.com URLs.
884 function testWebRequestAPIGoogleProperty() {
885   var webview = new WebView();
886   webview.request.onBeforeRequest.addListener(function(e) {
887     embedder.test.succeed();
888     return {cancel: true};
889   }, { urls: ['<all_urls>']}, ['blocking']) ;
890   webview.src = 'http://clients6.google.com';
891   document.body.appendChild(webview);
892 }
893
894 // This test verifies that the WebRequest event listener for onBeforeRequest
895 // survives reparenting of the <webview>.
896 function testWebRequestListenerSurvivesReparenting() {
897   var webview = new WebView();
898   var count = 0;
899   webview.request.onBeforeRequest.addListener(function(e) {
900     if (++count == 2) {
901       embedder.test.succeed();
902     }
903   }, { urls: ['<all_urls>']});
904   var onLoadStop =  function(e) {
905     webview.removeEventListener('loadstop', onLoadStop);
906     webview.parentNode.removeChild(webview);
907     var container = document.getElementById('object-container');
908     if (!container) {
909       embedder.test.fail('Container for object not found.');
910       return;
911     }
912     container.appendChild(webview);
913   };
914   webview.addEventListener('loadstop', onLoadStop);
915   webview.src = embedder.emptyGuestURL;
916   document.body.appendChild(webview);
917 }
918
919 // This test verifies that getProcessId is defined and returns a non-zero
920 // value corresponding to the processId of the guest process.
921 function testGetProcessId() {
922   var webview = document.createElement('webview');
923   webview.setAttribute('src', 'data:text/html,trigger navigation');
924   var firstLoad = function() {
925     webview.removeEventListener('loadstop', firstLoad);
926     embedder.test.assertTrue(webview.getProcessId() > 0);
927     embedder.test.succeed();
928   };
929   webview.addEventListener('loadstop', firstLoad);
930   document.body.appendChild(webview);
931 }
932
933 // This test verifies that the loadstart event fires at the beginning of a load
934 // and the loadredirect event fires when a redirect occurs.
935 function testLoadStartLoadRedirect() {
936   var webview = document.createElement('webview');
937   var loadstartCalled = false;
938   webview.setAttribute('src', embedder.redirectGuestURL);
939   webview.addEventListener('loadstart', function(e) {
940     embedder.test.assertTrue(e.isTopLevel);
941     embedder.test.assertEq(embedder.redirectGuestURL, e.url);
942     loadstartCalled = true;
943   });
944   webview.addEventListener('loadredirect', function(e) {
945     embedder.test.assertTrue(e.isTopLevel);
946     embedder.test.assertEq(embedder.redirectGuestURL,
947         e.oldUrl.replace('127.0.0.1', 'localhost'));
948     embedder.test.assertEq(embedder.redirectGuestURLDest,
949         e.newUrl.replace('127.0.0.1', 'localhost'));
950     if (loadstartCalled) {
951       embedder.test.succeed();
952     } else {
953       embedder.test.fail();
954     }
955   });
956   document.body.appendChild(webview);
957 }
958
959 // This test verifies that the loadabort event fires when loading a webview
960 // accessible resource from a partition that is not privileged.
961 function testLoadAbortChromeExtensionURLWrongPartition() {
962   var localResource = chrome.runtime.getURL('guest.html');
963   var webview = document.createElement('webview');
964   webview.addEventListener('loadabort', function(e) {
965     embedder.test.assertEq('ERR_ADDRESS_UNREACHABLE', e.reason);
966     embedder.test.succeed();
967   });
968   webview.addEventListener('loadstop', function(e) {
969     embedder.test.fail();
970   });
971   webview.setAttribute('src', localResource);
972   document.body.appendChild(webview);
973 }
974
975 // This test verifies that the loadabort event fires as expected and with the
976 // appropriate fields when an empty response is returned.
977 function testLoadAbortEmptyResponse() {
978   var webview = document.createElement('webview');
979   webview.addEventListener('loadabort', function(e) {
980     embedder.test.assertEq('ERR_EMPTY_RESPONSE', e.reason);
981     embedder.test.succeed();
982   });
983   webview.setAttribute('src', embedder.closeSocketURL);
984   document.body.appendChild(webview);
985 }
986
987 // This test verifies that the loadabort event fires as expected when an illegal
988 // chrome URL is provided.
989 function testLoadAbortIllegalChromeURL() {
990   var webview = document.createElement('webview');
991   var onFirstLoadStop = function(e) {
992     webview.removeEventListener('loadstop', onFirstLoadStop);
993     webview.setAttribute('src', 'chrome://newtab');
994   };
995   webview.addEventListener('loadstop', onFirstLoadStop);
996   webview.addEventListener('loadabort', function(e) {
997     embedder.test.assertEq('ERR_ABORTED', e.reason);
998     embedder.test.succeed();
999   });
1000   webview.setAttribute('src', 'about:blank');
1001   document.body.appendChild(webview);
1002 }
1003
1004 function testLoadAbortIllegalFileURL() {
1005   var webview = document.createElement('webview');
1006   webview.addEventListener('loadabort', function(e) {
1007     embedder.test.assertEq('ERR_ABORTED', e.reason);
1008     embedder.test.succeed();
1009   });
1010   webview.setAttribute('src', 'file://foo');
1011   document.body.appendChild(webview);
1012 }
1013
1014 function testLoadAbortIllegalJavaScriptURL() {
1015   var webview = document.createElement('webview');
1016   webview.addEventListener('loadabort', function(e) {
1017     embedder.test.assertEq('ERR_ABORTED', e.reason);
1018     embedder.test.succeed();
1019   });
1020   webview.setAttribute('src', 'javascript:void(document.bgColor="#0000FF")');
1021   document.body.appendChild(webview);
1022 }
1023
1024 // This test verifies that the reload method on webview functions as expected.
1025 function testReload() {
1026   var triggerNavUrl = 'data:text/html,trigger navigation';
1027   var webview = document.createElement('webview');
1028
1029   var loadCommitCount = 0;
1030   webview.addEventListener('loadstop', function(e) {
1031     if (loadCommitCount < 2) {
1032       webview.reload();
1033     } else if (loadCommitCount == 2) {
1034       embedder.test.succeed();
1035     } else {
1036       embedder.test.fail();
1037     }
1038   });
1039   webview.addEventListener('loadcommit', function(e) {
1040     embedder.test.assertEq(triggerNavUrl, e.url);
1041     embedder.test.assertTrue(e.isTopLevel);
1042     loadCommitCount++;
1043   });
1044
1045   webview.setAttribute('src', triggerNavUrl);
1046   document.body.appendChild(webview);
1047 }
1048
1049 // This test verifies that a <webview> is torn down gracefully when removed from
1050 // the DOM on exit.
1051
1052 window.removeWebviewOnExitDoCrash = null;
1053
1054 function testRemoveWebviewOnExit() {
1055   var triggerNavUrl = 'data:text/html,trigger navigation';
1056   var webview = document.createElement('webview');
1057
1058   webview.addEventListener('loadstop', function(e) {
1059     chrome.test.sendMessage('guest-loaded');
1060   });
1061
1062   window.removeWebviewOnExitDoCrash = function() {
1063     webview.terminate();
1064   };
1065
1066   webview.addEventListener('exit', function(e) {
1067     // We expected to be killed.
1068     if (e.reason != 'killed') {
1069       console.log('EXPECTED TO BE KILLED!');
1070       return;
1071     }
1072     webview.parentNode.removeChild(webview);
1073   });
1074
1075   // Trigger a navigation to create a guest process.
1076   webview.setAttribute('src', embedder.emptyGuestURL);
1077   document.body.appendChild(webview);
1078 }
1079
1080 function testRemoveWebviewAfterNavigation() {
1081   var webview = new WebView();
1082   document.body.appendChild(webview);
1083   webview.src = 'data:text/html,trigger navigation';
1084   document.body.removeChild(webview);
1085   setTimeout(function() {
1086     embedder.test.succeed();
1087   }, 0);
1088 }
1089
1090 function testNavigationToExternalProtocol() {
1091   var webview = document.createElement('webview');
1092   webview.addEventListener('loadstop', function(e) {
1093     webview.addEventListener('loadabort', function(e) {
1094       embedder.test.assertEq('ERR_UNKNOWN_URL_SCHEME', e.reason);
1095       embedder.test.succeed();
1096     });
1097     webview.executeScript({
1098       code: 'window.location.href = "tel:+12223334444";'
1099     }, function(results) {});
1100   });
1101   webview.setAttribute('src', 'data:text/html,navigate to external protocol');
1102   document.body.appendChild(webview);
1103 }
1104
1105 function testResizeWebviewResizesContent() {
1106   var triggerNavUrl = 'data:text/html,trigger navigation';
1107   var webview = new WebView();
1108   webview.src = triggerNavUrl;
1109   webview.addEventListener('loadstop', function(e) {
1110     webview.executeScript(
1111       {file: 'inject_resize_test.js'},
1112       function(results) {
1113         console.log('Script has been injected into webview.');
1114         // Establish a communication channel with the guest.
1115         var msg = ['connect'];
1116         webview.contentWindow.postMessage(JSON.stringify(msg), '*');
1117       }
1118     );
1119   });
1120   window.addEventListener('message', function(e) {
1121     var data = JSON.parse(e.data);
1122     if (data[0] == 'connected') {
1123       console.log('A communication channel has been established with webview.');
1124       console.log('Resizing <webview> width from 300px to 400px.');
1125       webview.style.width = '400px';
1126       return;
1127     }
1128     if (data[0] == 'resize') {
1129       var width = data[1];
1130       var height = data[2];
1131       embedder.test.assertEq(400, width);
1132       embedder.test.assertEq(300, height);
1133       embedder.test.succeed();
1134       return;
1135     }
1136     console.log('Unexpected message: \'' + data[0]  + '\'');
1137     embedder.test.fail();
1138   });
1139   document.body.appendChild(webview);
1140 }
1141
1142 embedder.test.testList = {
1143   'testAutosizeAfterNavigation': testAutosizeAfterNavigation,
1144   'testAutosizeBeforeNavigation': testAutosizeBeforeNavigation,
1145   'testAutosizeRemoveAttributes': testAutosizeRemoveAttributes,
1146   'testAutosizeWithPartialAttributes': testAutosizeWithPartialAttributes,
1147   'testAPIMethodExistence': testAPIMethodExistence,
1148   'testChromeExtensionURL': testChromeExtensionURL,
1149   'testChromeExtensionRelativePath': testChromeExtensionRelativePath,
1150   'testInvalidChromeExtensionURL': testInvalidChromeExtensionURL,
1151   'testWebRequestAPIExistence': testWebRequestAPIExistence,
1152   'testEventName': testEventName,
1153   'testOnEventProperties': testOnEventProperties,
1154   'testLoadProgressEvent': testLoadProgressEvent,
1155   'testDestroyOnEventListener': testDestroyOnEventListener,
1156   'testCannotMutateEventName': testCannotMutateEventName,
1157   'testPartitionRaisesException': testPartitionRaisesException,
1158   'testExecuteScriptFail': testExecuteScriptFail,
1159   'testExecuteScript': testExecuteScript,
1160   'testTerminateAfterExit': testTerminateAfterExit,
1161   'testAssignSrcAfterCrash': testAssignSrcAfterCrash,
1162   'testNavOnConsecutiveSrcAttributeChanges':
1163       testNavOnConsecutiveSrcAttributeChanges,
1164   'testNavOnSrcAttributeChange': testNavOnSrcAttributeChange,
1165   'testReassignSrcAttribute': testReassignSrcAttribute,
1166   'testRemoveSrcAttribute': testRemoveSrcAttribute,
1167   'testBrowserPluginNotAllowed': testBrowserPluginNotAllowed,
1168   'testPluginLoadPermission': testPluginLoadPermission,
1169   'testNewWindow': testNewWindow,
1170   'testNewWindowTwoListeners': testNewWindowTwoListeners,
1171   'testNewWindowNoPreventDefault': testNewWindowNoPreventDefault,
1172   'testNewWindowNoReferrerLink': testNewWindowNoReferrerLink,
1173   'testContentLoadEvent': testContentLoadEvent,
1174   'testWebRequestAPI': testWebRequestAPI,
1175   'testWebRequestAPIGoogleProperty': testWebRequestAPIGoogleProperty,
1176   'testWebRequestListenerSurvivesReparenting':
1177       testWebRequestListenerSurvivesReparenting,
1178   'testGetProcessId': testGetProcessId,
1179   'testLoadStartLoadRedirect': testLoadStartLoadRedirect,
1180   'testLoadAbortChromeExtensionURLWrongPartition':
1181       testLoadAbortChromeExtensionURLWrongPartition,
1182   'testLoadAbortEmptyResponse': testLoadAbortEmptyResponse,
1183   'testLoadAbortIllegalChromeURL': testLoadAbortIllegalChromeURL,
1184   'testLoadAbortIllegalFileURL': testLoadAbortIllegalFileURL,
1185   'testLoadAbortIllegalJavaScriptURL': testLoadAbortIllegalJavaScriptURL,
1186   'testNavigationToExternalProtocol': testNavigationToExternalProtocol,
1187   'testReload': testReload,
1188   'testRemoveWebviewOnExit': testRemoveWebviewOnExit,
1189   'testRemoveWebviewAfterNavigation': testRemoveWebviewAfterNavigation,
1190   'testResizeWebviewResizesContent': testResizeWebviewResizesContent
1191 };
1192
1193 onload = function() {
1194   chrome.test.getConfig(function(config) {
1195     embedder.setUp_(config);
1196     chrome.test.sendMessage("Launched");
1197   });
1198 };