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.
5 #import <UIKit/UIWebView.h>
7 #include "ios/web/public/test/web_test_util.h"
8 #import "ios/web/public/web_state/js/crw_js_injection_manager.h"
9 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
10 #include "ios/web/test/web_test.h"
11 #import "testing/gtest_mac.h"
13 // Testing class of JsInjectioManager that has no dependencies.
14 @interface TestingCRWJSBaseManager : CRWJSInjectionManager
17 @implementation TestingCRWJSBaseManager
19 - (NSString*)presenceBeacon {
23 - (NSString*)staticInjectionContent {
29 // Testing class of JsInjectionManager that has no dependencies.
30 @interface TestingAnotherCRWJSBaseManager : CRWJSInjectionManager
33 @implementation TestingAnotherCRWJSBaseManager
35 - (NSString*)presenceBeacon {
36 return @"anotherbase";
39 - (NSString*)staticInjectionContent {
40 return @"anotherbase = {};";
45 // Testing class of JsInjectioManager that has dependencies.
46 @interface TestingJsManager : CRWJSInjectionManager
49 @implementation TestingJsManager
51 - (NSString*)presenceBeacon {
52 return @"base['testingjs']";
55 - (NSString*)staticInjectionContent {
56 return @"base['testingjs'] = {};";
59 - (NSArray*)directDependencies {
60 return @[ [TestingCRWJSBaseManager class] ];
65 // Testing class of JsInjectioManager that has dynamic content.
66 @interface TestingDynamicJsManager : CRWJSInjectionManager
69 @implementation TestingDynamicJsManager
71 - (NSString*)presenceBeacon {
75 - (NSString*)injectionContent {
77 return [NSString stringWithFormat:@"dynamic = {}; dynamic['foo'] = %d;", ++i];
80 - (NSString*)staticInjectionContent {
81 // This should never be called on a manager that has dynamic content.
89 // Testing class of JsInjectioManager that has dependencies.
90 @interface TestingAnotherJsManager : CRWJSInjectionManager
93 @implementation TestingAnotherJsManager
95 - (NSString*)presenceBeacon {
96 return @"base['anothertestingjs']";
99 - (NSString*)staticInjectionContent {
100 return @"base['anothertestingjs'] = {};";
103 - (NSArray*)directDependencies {
104 return @[ [TestingCRWJSBaseManager class] ];
110 // Testing class of JsInjectioManager that has nested dependencies.
111 @interface TestingJsManagerWithNestedDependencies : CRWJSInjectionManager
114 @implementation TestingJsManagerWithNestedDependencies
116 - (NSString*)presenceBeacon {
117 return @"base['testingjswithnesteddependencies']";
120 - (NSString*)staticInjectionContent {
121 return @"base['testingjswithnesteddependencies'] = {};";
124 - (NSArray*)directDependencies {
125 return @[[TestingJsManager class]];
130 // Testing class of JsInjectioManager that has nested dependencies.
131 @interface TestingJsManagerComplex : CRWJSInjectionManager
134 @implementation TestingJsManagerComplex
136 - (NSString*)presenceBeacon {
137 return @"base['testingjswithnesteddependencies']['complex']";
140 - (NSString*)staticInjectionContent {
141 return @"base['testingjswithnesteddependencies']['complex'] = {};";
144 - (NSArray*)directDependencies {
146 [TestingJsManagerWithNestedDependencies class],
147 [TestingAnotherJsManager class],
148 [TestingAnotherCRWJSBaseManager class],
158 // A mixin class for testing with CRWWKWebViewWebController or
159 // CRWUIWebViewWebController.
160 template <typename WebTestT>
161 class JsInjectionManagerTest : public WebTestT {
163 virtual void SetUp() override {
165 // Loads a dummy page to prepare JavaScript evaluation.
166 NSString* const kPageContent = @"<html><body><div></div></body></html>";
167 WebTestT::LoadHtml(kPageContent);
169 // Returns the manager of the given class.
170 CRWJSInjectionManager* GetInstanceOfClass(Class jsInjectionManagerClass);
171 // Returns true if the receiver_ has all the managers in |managers|.
172 bool HasReceiverManagers(NSArray* managers);
173 // EXPECTs that |actual| consists of the CRWJSInjectionManagers of the
174 // expected classes in a correct order.
175 void TestAllDependencies(NSArray* expected, NSArray* actual);
178 // Concrete test fixture to test UIWebView-based web controller injection.
179 typedef JsInjectionManagerTest<web::UIWebViewWebTest>
180 JsInjectionManagerUIWebViewTest;
182 // Concrete test fixture to test WKWebView-based web controller injection.
183 class JsInjectionManagerWKWebViewTest :
184 public JsInjectionManagerTest<web::WKWebViewWebTest> {
186 void SetUp() override {
187 // SetUp crashes on WKWebView creation if running on iOS7.
188 CR_TEST_REQUIRES_WK_WEB_VIEW();
189 JsInjectionManagerTest<web::WKWebViewWebTest>::SetUp();
193 template <typename WebTestT>
194 bool JsInjectionManagerTest<WebTestT>::HasReceiverManagers(
195 NSArray* manager_classes) {
196 NSDictionary* receiver_managers =
197 [[WebTestT::webController_ jsInjectionReceiver] managers];
198 for (Class manager_class in manager_classes) {
199 if (![receiver_managers objectForKey:manager_class])
205 template <typename WebTestT>
206 void JsInjectionManagerTest<WebTestT>::TestAllDependencies(
207 NSArray* expected_classes,
209 EXPECT_EQ([expected_classes count], [actual count]);
211 for (Class manager_class in expected_classes) {
212 CRWJSInjectionManager* expected_manager = GetInstanceOfClass(manager_class);
213 EXPECT_TRUE([actual containsObject:expected_manager]);
216 for (size_t index = 0; index < [actual count]; ++ index) {
217 CRWJSInjectionManager* manager = [actual objectAtIndex:index];
218 for (Class manager_class in [manager directDependencies]) {
219 CRWJSInjectionManager* dependency = GetInstanceOfClass(manager_class);
220 size_t dependency_index = [actual indexOfObject:dependency];
221 EXPECT_TRUE(index > dependency_index);
226 template <typename WebTestT>
227 CRWJSInjectionManager* JsInjectionManagerTest<WebTestT>::GetInstanceOfClass(
228 Class jsInjectionManagerClass) {
229 return [[WebTestT::webController_ jsInjectionReceiver]
230 instanceOfClass:jsInjectionManagerClass];
233 WEB_TEST_F(JsInjectionManagerUIWebViewTest,
234 JsInjectionManagerWKWebViewTest,
236 NSUInteger originalCount =
237 [[[this->webController_ jsInjectionReceiver] managers] count];
238 CRWJSInjectionManager* manager =
239 this->GetInstanceOfClass([TestingCRWJSBaseManager class]);
240 EXPECT_TRUE(manager);
241 EXPECT_EQ(originalCount + 1U,
242 [[[this->webController_ jsInjectionReceiver] managers] count]);
243 EXPECT_TRUE(this->HasReceiverManagers(@[ [TestingCRWJSBaseManager class] ]));
244 EXPECT_FALSE([manager hasBeenInjected]);
247 EXPECT_TRUE([manager hasBeenInjected]);
250 WEB_TEST_F(JsInjectionManagerUIWebViewTest,
251 JsInjectionManagerWKWebViewTest,
253 NSUInteger originalCount =
254 [[[this->webController_ jsInjectionReceiver] managers] count];
255 CRWJSInjectionManager* manager =
256 this->GetInstanceOfClass([TestingJsManager class]);
257 EXPECT_TRUE(manager);
258 EXPECT_EQ(originalCount + 2U,
259 [[[this->webController_ jsInjectionReceiver] managers] count])
260 << "Two more CRWJSInjectionManagers should be created.";
261 EXPECT_TRUE(this->HasReceiverManagers(
262 @[ [TestingCRWJSBaseManager class], [TestingCRWJSBaseManager class] ]));
264 EXPECT_FALSE([manager hasBeenInjected]);
267 EXPECT_TRUE([manager hasBeenInjected]);
268 EXPECT_TRUE([this->GetInstanceOfClass([TestingCRWJSBaseManager class])
272 WEB_TEST_F(JsInjectionManagerUIWebViewTest,
273 JsInjectionManagerWKWebViewTest,
275 CRWJSInjectionManager* manager =
276 this->GetInstanceOfClass([TestingDynamicJsManager class]);
277 EXPECT_TRUE(manager);
279 EXPECT_FALSE([manager hasBeenInjected]);
281 EXPECT_TRUE([manager hasBeenInjected]);
282 // Ensure that content isn't cached.
283 EXPECT_NSNE([manager injectionContent], [manager injectionContent]);
286 WEB_TEST_F(JsInjectionManagerUIWebViewTest,
287 JsInjectionManagerWKWebViewTest,
288 HasNestedDependencies) {
289 NSUInteger originalCount =
290 [[[this->webController_ jsInjectionReceiver] managers] count];
291 CRWJSInjectionManager* manager =
292 this->GetInstanceOfClass([TestingJsManagerWithNestedDependencies class]);
293 EXPECT_TRUE(manager);
294 EXPECT_EQ(originalCount + 3U,
295 [[[this->webController_ jsInjectionReceiver] managers] count])
296 << "Three more CRWJSInjectionManagers should be created.";
297 EXPECT_TRUE(this->HasReceiverManagers(@[
298 [TestingJsManagerWithNestedDependencies class],
299 [TestingCRWJSBaseManager class],
300 [TestingCRWJSBaseManager class]
303 EXPECT_FALSE([manager hasBeenInjected]);
306 EXPECT_TRUE([manager hasBeenInjected]);
308 [this->GetInstanceOfClass([TestingJsManager class]) hasBeenInjected]);
309 EXPECT_TRUE([this->GetInstanceOfClass([TestingCRWJSBaseManager class])
312 NSArray* list = [manager allDependencies];
313 this->TestAllDependencies(
315 [TestingCRWJSBaseManager class],
316 [TestingJsManager class],
317 [TestingJsManagerWithNestedDependencies class]
322 // Tests that checking for an uninjected presence beacon returns false.
323 WEB_TEST_F(JsInjectionManagerUIWebViewTest,
324 JsInjectionManagerWKWebViewTest,
325 WebControllerCheckForUninjectedScript) {
326 EXPECT_FALSE([this->webController_
327 scriptHasBeenInjectedForClass:Nil
328 presenceBeacon:@"__gCrWeb.dummyBeacon"]);
331 WEB_TEST_F(JsInjectionManagerUIWebViewTest,
332 JsInjectionManagerWKWebViewTest,
334 CRWJSInjectionManager* manager =
335 this->GetInstanceOfClass([TestingJsManagerComplex class]);
336 NSArray* list = [manager allDependencies];
337 this->TestAllDependencies(
339 [TestingCRWJSBaseManager class],
340 [TestingAnotherCRWJSBaseManager class],
341 [TestingJsManager class],
342 [TestingAnotherJsManager class],
343 [TestingJsManagerWithNestedDependencies class],
344 [TestingJsManagerComplex class]