blob: d9f55487f9c2d35064e14e75eca2595bdba6342a [file] [log] [blame]
// Copyright 2021 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.
#import "ios/web/js_features/window_error/window_error_java_script_feature.h"
#include <memory>
#include "base/optional.h"
#include "base/test/ios/wait_util.h"
#import "ios/web/js_messaging/java_script_feature_manager.h"
#import "ios/web/public/test/web_test_with_web_state.h"
#include "testing/gtest_mac.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
using base::test::ios::WaitUntilConditionOrTimeout;
using base::test::ios::kWaitForJSCompletionTimeout;
namespace web {
class WindowErrorJavaScriptFeatureTest : public WebTestWithWebState {
protected:
WindowErrorJavaScriptFeatureTest()
: WebTestWithWebState(),
feature_(base::BindRepeating(
^(WindowErrorJavaScriptFeature::ErrorDetails error_details) {
error_details_ = error_details;
})) {}
void SetUp() override {
WebTestWithWebState::SetUp();
OverrideJavaScriptFeatures({&feature_});
}
base::Optional<WindowErrorJavaScriptFeature::ErrorDetails> error_details() {
return error_details_;
}
private:
WindowErrorJavaScriptFeature feature_;
base::Optional<WindowErrorJavaScriptFeature::ErrorDetails> error_details_;
};
// Tests that error details are received for a script error occurring in the
// head of the main frame.
TEST_F(WindowErrorJavaScriptFeatureTest, ReceiveErrorFromMainFramePageHead) {
ASSERT_FALSE(error_details());
NSString* html = @"<html><head>"
"<script>nonexistentFunction();</script>"
"</head><body></body></html>";
LoadHtml(html);
ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
return !!error_details();
}));
EXPECT_EQ(1, error_details()->line_number);
EXPECT_NSEQ(@"ReferenceError: Can't find variable: nonexistentFunction",
error_details()->message);
EXPECT_EQ("https://chromium.test/", error_details()->url.spec());
EXPECT_TRUE(error_details()->is_main_frame);
}
// Tests that error details are received for a script error occurring in the
// body of the main frame.
TEST_F(WindowErrorJavaScriptFeatureTest, ReceiveErrorFromMainFramePageBody) {
ASSERT_FALSE(error_details());
NSString* html = @"<html><body>"
"<script>nonexistentFunction();</script>"
"</body></html>";
LoadHtml(html);
ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
return !!error_details();
}));
EXPECT_EQ(1, error_details()->line_number);
EXPECT_NSEQ(@"ReferenceError: Can't find variable: nonexistentFunction",
error_details()->message);
EXPECT_EQ("https://chromium.test/", error_details()->url.spec());
EXPECT_TRUE(error_details()->is_main_frame);
}
// Tests that error details are received for a script error occurring in the
// head of an iframe.
TEST_F(WindowErrorJavaScriptFeatureTest, ReceiveErrorFromIframePageHead) {
ASSERT_FALSE(error_details());
NSString* html = @"<html><body>"
"<iframe "
"srcdoc='<html><head><script>nonexistentFunction();</"
"script></head></html>'/>"
"</body></html>";
LoadHtml(html);
ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
return !!error_details();
}));
EXPECT_EQ(0, error_details()->line_number);
EXPECT_NSEQ(@"Script error.", error_details()->message);
EXPECT_EQ("about:srcdoc", error_details()->url.spec());
EXPECT_FALSE(error_details()->is_main_frame);
}
// Tests that error details are received for a script error occurring in the
// body of an iframe.
TEST_F(WindowErrorJavaScriptFeatureTest, ReceiveErrorFromIframePageBody) {
ASSERT_FALSE(error_details());
NSString* html = @"<html><body>"
"<iframe "
"srcdoc='<html><body><script>nonexistentFunction();</"
"script></body></html>'/>"
"</body></html>";
LoadHtml(html);
ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
return !!error_details();
}));
EXPECT_EQ(0, error_details()->line_number);
EXPECT_NSEQ(@"Script error.", error_details()->message);
EXPECT_EQ("about:srcdoc", error_details()->url.spec());
EXPECT_FALSE(error_details()->is_main_frame);
}
// Ensures that error details are still retreived after a document is recreated.
// (Since event listeners are removed and need to be reinjected after a set of
// calls to document.open/write/close.)
TEST_F(WindowErrorJavaScriptFeatureTest, ReceiveErrorAfterDocumentRecreated) {
ASSERT_FALSE(error_details());
LoadHtml(@"<html></html>");
ASSERT_TRUE(ExecuteJavaScript(
@"document.open(); document.write('<p></p>'); document.close(); true;"));
ExecuteJavaScript(@"nonexistentFunction();");
ASSERT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
return !!error_details();
}));
EXPECT_EQ(1, error_details()->line_number);
EXPECT_NSEQ(@"ReferenceError: Can't find variable: nonexistentFunction",
error_details()->message);
EXPECT_EQ("https://chromium.test/", error_details()->url.spec());
EXPECT_TRUE(error_details()->is_main_frame);
}
} // namespace web