1// Copyright 2013 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#include <string>
6
7#include "base/command_line.h"
8#include "base/files/file_path.h"
9#include "base/files/file_util.h"
10#include "chrome/browser/ui/browser.h"
11#include "chrome/browser/ui/tabs/tab_strip_model.h"
12#include "chrome/common/chrome_switches.h"
13#include "chrome/test/base/in_process_browser_test.h"
14#include "chrome/test/base/ui_test_utils.h"
15#include "content/public/browser/navigation_details.h"
16#include "content/public/test/browser_test_utils.h"
17#include "grit/login_resources.h"
18#include "ui/base/resource/resource_bundle.h"
19#include "url/gurl.h"
20
21namespace {
22
23GURL CreateResource(const std::string& content) {
24  base::FilePath path;
25  EXPECT_TRUE(base::CreateTemporaryFile(&path));
26  EXPECT_TRUE(base::WriteFile(path, content.c_str(), content.size()));
27  return GURL("file:///" + path.AsUTF8Unsafe());
28}
29
30// Test the CrOS login screen resource loading mechanism.
31class ResourceLoaderBrowserTest : public InProcessBrowserTest {
32 public:
33  ResourceLoaderBrowserTest() {}
34
35 protected:
36  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
37    // Needed to load file:// URLs in XHRs.
38    command_line->AppendSwitch(switches::kDisableWebSecurity);
39  }
40
41  virtual void SetUpOnMainThread() OVERRIDE {
42    // Create the root page containing resource_loader.js.
43    std::string root_page =
44        "<html>"
45        "<head>"
46        "<script>"
47        "  cr = { ui: { login: {} } };"
48        "  cr.define = function (path, builder) {"
49        "    cr.ui.login.ResourceLoader = builder();"
50        "  };"
51        "  $ = document.getElementById.bind(document);"
52        "</script>"
53        "<script>";
54    ResourceBundle::GetSharedInstance().GetRawDataResource(
55        IDR_OOBE_RESOURCE_LOADER_JS).AppendToString(&root_page);
56    root_page +=
57        "</script>"
58        "</head>"
59        "<body>"
60        "<div id=\"root\"></div>"
61        "</body>"
62        "</html>";
63    ui_test_utils::NavigateToURL(browser(), CreateResource(root_page));
64    JSExpect("!!document.querySelector('#root')");
65
66    // Define global alias for convenience.
67    JSEval("ResourceLoader = cr.ui.login.ResourceLoader;");
68  }
69
70  void JSEval(const std::string& script) {
71    EXPECT_TRUE(content::ExecuteScript(
72        browser()->tab_strip_model()->GetActiveWebContents(), script));
73  }
74
75  void JSExpect(const std::string& expression) {
76    bool result;
77    EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
78        browser()->tab_strip_model()->GetActiveWebContents(),
79        "window.domAutomationController.send(!!(" + expression + "));",
80        &result));
81    EXPECT_TRUE(result) << expression;
82  }
83
84  void JSExpectAsync(const std::string& function) {
85    bool result;
86    EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
87        browser()->tab_strip_model()->GetActiveWebContents(),
88        "(" + function + ")(function() {"
89        "  window.domAutomationController.send(true);"
90        "});",
91        &result));
92    EXPECT_TRUE(result);
93  }
94
95 private:
96  DISALLOW_COPY_AND_ASSIGN(ResourceLoaderBrowserTest);
97};
98
99IN_PROC_BROWSER_TEST_F(ResourceLoaderBrowserTest, RegisterAssetsTest) {
100  JSExpect("!ResourceLoader.hasDeferredAssets('foo')");
101  JSEval("ResourceLoader.registerAssets({ id: 'foo' });");
102  JSExpect("ResourceLoader.hasDeferredAssets('foo')");
103}
104
105IN_PROC_BROWSER_TEST_F(ResourceLoaderBrowserTest, LoadAssetsTest) {
106  // Create a flag to set when the JavaScript is loaded.
107  JSEval("stuff = {}");
108
109  // Create the assets.
110  std::string html_url = CreateResource("<h1 id=\"bar\">foo</h1>").spec();
111  std::string css_url = CreateResource("h1 { color: red; }").spec();
112  std::string js_url = CreateResource("stuff.loaded = true;").spec();
113
114  // Register the asset bundle.
115  JSEval("ResourceLoader.registerAssets({"
116         "  id: 'test-bundle',"
117         "  html: [ { url: '" + html_url + "', targetID: 'root' } ]," +
118         "  css: [ '" + css_url + "' ]," +
119         "  js: [ '" + js_url + "' ]," +
120         "});");
121  JSExpect("!ResourceLoader.alreadyLoadedAssets('test-bundle')");
122
123  // Load the assets and make sure everything is properly added to the page.
124  JSExpectAsync("ResourceLoader.loadAssets.bind(null, 'test-bundle')");
125  JSExpect("ResourceLoader.alreadyLoadedAssets('test-bundle')");
126
127  // Check that the HTML was inserted into the root div.
128  JSExpect("!!document.querySelector('div#root h1#bar')");
129
130  // Check that the JS was loaded and evaluated.
131  JSExpect("stuff.loaded");
132
133  // Check that the styles were loaded.
134  JSExpect("!!document.head.querySelector('link').innerHTML.indexOf('red')");
135}
136
137}  // namespace
138