1 // Copyright 2015 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 "ios/web/webui/crw_web_ui_page_builder.h"
7 #import <Foundation/Foundation.h>
9 #include "base/logging.h"
10 #import "base/mac/scoped_nsobject.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "testing/gtest_mac.h"
14 #include "testing/platform_test.h"
19 // HTML page template.
20 NSString* const kPageTemplate = @"<html><head>%@</head></html>";
22 // URL for BuildSimplePage.
23 const char* kSimplePageUrl("http://simplepage");
24 // URL for BuildPageWithJSSubresource.
25 const char* kJsPageUrl("http://javascriptpage");
26 // URL for BuildPageWithCSSSubresource.
27 const char* kCssPageUrl("http://csspage");
28 // URL for BuildPageWithMultipleSubresources.
29 const char* kMultipleResourcesPageUrl("http://multipleresourcespage");
30 // URL for BuildPageWithCSSNestedSubresources.
31 const char* kCssImportPageUrl("http://csspagewithimport");
32 // URL for BuildPageWithRelativeSubresource.
33 const char* kCssRelativePageUrl("http://css/csspage.html");
34 // URL for BuildPageWithWebUIJS.
35 const char* kCoreJsPageUrl("http://corejs");
37 // URL for JS resource.
38 const char* kJsResourceUrl("http://javascriptpage/resources/javascript.js");
39 // URL for CSS resource.
40 const char* kCssResourceUrl("http://csspage/resources/stylesheet.css");
41 // URL for CSS resource with import.
42 const char* kCssImportResourceUrl("http://csspage/resources/import.css");
43 // Chrome URL for messaging JavaScript.
44 const char* kCoreJsResourceUrl("chrome://resources/js/ios/web_ui.js");
45 // String for relative resource URL.
46 const char* kRelativeCssString("myresource.css");
48 // Template for JS tag with URL.
49 NSString* const kJsTagTemplate = @"<script src=\"%@\"></script>";
50 // Template for inlined JS tag.
51 NSString* const kJsInlinedTemplate = @"<script>%@</script>";
52 // Template for CSS tag with URL.
53 NSString* const kCssTagTemplate = @"<link rel=\"stylesheet\" href=\"%@\">";
54 // Template for inlined CSS tag.
55 NSString* const kCssInlinedTemplate = @"<style>%@</style>";
56 // Template for CSS with import statement.
57 NSString* const kCssImportTemplate = @"@import url(%@); b {diplay:block;}";
59 // Content for JS resource.
60 NSString* const kJsContent = @"console.log('This is JavaScript');";
61 // Content for CSS resource.
62 NSString* const kCssContent = @"html {height:100%;}";
63 // Content for relative CSS resource.
64 NSString* const kRelativeCssContent = @"mytag {someprop:1}";
65 // Dummy content for WebUI messaging JavaScript.
66 NSString* kCoreJsContent = @"console.log('messaging javascript');";
68 // Returns HTML string containing tag formed with tag_template and content.
69 NSString* PageForTagTemplateAndContent(NSString* tag_template,
71 NSString* tag = [NSString stringWithFormat:tag_template, content];
72 return [NSString stringWithFormat:kPageTemplate, tag];
77 // Mock subclass of CRWWebUIPageBuilder for testing.
78 @interface MockCRWWebUIPageBuilder : CRWWebUIPageBuilder
79 // Stub out webUIJavaScript method so resource bundle access is not needed.
80 - (NSString*)webUIJavaScript;
83 @implementation MockCRWWebUIPageBuilder
84 - (NSString*)webUIJavaScript {
85 return kCoreJsContent;
89 // Mock CRWWebUIPageBuilderDelegate to serve responses for resource requests.
90 @interface MockPageBuilderDelegate : NSObject<CRWWebUIPageBuilderDelegate>
91 // Returns HTML page containing tag formed from tagTemplate and URL.
92 - (NSString*)pageWithTagTemplate:(NSString*)tagTemplate URL:(const char*)URL;
93 // Returns resource string for resourceURL.
94 - (NSString*)resourceForURL:(const GURL&)resourceURL;
97 @implementation MockPageBuilderDelegate
99 - (void)webUIPageBuilder:(CRWWebUIPageBuilder*)webUIPageBuilder
100 fetchResourceWithURL:(const GURL&)resourceURL
101 completionHandler:(web::WebUIDelegateCompletion)completionHandler {
102 completionHandler([self resourceForURL:resourceURL], resourceURL);
105 - (NSString*)resourceForURL:(const GURL&)resourceURL {
106 // Resource for BuildSimplePage.
107 if (resourceURL == GURL(kSimplePageUrl))
108 return [NSString stringWithFormat:kPageTemplate, @""];
109 // Resources for BuildPageWithJSSubresource.
110 if (resourceURL == GURL(kJsPageUrl))
111 return [self pageWithTagTemplate:kJsTagTemplate URL:kJsResourceUrl];
112 if (resourceURL == GURL(kJsResourceUrl))
114 // Resources for BuildPageWithCSSSubresource.
115 if (resourceURL == GURL(kCssPageUrl))
116 return [self pageWithTagTemplate:kCssTagTemplate URL:kCssResourceUrl];
117 if (resourceURL == GURL(kCssResourceUrl))
119 // Resource for BuildPageWithMultipleSubresources.
120 if (resourceURL == GURL(kMultipleResourcesPageUrl)) {
122 [NSString stringWithFormat:kJsTagTemplate,
123 base::SysUTF8ToNSString(kJsResourceUrl)];
125 [NSString stringWithFormat:kCssTagTemplate,
126 base::SysUTF8ToNSString(kCssResourceUrl)];
127 NSString* CoreJSTag =
128 [NSString stringWithFormat:kJsTagTemplate,
129 base::SysUTF8ToNSString(kCoreJsResourceUrl)];
130 NSString* tags = [[JSTag stringByAppendingString:CSSTag]
131 stringByAppendingString:CoreJSTag];
132 return [NSString stringWithFormat:kPageTemplate, tags];
134 // Resources for BuildPageWithCSSNestedSubresource.
135 if (resourceURL == GURL(kCssImportPageUrl)) {
136 return [self pageWithTagTemplate:kCssTagTemplate URL:kCssImportResourceUrl];
138 if (resourceURL == GURL(kCssImportResourceUrl)) {
139 return [NSString stringWithFormat:kCssImportTemplate,
140 base::SysUTF8ToNSString(kCssResourceUrl)];
142 // Resources for BuildPageWithRelativeSubresource.
143 GURL relativePageURL(kCssRelativePageUrl);
144 GURL cssRelativeResourceURL = relativePageURL.Resolve(kRelativeCssString);
145 if (resourceURL == relativePageURL) {
146 return [self pageWithTagTemplate:kCssTagTemplate URL:kRelativeCssString];
148 if (resourceURL == cssRelativeResourceURL)
149 return kRelativeCssContent;
150 // Resource for BuildPageWithWebUIJS.
151 if (resourceURL == GURL(kCoreJsPageUrl))
152 return [self pageWithTagTemplate:kJsTagTemplate URL:kCoreJsResourceUrl];
158 - (NSString*)pageWithTagTemplate:(NSString*)tagTemplate URL:(const char*)URL {
159 NSString* URLString = base::SysUTF8ToNSString(URL);
160 NSString* tag = [NSString stringWithFormat:tagTemplate, URLString];
161 return [NSString stringWithFormat:kPageTemplate, tag];
168 class CRWWebUIPageBuilderTest : public PlatformTest {
170 void SetUp() override {
171 PlatformTest::SetUp();
172 delegate_.reset([[MockPageBuilderDelegate alloc] init]);
173 web_ui_page_builder_.reset(
174 [[MockCRWWebUIPageBuilder alloc] initWithDelegate:delegate_]);
176 // CRWWebUIPageBuilder for testing.
177 base::scoped_nsobject<MockCRWWebUIPageBuilder> web_ui_page_builder_;
178 // Delegate for test CRWWebUIPageBuilder.
179 base::scoped_nsobject<MockPageBuilderDelegate> delegate_;
182 // Tests that a page without imports is passed to completion handler unchanged.
183 TEST_F(CRWWebUIPageBuilderTest, BuildSimplePage) {
184 NSString* simple_page_html = [NSString stringWithFormat:kPageTemplate, @""];
185 [web_ui_page_builder_ buildWebUIPageForURL:GURL(kSimplePageUrl)
186 completionHandler:^(NSString* result) {
187 EXPECT_NSEQ(simple_page_html, result);
191 // Tests that a page with a JavaScript subresource is passed to the completion
192 // handler with the resource inlined properly, i.e. <script
193 // src="http://somejs.js"></script> becomes <script>some javascript;</script>.
194 TEST_F(CRWWebUIPageBuilderTest, BuildPageWithJSSubresource) {
195 NSString* js_page_html =
196 PageForTagTemplateAndContent(kJsInlinedTemplate, kJsContent);
197 web::WebUIPageCompletion completionHandler = ^(NSString* result) {
198 EXPECT_NSEQ(js_page_html, result);
200 [web_ui_page_builder_ buildWebUIPageForURL:GURL(kJsPageUrl)
201 completionHandler:completionHandler];
204 // Tests that a page with a CSS subresource is passed to the completion handler
205 // with the resource inlined properly, i.e. <link rel="stylesheet"
206 // href="http://somecss.css"/> becomes <style>some css</style>.
207 TEST_F(CRWWebUIPageBuilderTest, BuildPageWithCSSSubresource) {
208 NSString* css_page_html =
209 PageForTagTemplateAndContent(kCssInlinedTemplate, kCssContent);
210 [web_ui_page_builder_ buildWebUIPageForURL:GURL(kCssPageUrl)
211 completionHandler:^(NSString* result) {
212 EXPECT_NSEQ(css_page_html, result);
216 TEST_F(CRWWebUIPageBuilderTest, BuildPageWithMultipleSubresources) {
217 NSString* js_tag = [NSString stringWithFormat:kJsInlinedTemplate, kJsContent];
219 [NSString stringWithFormat:kCssInlinedTemplate, kCssContent];
220 NSString* core_js_tag =
221 [NSString stringWithFormat:kJsInlinedTemplate, kCoreJsContent];
222 NSString* tags = [[js_tag stringByAppendingString:css_tag]
223 stringByAppendingString:core_js_tag];
224 NSString* multiple_resources_html =
225 [NSString stringWithFormat:kPageTemplate, tags];
226 [web_ui_page_builder_ buildWebUIPageForURL:GURL(kMultipleResourcesPageUrl)
227 completionHandler:^(NSString* result) {
228 EXPECT_NSEQ(multiple_resources_html, result);
232 // Tests that a page with a CSS subresource that contains an @import statement
233 // for another CSS subresource is passed to the completion handler with the
234 // resource inlined properly, i.e. if somecss.css from above has the statement
235 // @import url(morecss.css), the original tag becomes <style>contents of
236 // morecss</style><style>some css</style>.
237 TEST_F(CRWWebUIPageBuilderTest, BuildPageWithCSSNestedSubresource) {
238 NSString* css_inlined_tag =
239 [NSString stringWithFormat:kCssInlinedTemplate, kCssContent];
240 NSString* css_inlined_content =
241 [NSString stringWithFormat:kCssImportTemplate,
242 base::SysUTF8ToNSString(kCssResourceUrl)];
243 NSString* css_import_inlined_tag =
244 [NSString stringWithFormat:kCssInlinedTemplate, css_inlined_content];
246 [css_inlined_tag stringByAppendingString:css_import_inlined_tag];
247 NSString* css_import_page_html =
248 [NSString stringWithFormat:kPageTemplate, tags];
249 [web_ui_page_builder_ buildWebUIPageForURL:GURL(kCssImportPageUrl)
250 completionHandler:^(NSString* result) {
251 EXPECT_NSEQ(css_import_page_html, result);
255 // Tests that a page with a relative subresource is properly resolved.
256 TEST_F(CRWWebUIPageBuilderTest, BuildPageWithRelativeSubresource) {
257 NSString* css_page_html =
258 PageForTagTemplateAndContent(kCssInlinedTemplate, kRelativeCssContent);
259 [web_ui_page_builder_ buildWebUIPageForURL:GURL(kCssRelativePageUrl)
260 completionHandler:^(NSString* result) {
261 EXPECT_NSEQ(css_page_html, result);
265 // Tests that the JavaScript for connecting WebUI messaging to web controller
266 // messaging is properly inlined.
267 TEST_F(CRWWebUIPageBuilderTest, BuildPageWithWebUIJS) {
268 NSString* core_js_html =
269 PageForTagTemplateAndContent(kJsInlinedTemplate, kCoreJsContent);
270 [web_ui_page_builder_ buildWebUIPageForURL:GURL(kCoreJsPageUrl)
271 completionHandler:^(NSString* result) {
272 EXPECT_NSEQ(core_js_html, result);