summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-04 08:44:40 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-04 08:44:40 +0000
commitc67455479bbba5d654e103de91bd50a3c694812d (patch)
tree6586041b8662728b2469f1785f24e7c10d957b63 /chrome
parentcc5da3358b18bb13a0f6963a359b3e0e1b0e8267 (diff)
downloadchromium_src-c67455479bbba5d654e103de91bd50a3c694812d.zip
chromium_src-c67455479bbba5d654e103de91bd50a3c694812d.tar.gz
chromium_src-c67455479bbba5d654e103de91bd50a3c694812d.tar.bz2
Commit http://codereview.chromium.org/27037
Implement GM_xmlhttpRequest Review URL: http://codereview.chromium.org/39121 Patch from Steve Krulewitz <skrulx@gmail.com>. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10886 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rwxr-xr-xchrome/renderer/extensions/greasemonkey_api_unittest.cc2
-rw-r--r--chrome/renderer/resources/greasemonkey_api.js47
-rw-r--r--chrome/test/data/extensions/greasemonkey_api_test.js332
-rw-r--r--chrome/test/v8_unit_test.h51
4 files changed, 173 insertions, 259 deletions
diff --git a/chrome/renderer/extensions/greasemonkey_api_unittest.cc b/chrome/renderer/extensions/greasemonkey_api_unittest.cc
index fef69a8..23bf07a 100755
--- a/chrome/renderer/extensions/greasemonkey_api_unittest.cc
+++ b/chrome/renderer/extensions/greasemonkey_api_unittest.cc
@@ -67,11 +67,9 @@ TEST_F(GreasemonkeyApiTest, AddStyle) {
TestFunction("testAddStyle");
}
-/*
TEST_F(GreasemonkeyApiTest, XmlhttpRequest) {
TestFunction("testXmlhttpRequest");
}
-*/
TEST_F(GreasemonkeyApiTest, RegisterMenuCommand) {
TestFunction("testRegisterMenuCommand");
diff --git a/chrome/renderer/resources/greasemonkey_api.js b/chrome/renderer/resources/greasemonkey_api.js
index 57fa252..320e42a 100644
--- a/chrome/renderer/resources/greasemonkey_api.js
+++ b/chrome/renderer/resources/greasemonkey_api.js
@@ -63,18 +63,53 @@ function GM_getResourceText(resourceName) {
}
function GM_addStyle(css) {
- var head = document.getElementsByTagName("head")[0];
- if (!head) {
- return;
+ var parent = document.getElementsByTagName("head")[0];
+ if (!parent) {
+ parent = document.documentElement;
}
var style = document.createElement("style");
style.type = "text/css";
- style.innerHTML = css;
- head.appendChild(style);
+ var textNode = document.createTextNode(css);
+ style.appendChild(textNode);
+ parent.appendChild(style);
}
function GM_xmlhttpRequest(details) {
- throw new Error("not implemented.");
+ function setupEvent(xhr, url, eventName, callback) {
+ xhr[eventName] = function () {
+ var isComplete = xhr.readyState == 4;
+ var responseState = {
+ responseText: xhr.responseText,
+ readyState: xhr.readyState,
+ responseHeaders: isComplete ? xhr.getAllResponseHeaders() : "",
+ status: isComplete ? xhr.status : 0,
+ statusText: isComplete ? xhr.statusText : "",
+ finalUrl: isComplete ? url : ""
+ };
+ callback(responseState);
+ };
+ }
+
+ var xhr = new XMLHttpRequest();
+ var eventNames = ["onload", "onerror", "onreadystatechange"];
+ for (var i = 0; i < eventNames.length; i++ ) {
+ var eventName = eventNames[i];
+ if (eventName in details) {
+ setupEvent(xhr, details.url, eventName, details[eventName]);
+ }
+ }
+
+ xhr.open(details.method, details.url);
+
+ if (details.overrideMimeType) {
+ xhr.overrideMimeType(details.overrideMimeType);
+ }
+ if (details.headers) {
+ for (var header in details.headers) {
+ xhr.setRequestHeader(header, details.headers[header]);
+ }
+ }
+ xhr.send(details.data ? details.data : null);
}
function GM_registerMenuCommand(commandName, commandFunc, accelKey,
diff --git a/chrome/test/data/extensions/greasemonkey_api_test.js b/chrome/test/data/extensions/greasemonkey_api_test.js
index d43e2a0..e629cee 100644
--- a/chrome/test/data/extensions/greasemonkey_api_test.js
+++ b/chrome/test/data/extensions/greasemonkey_api_test.js
@@ -1,6 +1,8 @@
var localStorage;
var document;
var window;
+var XMLHttpRequest;
+var lastCreatedXhr;
function testGetSetValue() {
localStorage = new LocalStorageFake();
@@ -65,19 +67,100 @@ function testGetResourceText() {
}
function testAddStyle() {
+ var documentElement = new ElementFake('');
var head = new ElementFake('head');
- document = new DocumentFake(head);
+ document = new DocumentFake(documentElement, head);
var css = 'color: #decaff;';
GM_addStyle(css);
+ assert(0, documentElement.childNodes.length);
assert(1, head.childNodes.length);
var style = head.childNodes[0];
assert("style", style.tagName);
assert("text/css", style.type);
- assert(css, style.innerHTML);
+ assert(1, style.childNodes.length);
+ var textNode = style.childNodes[0];
+ assert(css, textNode.text);
+
+ document = new DocumentFake(documentElement, null);
+ GM_addStyle(css);
+ assert(1, documentElement.childNodes.length);
+ var style = documentElement.childNodes[0];
+ assert("text/css", style.type);
+ assert(1, style.childNodes.length);
+ textNode = style.childNodes[0];
+ assert(css, textNode.text);
}
function testXmlhttpRequest() {
- var xhr = GM_xmlhttpRequest({});
+ XMLHttpRequest = XMLHttpRequestFake;
+ var url = 'http://example.com';
+
+ var onLoadCallback = function(state) {
+ onLoadCallbackResponseState = state;
+ };
+ var onErrorCallback = function(state) {
+ onErrorCallbackResponseState = state;
+ };
+ var onReadyStateChangeCallback = function(state) {
+ onReadyStateChangeCallbackResponseState = state;
+ };
+
+ var details = {
+ onload: onLoadCallback,
+ onerror: onErrorCallback,
+ onreadystatechange: onReadyStateChangeCallback,
+ method: 'GET',
+ url: url,
+ overrideMimeType: 'text/html',
+ headers: {
+ 'X-Header': 'foo'
+ },
+ data: 'data'
+ };
+
+ GM_xmlhttpRequest(details);
+ var xhr = lastCreatedXhr;
+
+ assert('GET', xhr.openedMethod);
+ assert(url, xhr.openedUrl);
+ assert('text/html', xhr.overrideMimeType);
+ assert('foo', xhr.requestHeaders['X-Header']);
+ assert('data', xhr.sentBody);
+
+ xhr.responseText = 'foo';
+ xhr.responseHeaders['X-Response'] = 'foo';
+ xhr.status = 200;
+ xhr.statusText = 'OK';
+
+ xhr.readyState = 1;
+ xhr.onreadystatechange();
+ var state = onReadyStateChangeCallbackResponseState;
+ assert(xhr.responseText, state.responseText);
+ assert(xhr.readyState, state.readyState);
+ assert('', state.responseHeaders);
+ assert(0, state.status);
+ assert('', state.statusText);
+ assert('', state.finalUrl);
+
+ xhr.readyState = 0;
+ xhr.onerror();
+ state = onErrorCallbackResponseState;
+ assert(xhr.responseText, state.responseText);
+ assert(xhr.readyState, state.readyState);
+ assert('', state.responseHeaders);
+ assert(0, state.status);
+ assert('', state.statusText);
+ assert('', state.finalUrl);
+
+ xhr.readyState = 4;
+ xhr.onload();
+ state = onLoadCallbackResponseState;
+ assert(xhr.responseText, state.responseText);
+ assert(xhr.readyState, state.readyState);
+ assert('X-Response: foo\r\n', state.responseHeaders);
+ assert(xhr.status, state.status);
+ assert(xhr.statusText, state.statusText);
+ assert(url, state.finalUrl);
}
function testRegisterMenuCommand() {
@@ -155,7 +238,8 @@ LocalStorageFake.prototype = {
}
}
-function DocumentFake(head) {
+function DocumentFake(documentElement, head) {
+ this.documentElement = documentElement;
this.head_ = head;
}
DocumentFake.prototype = {
@@ -167,224 +251,69 @@ DocumentFake.prototype = {
},
createElement: function(tagName) {
return new ElementFake(tagName);
+ },
+ createTextNode: function(text) {
+ return new TextNodeFake(text);
}
}
function ElementFake(tagName) {
this.tagName = tagName;
+ this.childNodes = [];
}
ElementFake.prototype = {
- childNodes: [],
appendChild: function(e) {
this.childNodes.push(e);
return e;
- },
-}
-
-function assert(expected, actual) {
- if (expected !== actual) {
- throw new Error('Assert failed: "' + expected + '" !== "' + actual + '"');
}
}
-function fail() {
- throw new Error('Fail');
-}
-
-function assertThrow(f) {
- var threw = false;
- try {
- f();
- } catch(e) {
- threw = true;
- }
- if (!threw) {
- throw new Error('Assert failed, expression did not throw.');
- }
-}
-var localStorage;
-var document;
-var window;
-
-function testGetSetValue() {
- localStorage = new LocalStorageFake();
- GM_setValue('string', 'value');
- assert('value', GM_getValue('string'));
- GM_setValue('integer', 123);
- assert(123, GM_getValue('integer'));
- GM_setValue('boolean', true);
- assert(true, GM_getValue('boolean'));
-
- assert(undefined, GM_getValue('notset'));
- assert('default', GM_getValue('notset', 'default'));
-
- // illegal values
- assertThrow(function() {
- GM_setValue('illegal value', null);
- });
- assertThrow(function() {
- GM_setValue('illegal value', 1.5);
- });
-}
-
-function testDeleteValue() {
- localStorage = new LocalStorageFake();
- GM_setValue('delete', 'value');
- assert('value', GM_getValue('delete'));
- GM_deleteValue('delete');
- assert(undefined, GM_getValue('delete'));
- GM_deleteValue('notset');
-}
-
-function testListValues() {
- localStorage = new LocalStorageFake();
- var a = GM_listValues();
- assert(0, a.length);
-
- GM_setValue('one', 'first');
- a = GM_listValues();
- assert(1, a.length);
- assert('one', a[0]);
-
- GM_setValue('two', 'second');
- a = GM_listValues();
-
- // Test that keys that are not namespaced can't be read.
- localStorage.setItem('three', 'third');
- assert(2, a.length);
- assert(true, a.indexOf('one') >= 0);
- assert(true, a.indexOf('two') >= 0);
-}
-
-function testGetResourceURL() {
- assertThrow(function() {
- var resource = GM_getResourceURL('urlResourceName');
- });
-}
-
-function testGetResourceText() {
- assertThrow(function() {
- var resource = GM_getResourceText('textResourceName');
- });
-}
-
-function testAddStyle() {
- var head = new ElementFake('head');
- document = new DocumentFake(head);
- var css = 'color: #decaff;';
- GM_addStyle(css);
- assert(1, head.childNodes.length);
- var style = head.childNodes[0];
- assert("style", style.tagName);
- assert("text/css", style.type);
- assert(css, style.innerHTML);
-}
-
-function testXmlhttpRequest() {
- var xhr = GM_xmlhttpRequest({});
-}
-
-function testRegisterMenuCommand() {
- assertThrow(function() {
- GM_registerMenuCommand('name', function() {}, 'a', '', 'a');
- });
-}
-
-function testOpenInTab() {
- var mockWindow = {
- open: function(url, name, opt_options) {
- this.openedUrl = url;
- this.openedName = name;
- this.openedOptions = opt_options;
- }
- };
- window = mockWindow;
- var url = 'http://example.com';
- GM_openInTab(url);
- assert(mockWindow.openedUrl, url);
-}
-
-function testLog() {
- var mockWindow = {
- console: {
- message: null,
- log: function(message) {
- this.message = message;
- }
- }
- };
- window = mockWindow;
- var message = 'hello world';
- GM_log(message);
- assert(message, mockWindow.console.message);
-}
-
-function LocalStorageFake() {
- this.map_ = {};
- this.keys_ = [];
-}
-LocalStorageFake.prototype = {
- length: 0,
- key: function(index) {
- if (index >= this.length) {
- throw new Error('INDEX_SIZE_ERR');
- }
- return this.keys_[index];
+function TextNodeFake(text) {
+ this.text = text;
+}
+
+function XMLHttpRequestFake() {
+ lastCreatedXhr = this;
+ this.onload = null;
+ this.onerror = null;
+ this.onreadystatechange = null;
+ this.openedMethod = null;
+ this.openededUrl = null;
+ this.overriddenMimeType = null;
+ this.requestHeaders = {};
+ this.sentBody = null;
+ this.responseText = null;
+ this.readyState = null;
+ this.responseHeaders = {};
+ this.status = null;
+ this.statusText = null;
+}
+XMLHttpRequestFake.prototype = {
+ open: function(method, url) {
+ this.openedMethod = method;
+ this.openedUrl = url;
},
- getItem: function(key) {
- if (key in this.map_) {
- return this.map_[key];
- }
- return null;
+ overrideMimeType: function(mimeType) {
+ this.overrideMimeType = mimeType;
},
- setItem: function(key, data) {
- this.map_[key] = data;
- this.updateKeys_();
+ setRequestHeader: function(header, value) {
+ this.requestHeaders[header] = value;
},
- removeItem: function(key) {
- delete this.map_[key];
- this.updateKeys_();
- },
- clear: function() {
- this.map_ = {};
- this.updateKeys_();
+ send: function(opt_body) {
+ this.sentBody = opt_body;
},
- updateKeys_: function() {
- var keys = [];
- for (var key in this.map_) {
- keys.push(key);
- }
- this.keys_ = keys;
- this.length = keys.length;
- }
-}
-
-function DocumentFake(head) {
- this.head_ = head;
-}
-DocumentFake.prototype = {
- getElementsByTagName: function(tagName) {
- if (tagName == 'head' && this.head_) {
- return [this.head_];
+ getAllResponseHeaders: function() {
+ var s = '';
+ for (var header in this.responseHeaders) {
+ // The delimiter used in Webkit's XMLHttpRequest is \r\n, however
+ // the new Chrome networking code (and Firefox) uses \n, so watch
+ // out for this!
+ s += header + ': ' + this.responseHeaders[header] + '\r\n';
}
- return [];
- },
- createElement: function(tagName) {
- return new ElementFake(tagName);
+ return s;
}
}
-function ElementFake(tagName) {
- this.tagName = tagName;
-}
-ElementFake.prototype = {
- childNodes: [],
- appendChild: function(e) {
- this.childNodes.push(e);
- return e;
- },
-}
-
function assert(expected, actual) {
if (expected !== actual) {
throw new Error('Assert failed: "' + expected + '" !== "' + actual + '"');
@@ -406,3 +335,4 @@ function assertThrow(f) {
throw new Error('Assert failed, expression did not throw.');
}
}
+
diff --git a/chrome/test/v8_unit_test.h b/chrome/test/v8_unit_test.h
index 5b4c4ce..0ffddd2 100644
--- a/chrome/test/v8_unit_test.h
+++ b/chrome/test/v8_unit_test.h
@@ -11,7 +11,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "v8/include/v8.h"
-// A superclass for unit tests that involve running JavaeScript. This class
+// A superclass for unit tests that involve running JavaScript. This class
// sets up V8 context and has methods that make it easy to execute scripts in
// this context as well as call functions in the context.
class V8UnitTest : public testing::Test {
@@ -48,53 +48,4 @@ class V8UnitTest : public testing::Test {
#endif // CHROME_TEST_V8_UNIT_TEST_H_
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_TEST_V8_UNIT_TEST_H_
-#define CHROME_TEST_V8_UNIT_TEST_H_
-
-#include <string>
-
-#include "base/string_piece.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "v8/include/v8.h"
-
-// A superclass for unit tests that involve running JavaeScript. This class
-// sets up V8 context and has methods that make it easy to execute scripts in
-// this context as well as call functions in the context.
-class V8UnitTest : public testing::Test {
- public:
- V8UnitTest() {}
- virtual void SetUp();
-
- protected:
- // Executes the given script source in the context. The specified script
- // name is used when reporting errors.
- virtual void ExecuteScriptInContext(const StringPiece& script_source,
- const StringPiece& script_name);
-
- // Converts a v8::TryCatch into a human readable string.
- virtual std::string ExceptionToString(v8::TryCatch* try_catch);
-
- // Calls the specified function that resides in the global scope of the
- // context. If the function throws an exception, FAIL() is called to
- // indicate a unit test failure. This is useful for executing unit test
- // functions implemented in JavaScript.
- virtual void TestFunction(const std::string& function_name);
-
- // This method is bound to a global function "log" in the context.
- // Scripts running in the context can call this to print out logging
- // information to the console.
- static v8::Handle<v8::Value> Log(const v8::Arguments& args);
-
- // Handle scope that is used throughout the life of this class.
- v8::HandleScope handle_scope_;
-
- // Context for the JavaScript in the test.
- v8::Handle<v8::Context> context_;
-};
-
-#endif // CHROME_TEST_V8_UNIT_TEST_H_