blob: e3d8b1d85c65b35ace0f2f3382fe1cb4488a6b9c [file] [log] [blame]
// Copyright 2018 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 "components/autofill/ios/form_util/form_activity_tab_helper.h"
#import "base/test/ios/wait_util.h"
#import "components/autofill/ios/form_util/form_activity_observer.h"
#import "components/autofill/ios/form_util/test_form_activity_observer.h"
#import "ios/web/public/test/fakes/test_web_client.h"
#import "ios/web/public/test/fakes/test_web_state_observer_util.h"
#import "ios/web/public/test/js_test_util.h"
#import "ios/web/public/test/web_js_test.h"
#import "ios/web/public/test/web_test_with_web_state.h"
#include "ios/web/public/web_state/web_frame.h"
#include "ios/web/public/web_state/web_frame_util.h"
#import "ios/web/public/web_state/web_frames_manager.h"
#include "testing/platform_test.h"
class FormTestClient : public web::TestWebClient {
public:
NSString* GetDocumentStartScriptForAllFrames(
web::BrowserState* browser_state) const override {
return web::test::GetPageScript(@"form_util_js");
}
};
// Tests fixture for autofill::FormActivityTabHelper class.
class FormActivityTabHelperTest
: public web::WebJsTest<web::WebTestWithWebState> {
public:
FormActivityTabHelperTest()
: web::WebJsTest<web::WebTestWithWebState>(
std::make_unique<FormTestClient>()) {}
void SetUp() override {
web::WebJsTest<web::WebTestWithWebState>::SetUp();
autofill::FormActivityTabHelper* tab_helper =
autofill::FormActivityTabHelper::GetOrCreateForWebState(web_state());
observer_ =
std::make_unique<autofill::TestFormActivityObserver>(web_state());
tab_helper->AddObserver(observer_.get());
}
void TearDown() override {
autofill::FormActivityTabHelper* tab_helper =
autofill::FormActivityTabHelper::GetOrCreateForWebState(web_state());
tab_helper->RemoveObserver(observer_.get());
web::WebJsTest<web::WebTestWithWebState>::TearDown();
}
protected:
std::unique_ptr<autofill::TestFormActivityObserver> observer_;
};
// Tests that observer is called on form submission using submit control.
TEST_F(FormActivityTabHelperTest, TestObserverDocumentSubmitted) {
LoadHtmlAndInject(
@"<form name='form-name'>"
"<input type='submit' id='submit'/>"
"</form>");
ASSERT_FALSE(observer_->submit_document_info());
const std::string kTestFormName("form-name");
const std::string kTestFormData(
"[{\"name\":\"form-name\",\"origin\":\"https://chromium.test/"
"\",\"action\":\"https://chromium.test/\","
"\"name_attribute\":\"form-name\",\"id_attribute\":\"\"}]");
bool has_user_gesture = false;
bool form_in_main_frame = true;
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForJSCompletionTimeout, ^bool {
return web::GetMainWebFrame(web_state()) != nullptr;
}));
web::WebFrame* main_frame = web::GetMainWebFrame(web_state());
ExecuteJavaScript(@"document.getElementById('submit').click();");
ASSERT_TRUE(observer_->submit_document_info());
EXPECT_EQ(web_state(), observer_->submit_document_info()->web_state);
EXPECT_EQ(main_frame, observer_->submit_document_info()->sender_frame);
EXPECT_EQ(kTestFormName, observer_->submit_document_info()->form_name);
EXPECT_EQ(kTestFormData, observer_->submit_document_info()->form_data);
EXPECT_EQ(has_user_gesture,
observer_->submit_document_info()->has_user_gesture);
EXPECT_EQ(form_in_main_frame,
observer_->submit_document_info()->form_in_main_frame);
}
// Tests that observer is called on form submission using submit() method.
TEST_F(FormActivityTabHelperTest, TestFormSubmittedHook) {
LoadHtmlAndInject(
@"<form name='form-name' id='form'>"
"<input type='submit'/>"
"</form>");
ASSERT_FALSE(observer_->submit_document_info());
const std::string kTestFormName("form-name");
const std::string kTestFormData(
"[{\"name\":\"form-name\",\"origin\":\"https://chromium.test/"
"\",\"action\":\"https://chromium.test/\","
"\"name_attribute\":\"form-name\",\"id_attribute\":\"form\"}]");
bool has_user_gesture = false;
bool form_in_main_frame = true;
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForJSCompletionTimeout, ^bool {
return web::GetMainWebFrame(web_state()) != nullptr;
}));
web::WebFrame* main_frame = web::GetMainWebFrame(web_state());
ExecuteJavaScript(@"document.getElementById('form').submit();");
ASSERT_TRUE(observer_->submit_document_info());
EXPECT_EQ(web_state(), observer_->submit_document_info()->web_state);
EXPECT_EQ(main_frame, observer_->submit_document_info()->sender_frame);
EXPECT_EQ(kTestFormName, observer_->submit_document_info()->form_name);
EXPECT_EQ(kTestFormData, observer_->submit_document_info()->form_data);
EXPECT_EQ(has_user_gesture,
observer_->submit_document_info()->has_user_gesture);
EXPECT_EQ(form_in_main_frame,
observer_->submit_document_info()->form_in_main_frame);
}
// Tests that observer is called on form activity (input event).
TEST_F(FormActivityTabHelperTest, TestObserverFormActivityFrameMessaging) {
LoadHtmlAndInject(
@"<form name='form-name'>"
"<input type='input' name='field-name' id='fieldid'/>"
"</form>");
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForJSCompletionTimeout, ^bool {
return web::GetMainWebFrame(web_state()) != nullptr;
}));
web::WebFrame* main_frame = web::GetMainWebFrame(web_state());
ASSERT_FALSE(observer_->form_activity_info());
// First call will set document.activeElement (which is usually set by user
// action. Second call will trigger the message.
ExecuteJavaScript(@"document.getElementById('fieldid').focus();");
ASSERT_FALSE(observer_->form_activity_info());
ExecuteJavaScript(@"document.getElementById('fieldid').focus();");
EXPECT_TRUE(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForJSCompletionTimeout, ^bool {
return observer_->form_activity_info() != nullptr;
}));
EXPECT_EQ(web_state(), observer_->form_activity_info()->web_state);
EXPECT_EQ(main_frame, observer_->form_activity_info()->sender_frame);
EXPECT_EQ("form-name",
observer_->form_activity_info()->form_activity.form_name);
EXPECT_EQ("text", observer_->form_activity_info()->form_activity.field_type);
EXPECT_EQ("focus", observer_->form_activity_info()->form_activity.type);
EXPECT_EQ("", observer_->form_activity_info()->form_activity.value);
EXPECT_FALSE(observer_->form_activity_info()->form_activity.input_missing);
EXPECT_TRUE(observer_->form_activity_info()->form_activity.is_main_frame);
EXPECT_TRUE(observer_->form_activity_info()->form_activity.has_user_gesture);
}