| // Copyright 2017 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. |
| |
| #include "third_party/blink/renderer/core/loader/modulescript/module_script_loader.h" |
| |
| #include "base/test/scoped_feature_list.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "third_party/blink/public/common/tokens/tokens.h" |
| #include "third_party/blink/public/platform/platform.h" |
| #include "third_party/blink/public/platform/task_type.h" |
| #include "third_party/blink/public/platform/web_url_loader_mock_factory.h" |
| #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h" |
| #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h" |
| #include "third_party/blink/renderer/core/dom/document.h" |
| #include "third_party/blink/renderer/core/frame/local_frame.h" |
| #include "third_party/blink/renderer/core/loader/modulescript/document_module_script_fetcher.h" |
| #include "third_party/blink/renderer/core/loader/modulescript/module_script_fetch_request.h" |
| #include "third_party/blink/renderer/core/loader/modulescript/module_script_loader_client.h" |
| #include "third_party/blink/renderer/core/loader/modulescript/module_script_loader_registry.h" |
| #include "third_party/blink/renderer/core/loader/modulescript/worklet_module_script_fetcher.h" |
| #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h" |
| #include "third_party/blink/renderer/core/script/modulator.h" |
| #include "third_party/blink/renderer/core/script/module_script.h" |
| #include "third_party/blink/renderer/core/script/script.h" |
| #include "third_party/blink/renderer/core/testing/dummy_modulator.h" |
| #include "third_party/blink/renderer/core/testing/page_test_base.h" |
| #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" |
| #include "third_party/blink/renderer/core/workers/worker_thread_test_helper.h" |
| #include "third_party/blink/renderer/core/workers/worklet_global_scope.h" |
| #include "third_party/blink/renderer/core/workers/worklet_global_scope_test_helper.h" |
| #include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h" |
| #include "third_party/blink/renderer/platform/heap/handle.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/fetch_client_settings_object_snapshot.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h" |
| #include "third_party/blink/renderer/platform/loader/testing/fetch_testing_platform_support.h" |
| #include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h" |
| #include "third_party/blink/renderer/platform/loader/testing/test_loader_factory.h" |
| #include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h" |
| #include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h" |
| #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" |
| #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h" |
| #include "third_party/blink/renderer/platform/testing/url_test_helpers.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| class TestModuleScriptLoaderClient final |
| : public GarbageCollected<TestModuleScriptLoaderClient>, |
| public ModuleScriptLoaderClient { |
| public: |
| TestModuleScriptLoaderClient() = default; |
| ~TestModuleScriptLoaderClient() override = default; |
| |
| void Trace(Visitor* visitor) const override { |
| visitor->Trace(module_script_); |
| } |
| |
| void NotifyNewSingleModuleFinished(ModuleScript* module_script) override { |
| was_notify_finished_ = true; |
| module_script_ = module_script; |
| } |
| |
| bool WasNotifyFinished() const { return was_notify_finished_; } |
| ModuleScript* GetModuleScript() { return module_script_; } |
| |
| private: |
| bool was_notify_finished_ = false; |
| Member<ModuleScript> module_script_; |
| }; |
| |
| class ModuleScriptLoaderTestModulator final : public DummyModulator { |
| public: |
| explicit ModuleScriptLoaderTestModulator(ScriptState* script_state) |
| : script_state_(script_state) {} |
| |
| ~ModuleScriptLoaderTestModulator() override = default; |
| |
| KURL ResolveModuleSpecifier(const String& module_request, |
| const KURL& base_url, |
| String* failure_reason) final { |
| return KURL(base_url, module_request); |
| } |
| |
| ScriptState* GetScriptState() override { return script_state_; } |
| |
| void SetModuleRequests(const Vector<String>& requests) { |
| requests_.clear(); |
| for (const String& request : requests) { |
| requests_.emplace_back(request, TextPosition::MinimumPosition(), |
| Vector<ImportAssertion>()); |
| } |
| } |
| Vector<ModuleRequest> ModuleRequestsFromModuleRecord( |
| v8::Local<v8::Module>) override { |
| return requests_; |
| } |
| |
| ModuleScriptFetcher* CreateModuleScriptFetcher( |
| ModuleScriptCustomFetchType custom_fetch_type, |
| base::PassKey<ModuleScriptLoader> pass_key) override { |
| auto* execution_context = ExecutionContext::From(script_state_); |
| if (auto* scope = DynamicTo<WorkletGlobalScope>(execution_context)) { |
| EXPECT_EQ(ModuleScriptCustomFetchType::kWorkletAddModule, |
| custom_fetch_type); |
| return MakeGarbageCollected<WorkletModuleScriptFetcher>( |
| scope->GetModuleResponsesMap(), pass_key); |
| } |
| EXPECT_EQ(ModuleScriptCustomFetchType::kNone, custom_fetch_type); |
| return MakeGarbageCollected<DocumentModuleScriptFetcher>(pass_key); |
| } |
| |
| void Trace(Visitor*) const override; |
| |
| private: |
| Member<ScriptState> script_state_; |
| Vector<ModuleRequest> requests_; |
| }; |
| |
| void ModuleScriptLoaderTestModulator::Trace(Visitor* visitor) const { |
| visitor->Trace(script_state_); |
| DummyModulator::Trace(visitor); |
| } |
| |
| } // namespace |
| |
| class ModuleScriptLoaderTest : public PageTestBase { |
| DISALLOW_COPY_AND_ASSIGN(ModuleScriptLoaderTest); |
| |
| public: |
| ModuleScriptLoaderTest(); |
| void SetUp() override; |
| |
| void InitializeForDocument(); |
| void InitializeForWorklet(); |
| |
| void TestFetchDataURL(ModuleScriptCustomFetchType, |
| TestModuleScriptLoaderClient*); |
| void TestInvalidSpecifier(ModuleScriptCustomFetchType, |
| TestModuleScriptLoaderClient*); |
| void TestFetchInvalidURL(ModuleScriptCustomFetchType, |
| TestModuleScriptLoaderClient*); |
| void TestFetchURL(ModuleScriptCustomFetchType, TestModuleScriptLoaderClient*); |
| void TestFetchDataURLJSONModule(ModuleScriptCustomFetchType custom_fetch_type, |
| TestModuleScriptLoaderClient* client); |
| void TestFetchDataURLInvalidJSONModule( |
| ModuleScriptCustomFetchType custom_fetch_type, |
| TestModuleScriptLoaderClient* client); |
| |
| ModuleScriptLoaderTestModulator* GetModulator() { return modulator_.Get(); } |
| |
| void RunUntilIdle() { |
| static_cast<scheduler::FakeTaskRunner*>(fetcher_->GetTaskRunner().get()) |
| ->RunUntilIdle(); |
| } |
| |
| private: |
| const base::TickClock* GetTickClock() override { |
| return platform_->test_task_runner()->GetMockTickClock(); |
| } |
| base::test::ScopedFeatureList scoped_feature_list_; |
| |
| protected: |
| const KURL url_; |
| const scoped_refptr<const SecurityOrigin> security_origin_; |
| |
| Persistent<ResourceFetcher> fetcher_; |
| |
| ScopedTestingPlatformSupport<FetchTestingPlatformSupport> platform_; |
| std::unique_ptr<MockWorkerReportingProxy> reporting_proxy_; |
| Persistent<ModuleScriptLoaderTestModulator> modulator_; |
| Persistent<WorkletGlobalScope> global_scope_; |
| }; |
| |
| void ModuleScriptLoaderTest::SetUp() { |
| PageTestBase::SetUp(IntSize(500, 500)); |
| } |
| |
| ModuleScriptLoaderTest::ModuleScriptLoaderTest() |
| : url_("https://example.test"), |
| security_origin_(SecurityOrigin::Create(url_)) { |
| scoped_feature_list_.InitAndEnableFeature(blink::features::kJSONModules); |
| platform_->AdvanceClockSeconds(1.); // For non-zero DocumentParserTimings |
| } |
| |
| void ModuleScriptLoaderTest::InitializeForDocument() { |
| auto* fetch_context = MakeGarbageCollected<MockFetchContext>(); |
| auto* properties = |
| MakeGarbageCollected<TestResourceFetcherProperties>(security_origin_); |
| fetcher_ = MakeGarbageCollected<ResourceFetcher>( |
| ResourceFetcherInit(properties->MakeDetachable(), fetch_context, |
| base::MakeRefCounted<scheduler::FakeTaskRunner>(), |
| base::MakeRefCounted<scheduler::FakeTaskRunner>(), |
| MakeGarbageCollected<TestLoaderFactory>( |
| platform_->GetURLLoaderMockFactory()), |
| MakeGarbageCollected<MockContextLifecycleNotifier>(), |
| nullptr /* back_forward_cache_loader_helper */)); |
| modulator_ = MakeGarbageCollected<ModuleScriptLoaderTestModulator>( |
| ToScriptStateForMainWorld(&GetFrame())); |
| } |
| |
| void ModuleScriptLoaderTest::InitializeForWorklet() { |
| auto* fetch_context = MakeGarbageCollected<MockFetchContext>(); |
| auto* properties = |
| MakeGarbageCollected<TestResourceFetcherProperties>(security_origin_); |
| fetcher_ = MakeGarbageCollected<ResourceFetcher>( |
| ResourceFetcherInit(properties->MakeDetachable(), fetch_context, |
| base::MakeRefCounted<scheduler::FakeTaskRunner>(), |
| base::MakeRefCounted<scheduler::FakeTaskRunner>(), |
| MakeGarbageCollected<TestLoaderFactory>( |
| platform_->GetURLLoaderMockFactory()), |
| MakeGarbageCollected<MockContextLifecycleNotifier>(), |
| nullptr /* back_forward_cache_loader_helper */)); |
| reporting_proxy_ = std::make_unique<MockWorkerReportingProxy>(); |
| auto creation_params = std::make_unique<GlobalScopeCreationParams>( |
| url_, mojom::blink::ScriptType::kModule, "GlobalScopeName", "UserAgent", |
| UserAgentMetadata(), nullptr /* web_worker_fetch_context */, |
| Vector<network::mojom::blink::ContentSecurityPolicyPtr>(), |
| network::mojom::ReferrerPolicy::kDefault, security_origin_.get(), |
| true /* is_secure_context */, HttpsState::kModern, |
| nullptr /* worker_clients */, nullptr /* content_settings_client */, |
| network::mojom::IPAddressSpace::kLocal, nullptr /* origin_trial_token */, |
| base::UnguessableToken::Create(), nullptr /* worker_settings */, |
| mojom::blink::V8CacheOptions::kDefault, |
| MakeGarbageCollected<WorkletModuleResponsesMap>(), |
| mojo::NullRemote() /* browser_interface_broker */, |
| BeginFrameProviderParams(), nullptr /* parent_feature_policy */, |
| base::UnguessableToken::Create() /* agent_cluster_id */); |
| creation_params->parent_context_token = GetFrame().GetLocalFrameToken(); |
| global_scope_ = MakeGarbageCollected<FakeWorkletGlobalScope>( |
| std::move(creation_params), *reporting_proxy_, &GetFrame(), |
| false /* create_microtask_queue */); |
| global_scope_->ScriptController()->Initialize(NullURL()); |
| modulator_ = MakeGarbageCollected<ModuleScriptLoaderTestModulator>( |
| global_scope_->ScriptController()->GetScriptState()); |
| } |
| // TODO(nhiroki): Add tests for workers. |
| |
| void ModuleScriptLoaderTest::TestFetchDataURL( |
| ModuleScriptCustomFetchType custom_fetch_type, |
| TestModuleScriptLoaderClient* client) { |
| auto* registry = MakeGarbageCollected<ModuleScriptLoaderRegistry>(); |
| KURL url("data:text/javascript,export default 'grapes';"); |
| ModuleScriptLoader::Fetch( |
| ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript), |
| fetcher_, ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), |
| custom_fetch_type, registry, client); |
| } |
| |
| void ModuleScriptLoaderTest::TestFetchDataURLJSONModule( |
| ModuleScriptCustomFetchType custom_fetch_type, |
| TestModuleScriptLoaderClient* client) { |
| auto* registry = MakeGarbageCollected<ModuleScriptLoaderRegistry>(); |
| KURL url( |
| "data:application/" |
| "json,{\"1\":{\"name\":\"MIKE\",\"surname\":\"TAYLOR\"},\"2\":{\"name\":" |
| "\"TOM\",\"surname\":\"JERRY\"}}"); |
| ModuleScriptLoader::Fetch( |
| ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJSON), fetcher_, |
| ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), custom_fetch_type, |
| registry, client); |
| } |
| |
| void ModuleScriptLoaderTest::TestFetchDataURLInvalidJSONModule( |
| ModuleScriptCustomFetchType custom_fetch_type, |
| TestModuleScriptLoaderClient* client) { |
| auto* registry = MakeGarbageCollected<ModuleScriptLoaderRegistry>(); |
| KURL url( |
| "data:application/" |
| "json,{{{"); |
| ModuleScriptLoader::Fetch( |
| ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJSON), fetcher_, |
| ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), custom_fetch_type, |
| registry, client); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, FetchDataURL) { |
| InitializeForDocument(); |
| TestModuleScriptLoaderClient* client = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchDataURL(ModuleScriptCustomFetchType::kNone, client); |
| |
| // TODO(leszeks): This should finish synchronously, but currently due |
| // to the script resource/script streamer interaction, it does not. |
| RunUntilIdle(); |
| EXPECT_TRUE(client->WasNotifyFinished()); |
| ASSERT_TRUE(client->GetModuleScript()); |
| EXPECT_FALSE(client->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_FALSE(client->GetModuleScript()->HasParseError()); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, FetchDataURLJSONModule) { |
| InitializeForDocument(); |
| TestModuleScriptLoaderClient* client = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchDataURLJSONModule(ModuleScriptCustomFetchType::kNone, client); |
| |
| // TODO(leszeks): This should finish synchronously, but currently due |
| // to the script resource/script streamer interaction, it does not. |
| RunUntilIdle(); |
| EXPECT_TRUE(client->WasNotifyFinished()); |
| ASSERT_TRUE(client->GetModuleScript()); |
| EXPECT_FALSE(client->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_FALSE(client->GetModuleScript()->HasParseError()); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, FetchDataURLInvalidJSONModule) { |
| InitializeForDocument(); |
| TestModuleScriptLoaderClient* client = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchDataURLInvalidJSONModule(ModuleScriptCustomFetchType::kNone, client); |
| |
| // TODO(leszeks): This should finish synchronously, but currently due |
| // to the script resource/script streamer interaction, it does not. |
| RunUntilIdle(); |
| EXPECT_TRUE(client->WasNotifyFinished()); |
| ASSERT_TRUE(client->GetModuleScript()); |
| EXPECT_TRUE(client->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_TRUE(client->GetModuleScript()->HasParseError()); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, FetchDataURL_OnWorklet) { |
| InitializeForWorklet(); |
| TestModuleScriptLoaderClient* client1 = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchDataURL(ModuleScriptCustomFetchType::kWorkletAddModule, client1); |
| |
| EXPECT_FALSE(client1->WasNotifyFinished()) |
| << "ModuleScriptLoader should finish asynchronously."; |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(client1->WasNotifyFinished()); |
| ASSERT_TRUE(client1->GetModuleScript()); |
| EXPECT_FALSE(client1->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_FALSE(client1->GetModuleScript()->HasParseError()); |
| |
| // Try to fetch the same URL again in order to verify the case where |
| // WorkletModuleResponsesMap serves a cache. |
| TestModuleScriptLoaderClient* client2 = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchDataURL(ModuleScriptCustomFetchType::kWorkletAddModule, client2); |
| |
| EXPECT_FALSE(client2->WasNotifyFinished()) |
| << "ModuleScriptLoader should finish asynchronously."; |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(client2->WasNotifyFinished()); |
| ASSERT_TRUE(client2->GetModuleScript()); |
| EXPECT_FALSE(client2->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_FALSE(client2->GetModuleScript()->HasParseError()); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, FetchDataURLJSONModule_OnWorklet) { |
| InitializeForWorklet(); |
| TestModuleScriptLoaderClient* client1 = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchDataURLJSONModule(ModuleScriptCustomFetchType::kWorkletAddModule, |
| client1); |
| |
| EXPECT_FALSE(client1->WasNotifyFinished()) |
| << "ModuleScriptLoader should finish asynchronously."; |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(client1->WasNotifyFinished()); |
| ASSERT_TRUE(client1->GetModuleScript()); |
| EXPECT_FALSE(client1->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_FALSE(client1->GetModuleScript()->HasParseError()); |
| |
| // Try to fetch the same URL again in order to verify the case where |
| // WorkletModuleResponsesMap serves a cache. |
| TestModuleScriptLoaderClient* client2 = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchDataURLJSONModule(ModuleScriptCustomFetchType::kWorkletAddModule, |
| client2); |
| |
| EXPECT_FALSE(client2->WasNotifyFinished()) |
| << "ModuleScriptLoader should finish asynchronously."; |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(client2->WasNotifyFinished()); |
| ASSERT_TRUE(client2->GetModuleScript()); |
| EXPECT_FALSE(client2->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_FALSE(client2->GetModuleScript()->HasParseError()); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, FetchDataURLInvalidJSONModule_OnWorklet) { |
| InitializeForWorklet(); |
| TestModuleScriptLoaderClient* client1 = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchDataURLInvalidJSONModule( |
| ModuleScriptCustomFetchType::kWorkletAddModule, client1); |
| |
| EXPECT_FALSE(client1->WasNotifyFinished()) |
| << "ModuleScriptLoader should finish asynchronously."; |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(client1->WasNotifyFinished()); |
| ASSERT_TRUE(client1->GetModuleScript()); |
| EXPECT_TRUE(client1->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_TRUE(client1->GetModuleScript()->HasParseError()); |
| |
| // Try to fetch the same URL again in order to verify the case where |
| // WorkletModuleResponsesMap serves a cache. |
| TestModuleScriptLoaderClient* client2 = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchDataURLInvalidJSONModule( |
| ModuleScriptCustomFetchType::kWorkletAddModule, client2); |
| |
| EXPECT_FALSE(client2->WasNotifyFinished()) |
| << "ModuleScriptLoader should finish asynchronously."; |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(client2->WasNotifyFinished()); |
| ASSERT_TRUE(client2->GetModuleScript()); |
| EXPECT_TRUE(client2->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_TRUE(client2->GetModuleScript()->HasParseError()); |
| } |
| |
| void ModuleScriptLoaderTest::TestInvalidSpecifier( |
| ModuleScriptCustomFetchType custom_fetch_type, |
| TestModuleScriptLoaderClient* client) { |
| auto* registry = MakeGarbageCollected<ModuleScriptLoaderRegistry>(); |
| KURL url("data:text/javascript,import 'invalid';export default 'grapes';"); |
| GetModulator()->SetModuleRequests({"invalid"}); |
| ModuleScriptLoader::Fetch( |
| ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript), |
| fetcher_, ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), |
| custom_fetch_type, registry, client); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, InvalidSpecifier) { |
| InitializeForDocument(); |
| TestModuleScriptLoaderClient* client = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestInvalidSpecifier(ModuleScriptCustomFetchType::kNone, client); |
| |
| // TODO(leszeks): This should finish synchronously, but currently due |
| // to the script resource/script streamer interaction, it does not. |
| RunUntilIdle(); |
| EXPECT_TRUE(client->WasNotifyFinished()); |
| |
| ASSERT_TRUE(client->GetModuleScript()); |
| EXPECT_TRUE(client->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_TRUE(client->GetModuleScript()->HasParseError()); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, InvalidSpecifier_OnWorklet) { |
| InitializeForWorklet(); |
| TestModuleScriptLoaderClient* client = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestInvalidSpecifier(ModuleScriptCustomFetchType::kWorkletAddModule, client); |
| |
| EXPECT_FALSE(client->WasNotifyFinished()) |
| << "ModuleScriptLoader should finish asynchronously."; |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(client->WasNotifyFinished()); |
| ASSERT_TRUE(client->GetModuleScript()); |
| EXPECT_TRUE(client->GetModuleScript()->HasEmptyRecord()); |
| EXPECT_TRUE(client->GetModuleScript()->HasParseError()); |
| } |
| |
| void ModuleScriptLoaderTest::TestFetchInvalidURL( |
| ModuleScriptCustomFetchType custom_fetch_type, |
| TestModuleScriptLoaderClient* client) { |
| auto* registry = MakeGarbageCollected<ModuleScriptLoaderRegistry>(); |
| KURL url; |
| EXPECT_FALSE(url.IsValid()); |
| ModuleScriptLoader::Fetch( |
| ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript), |
| fetcher_, ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), |
| custom_fetch_type, registry, client); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, FetchInvalidURL) { |
| InitializeForDocument(); |
| TestModuleScriptLoaderClient* client = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchInvalidURL(ModuleScriptCustomFetchType::kNone, client); |
| |
| // TODO(leszeks): This should finish synchronously, but currently due |
| // to the script resource/script streamer interaction, it does not. |
| RunUntilIdle(); |
| EXPECT_TRUE(client->WasNotifyFinished()); |
| EXPECT_FALSE(client->GetModuleScript()); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, FetchInvalidURL_OnWorklet) { |
| InitializeForWorklet(); |
| TestModuleScriptLoaderClient* client = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchInvalidURL(ModuleScriptCustomFetchType::kWorkletAddModule, client); |
| |
| EXPECT_FALSE(client->WasNotifyFinished()) |
| << "ModuleScriptLoader should finish asynchronously."; |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(client->WasNotifyFinished()); |
| EXPECT_FALSE(client->GetModuleScript()); |
| } |
| |
| void ModuleScriptLoaderTest::TestFetchURL( |
| ModuleScriptCustomFetchType custom_fetch_type, |
| TestModuleScriptLoaderClient* client) { |
| KURL url("https://example.test/module.js"); |
| url_test_helpers::RegisterMockedURLLoad( |
| url, test::CoreTestDataPath("module.js"), "text/javascript", |
| platform_->GetURLLoaderMockFactory()); |
| |
| auto* registry = MakeGarbageCollected<ModuleScriptLoaderRegistry>(); |
| ModuleScriptLoader::Fetch( |
| ModuleScriptFetchRequest::CreateForTest(url, ModuleType::kJavaScript), |
| fetcher_, ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), |
| custom_fetch_type, registry, client); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, FetchURL) { |
| InitializeForDocument(); |
| TestModuleScriptLoaderClient* client = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchURL(ModuleScriptCustomFetchType::kNone, client); |
| |
| EXPECT_FALSE(client->WasNotifyFinished()) |
| << "ModuleScriptLoader unexpectedly finished synchronously."; |
| platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); |
| // TODO(leszeks): This should finish synchronously, but currently due |
| // to the script resource/script streamer interaction, it does not. |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(client->WasNotifyFinished()); |
| EXPECT_TRUE(client->GetModuleScript()); |
| } |
| |
| TEST_F(ModuleScriptLoaderTest, FetchURL_OnWorklet) { |
| InitializeForWorklet(); |
| TestModuleScriptLoaderClient* client = |
| MakeGarbageCollected<TestModuleScriptLoaderClient>(); |
| TestFetchURL(ModuleScriptCustomFetchType::kWorkletAddModule, client); |
| |
| EXPECT_FALSE(client->WasNotifyFinished()) |
| << "ModuleScriptLoader unexpectedly finished synchronously."; |
| platform_->GetURLLoaderMockFactory()->ServeAsynchronousRequests(); |
| RunUntilIdle(); |
| |
| EXPECT_TRUE(client->WasNotifyFinished()); |
| EXPECT_TRUE(client->GetModuleScript()); |
| } |
| |
| } // namespace blink |