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.
5 #include "chrome/browser/extensions/extension_browsertest.h"
6 #include "chrome/browser/ui/browser.h"
7 #include "chrome/browser/ui/tabs/tab_strip_model.h"
8 #include "chrome/common/url_constants.h"
9 #include "chrome/test/base/ui_test_utils.h"
10 #include "content/public/browser/web_contents.h"
11 #include "content/public/test/browser_test_utils.h"
12 #include "extensions/common/constants.h"
13 #include "extensions/common/extension.h"
15 using content::WebContents
;
16 using extensions::Extension
;
20 const char kSubscribePage
[] = "/subscribe.html";
21 const char kFeedPageMultiRel
[] = "files/feeds/feed_multi_rel.html";
22 const char kValidFeedNoLinks
[] = "files/feeds/feed_nolinks.xml";
23 const char kValidFeed0
[] = "files/feeds/feed_script.xml";
24 const char kValidFeed1
[] = "files/feeds/feed1.xml";
25 const char kValidFeed2
[] = "files/feeds/feed2.xml";
26 const char kValidFeed3
[] = "files/feeds/feed3.xml";
27 const char kValidFeed4
[] = "files/feeds/feed4.xml";
28 const char kValidFeed5
[] = "files/feeds/feed5.xml";
29 const char kValidFeed6
[] = "files/feeds/feed6.xml";
30 const char kInvalidFeed1
[] = "files/feeds/feed_invalid1.xml";
31 const char kInvalidFeed2
[] = "files/feeds/feed_invalid2.xml";
32 // We need a triple encoded string to prove that we are not decoding twice in
33 // subscribe.js because one layer is also stripped off when subscribe.js passes
34 // it to the XMLHttpRequest object.
35 const char kFeedTripleEncoded
[] = "files/feeds/url%25255Fdecoding.html";
37 static const char kScriptFeedTitle
[] =
38 "window.domAutomationController.send("
39 " document.getElementById('title') ? "
40 " document.getElementById('title').textContent : "
41 " \"element 'title' not found\""
43 static const char kScriptAnchor
[] =
44 "window.domAutomationController.send("
45 " document.getElementById('anchor_0') ? "
46 " document.getElementById('anchor_0').textContent : "
47 " \"element 'anchor_0' not found\""
49 static const char kScriptDesc
[] =
50 "window.domAutomationController.send("
51 " document.getElementById('desc_0') ? "
52 " document.getElementById('desc_0').textContent : "
53 " \"element 'desc_0' not found\""
55 static const char kScriptError
[] =
56 "window.domAutomationController.send("
57 " document.getElementById('error') ? "
58 " document.getElementById('error').textContent : "
62 GURL
GetFeedUrl(net::SpawnedTestServer
* server
, const std::string
& feed_page
,
63 bool direct_url
, std::string extension_id
) {
64 GURL feed_url
= server
->GetURL(feed_page
);
66 // We navigate directly to the subscribe page for feeds where the feed
67 // sniffing won't work, in other words, as is the case for malformed feeds.
68 return GURL(std::string(extensions::kExtensionScheme
) +
69 content::kStandardSchemeSeparator
+
70 extension_id
+ std::string(kSubscribePage
) + std::string("?") +
71 feed_url
.spec() + std::string("&synchronous"));
73 // Navigate to the feed content (which will cause the extension to try to
74 // sniff the type and display the subscribe page in another tab.
75 return GURL(feed_url
.spec());
79 bool ValidatePageElement(WebContents
* tab
,
80 const std::string
& frame_xpath
,
81 const std::string
& javascript
,
82 const std::string
& expected_value
) {
83 std::string returned_value
;
85 if (!content::ExecuteScriptInFrameAndExtractString(tab
, frame_xpath
,
90 EXPECT_STREQ(expected_value
.c_str(), returned_value
.c_str());
91 return expected_value
== returned_value
;
94 // Navigates to a feed page and, if |sniff_xml_type| is set, wait for the
95 // extension to kick in, detect the feed and redirect to a feed preview page.
96 // |sniff_xml_type| is generally set to true if the feed is sniffable and false
98 void NavigateToFeedAndValidate(net::SpawnedTestServer
* server
,
99 const std::string
& url
,
101 std::string extension_id
,
103 const std::string
& expected_feed_title
,
104 const std::string
& expected_item_title
,
105 const std::string
& expected_item_desc
,
106 const std::string
& expected_error
) {
107 if (sniff_xml_type
) {
108 // TODO(finnur): Implement this is a non-flaky way.
111 // Navigate to the subscribe page directly.
112 ui_test_utils::NavigateToURL(browser
,
113 GetFeedUrl(server
, url
, true, extension_id
));
115 WebContents
* tab
= browser
->tab_strip_model()->GetActiveWebContents();
116 ASSERT_TRUE(ValidatePageElement(
117 tab
, std::string(), kScriptFeedTitle
, expected_feed_title
));
118 ASSERT_TRUE(ValidatePageElement(tab
,
119 "//html/body/div/iframe[1]",
121 expected_item_title
));
122 ASSERT_TRUE(ValidatePageElement(tab
,
123 "//html/body/div/iframe[1]",
125 expected_item_desc
));
126 ASSERT_TRUE(ValidatePageElement(tab
,
127 "//html/body/div/iframe[1]",
134 // Makes sure that the RSS detects RSS feed links, even when rel tag contains
135 // more than just "alternate".
136 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSMultiRelLink
) {
137 ASSERT_TRUE(test_server()->Start());
139 ASSERT_TRUE(LoadExtension(
140 test_data_dir_
.AppendASCII("subscribe_page_action")));
142 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(0));
144 // Navigate to the feed page.
145 GURL feed_url
= test_server()->GetURL(kFeedPageMultiRel
);
146 ui_test_utils::NavigateToURL(browser(), feed_url
);
147 // We should now have one page action ready to go in the LocationBar.
148 ASSERT_TRUE(WaitForPageActionVisibilityChangeTo(1));
151 // This test is flaky on all platforms; see http://crbug.com/340354
152 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, DISABLED_RSSParseFeedValidFeed1
) {
153 ASSERT_TRUE(test_server()->Start());
155 const Extension
* extension
= LoadExtension(
156 test_data_dir_
.AppendASCII("subscribe_page_action"));
157 ASSERT_TRUE(extension
);
158 std::string id
= extension
->id();
160 NavigateToFeedAndValidate(test_server(), kValidFeed1
, browser(), id
, true,
161 "Feed for MyFeedTitle",
167 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedValidFeed2
) {
168 ASSERT_TRUE(test_server()->Start());
170 const Extension
* extension
= LoadExtension(
171 test_data_dir_
.AppendASCII("subscribe_page_action"));
172 ASSERT_TRUE(extension
);
173 std::string id
= extension
->id();
175 NavigateToFeedAndValidate(test_server(), kValidFeed2
, browser(), id
, true,
178 "This is a summary.",
182 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedValidFeed3
) {
183 ASSERT_TRUE(test_server()->Start());
185 const Extension
* extension
= LoadExtension(
186 test_data_dir_
.AppendASCII("subscribe_page_action"));
187 ASSERT_TRUE(extension
);
188 std::string id
= extension
->id();
190 NavigateToFeedAndValidate(test_server(), kValidFeed3
, browser(), id
, true,
191 "Feed for Google Code buglist rss feed",
197 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedValidFeed4
) {
198 ASSERT_TRUE(test_server()->Start());
200 const Extension
* extension
= LoadExtension(
201 test_data_dir_
.AppendASCII("subscribe_page_action"));
202 ASSERT_TRUE(extension
);
203 std::string id
= extension
->id();
205 NavigateToFeedAndValidate(test_server(), kValidFeed4
, browser(), id
, true,
206 "Feed for Title chars <script> %23 stop",
207 "Title chars %23 stop",
208 "My dear content %23 stop",
212 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedValidFeed0
) {
213 ASSERT_TRUE(test_server()->Start());
215 const Extension
* extension
= LoadExtension(
216 test_data_dir_
.AppendASCII("subscribe_page_action"));
217 ASSERT_TRUE(extension
);
218 std::string id
= extension
->id();
220 // Try a feed with a link with an onclick handler (before r27440 this would
221 // trigger a NOTREACHED).
222 NavigateToFeedAndValidate(test_server(), kValidFeed0
, browser(), id
, true,
223 "Feed for MyFeedTitle",
229 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedValidFeed5
) {
230 ASSERT_TRUE(test_server()->Start());
232 const Extension
* extension
= LoadExtension(
233 test_data_dir_
.AppendASCII("subscribe_page_action"));
234 ASSERT_TRUE(extension
);
235 std::string id
= extension
->id();
237 // Feed with valid but mostly empty xml.
238 NavigateToFeedAndValidate(test_server(), kValidFeed5
, browser(), id
, true,
239 "Feed for Unknown feed name",
240 "element 'anchor_0' not found",
241 "element 'desc_0' not found",
242 "This feed contains no entries.");
245 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedValidFeed6
) {
246 ASSERT_TRUE(test_server()->Start());
248 const Extension
* extension
= LoadExtension(
249 test_data_dir_
.AppendASCII("subscribe_page_action"));
250 ASSERT_TRUE(extension
);
251 std::string id
= extension
->id();
253 // Feed that is technically invalid but still parseable.
254 NavigateToFeedAndValidate(test_server(), kValidFeed6
, browser(), id
, true,
255 "Feed for MyFeedTitle",
261 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedInvalidFeed1
) {
262 ASSERT_TRUE(test_server()->Start());
264 const Extension
* extension
= LoadExtension(
265 test_data_dir_
.AppendASCII("subscribe_page_action"));
266 ASSERT_TRUE(extension
);
267 std::string id
= extension
->id();
269 // Try an empty feed.
270 NavigateToFeedAndValidate(test_server(), kInvalidFeed1
, browser(), id
, false,
271 "Feed for Unknown feed name",
272 "element 'anchor_0' not found",
273 "element 'desc_0' not found",
274 "This feed contains no entries.");
277 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedInvalidFeed2
) {
278 ASSERT_TRUE(test_server()->Start());
280 const Extension
* extension
= LoadExtension(
281 test_data_dir_
.AppendASCII("subscribe_page_action"));
282 ASSERT_TRUE(extension
);
283 std::string id
= extension
->id();
285 // Try a garbage feed.
286 NavigateToFeedAndValidate(test_server(), kInvalidFeed2
, browser(), id
, false,
287 "Feed for Unknown feed name",
288 "element 'anchor_0' not found",
289 "element 'desc_0' not found",
290 "This feed contains no entries.");
293 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedInvalidFeed3
) {
294 ASSERT_TRUE(test_server()->Start());
296 const Extension
* extension
= LoadExtension(
297 test_data_dir_
.AppendASCII("subscribe_page_action"));
298 ASSERT_TRUE(extension
);
299 std::string id
= extension
->id();
301 // Try a feed that doesn't exist.
302 NavigateToFeedAndValidate(test_server(), "foo.xml", browser(), id
, false,
303 "Feed for Unknown feed name",
304 "element 'anchor_0' not found",
305 "element 'desc_0' not found",
306 "This feed contains no entries.");
309 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedInvalidFeed4
) {
310 ASSERT_TRUE(test_server()->Start());
312 const Extension
* extension
= LoadExtension(
313 test_data_dir_
.AppendASCII("subscribe_page_action"));
314 ASSERT_TRUE(extension
);
315 std::string id
= extension
->id();
317 // subscribe.js shouldn't double-decode the URL passed in. Otherwise feed
318 // links such as http://search.twitter.com/search.atom?lang=en&q=%23chrome
319 // will result in no feed being downloaded because %23 gets decoded to # and
320 // therefore #chrome is not treated as part of the Twitter query. This test
321 // uses an underscore instead of a hash, but the principle is the same. If
322 // we start erroneously double decoding again, the path (and the feed) will
323 // become valid resulting in a failure for this test.
324 NavigateToFeedAndValidate(
325 test_server(), kFeedTripleEncoded
, browser(), id
, true,
326 "Feed for Unknown feed name",
327 "element 'anchor_0' not found",
328 "element 'desc_0' not found",
329 "This feed contains no entries.");
332 IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest
, RSSParseFeedValidFeedNoLinks
) {
333 ASSERT_TRUE(test_server()->Start());
335 const Extension
* extension
= LoadExtension(
336 test_data_dir_
.AppendASCII("subscribe_page_action"));
337 ASSERT_TRUE(extension
);
338 std::string id
= extension
->id();
340 // Valid feed but containing no links.
341 NavigateToFeedAndValidate(
342 test_server(), kValidFeedNoLinks
, browser(), id
, true,
343 "Feed for MyFeedTitle",
344 "Title with no link",