Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2017 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 "core/loader/modulescript/ModuleTreeLinker.h" | |
| 6 | |
| 7 #include "bindings/core/v8/ScriptModule.h" | |
| 8 #include "bindings/core/v8/ScriptState.h" | |
| 9 #include "bindings/core/v8/V8Binding.h" | |
| 10 #include "bindings/core/v8/V8BindingForTesting.h" | |
| 11 #include "bindings/core/v8/V8ThrowException.h" | |
| 12 #include "core/dom/Modulator.h" | |
| 13 #include "core/dom/ModuleScript.h" | |
| 14 #include "core/loader/modulescript/ModuleScriptFetchRequest.h" | |
| 15 #include "core/loader/modulescript/ModuleTreeLinkerRegistry.h" | |
| 16 #include "core/testing/DummyModulator.h" | |
| 17 #include "core/testing/DummyPageHolder.h" | |
| 18 #include "platform/heap/Handle.h" | |
| 19 #include "platform/weborigin/KURL.h" | |
| 20 #include "platform/wtf/text/StringBuilder.h" | |
| 21 #include "public/platform/Platform.h" | |
| 22 #include "public/platform/scheduler/renderer/renderer_scheduler.h" | |
| 23 #include "testing/gtest/include/gtest/gtest.h" | |
| 24 | |
| 25 namespace blink { | |
| 26 | |
| 27 namespace { | |
| 28 | |
| 29 class TestModuleTreeClient final | |
| 30 : public GarbageCollectedFinalized<TestModuleTreeClient>, | |
| 31 public ModuleTreeClient { | |
| 32 USING_GARBAGE_COLLECTED_MIXIN(TestModuleTreeClient); | |
| 33 | |
| 34 public: | |
| 35 TestModuleTreeClient() = default; | |
| 36 | |
| 37 DEFINE_INLINE_TRACE() { visitor->Trace(module_script_); } | |
| 38 | |
| 39 void NotifyModuleTreeLoadFinished(ModuleScript* module_script) override { | |
| 40 was_notify_finished_ = true; | |
| 41 module_script_ = module_script; | |
| 42 } | |
| 43 | |
| 44 bool WasNotifyFinished() const { return was_notify_finished_; } | |
| 45 ModuleScript* GetModuleScript() { return module_script_; } | |
| 46 | |
| 47 private: | |
| 48 bool was_notify_finished_ = false; | |
| 49 Member<ModuleScript> module_script_; | |
| 50 }; | |
| 51 | |
| 52 class ModuleTreeLinkerTestModulator final : public DummyModulator { | |
| 53 public: | |
| 54 ModuleTreeLinkerTestModulator(RefPtr<ScriptState> script_state) | |
| 55 : script_state_(std::move(script_state)) {} | |
| 56 ~ModuleTreeLinkerTestModulator() override {} | |
| 57 | |
| 58 DECLARE_TRACE(); | |
| 59 | |
| 60 enum class ResolveResult { kFailure, kSuccess }; | |
| 61 | |
| 62 // Resolve last |Modulator::FetchSingle()| call. | |
| 63 ModuleScript* ResolveSingleModuleScriptFetch( | |
| 64 const KURL& url, | |
| 65 const Vector<String>& dependency_module_requests) { | |
| 66 ScriptState::Scope scope(script_state_.Get()); | |
| 67 | |
| 68 StringBuilder source_text; | |
| 69 for (const auto& request : dependency_module_requests) { | |
| 70 source_text.Append("import '"); | |
| 71 source_text.Append(request); | |
| 72 source_text.Append("';\n"); | |
| 73 } | |
| 74 source_text.Append("export default 'grapes';"); | |
| 75 | |
| 76 ScriptModule script_module = ScriptModule::Compile( | |
| 77 script_state_->GetIsolate(), source_text.ToString(), url.GetString(), | |
| 78 kSharableCrossOrigin); | |
| 79 ModuleScript* module_script = | |
| 80 ModuleScript::Create(this, script_module, url, "", kParserInserted, | |
| 81 WebURLRequest::kFetchCredentialsModeOmit); | |
| 82 auto result_request = dependency_module_requests_map_.insert( | |
| 83 script_module, dependency_module_requests); | |
| 84 EXPECT_TRUE(result_request.is_new_entry); | |
| 85 auto result_map = module_map_.insert(url, module_script); | |
| 86 EXPECT_TRUE(result_map.is_new_entry); | |
| 87 | |
| 88 EXPECT_EQ(url, pending_request_url_); | |
| 89 EXPECT_TRUE(pending_client_); | |
| 90 pending_client_->NotifyModuleLoadFinished(module_script); | |
| 91 pending_client_.Clear(); | |
| 92 | |
| 93 return module_script; | |
| 94 } | |
| 95 | |
| 96 // Get AncestorList specified in |Modulator::FetchTreeInternal()| call for | |
| 97 // request matching |url|. | |
| 98 AncestorList GetAncestorListForTreeFetch(const KURL& url) const { | |
| 99 const auto& it = pending_tree_ancestor_list_.Find(url); | |
| 100 if (it == pending_tree_ancestor_list_.end()) | |
| 101 return AncestorList(); | |
| 102 return it->value; | |
| 103 } | |
| 104 | |
| 105 // Resolve |Modulator::FetchTreeInternal()| for given url. | |
| 106 void ResolveDependentTreeFetch(const KURL& url, ResolveResult result) { | |
| 107 const auto& it = pending_tree_client_map_.Find(url); | |
| 108 EXPECT_NE(pending_tree_client_map_.end(), it); | |
| 109 auto pending_client = it->value; | |
| 110 EXPECT_TRUE(pending_client); | |
| 111 pending_tree_client_map_.erase(it); | |
| 112 | |
| 113 if (result == ResolveResult::kFailure) { | |
| 114 pending_client->NotifyModuleTreeLoadFinished(nullptr); | |
| 115 return; | |
| 116 } | |
| 117 EXPECT_EQ(ResolveResult::kSuccess, result); | |
| 118 | |
| 119 ScriptState::Scope scope(script_state_.Get()); | |
| 120 | |
| 121 ScriptModule script_module = ScriptModule::Compile( | |
| 122 script_state_->GetIsolate(), "export default 'pineapples';", | |
| 123 url.GetString(), kSharableCrossOrigin); | |
| 124 ModuleScript* module_script = | |
| 125 ModuleScript::Create(this, script_module, url, "", kParserInserted, | |
| 126 WebURLRequest::kFetchCredentialsModeOmit); | |
| 127 auto result_map = module_map_.insert(url, module_script); | |
| 128 EXPECT_TRUE(result_map.is_new_entry); | |
| 129 | |
| 130 pending_client->NotifyModuleTreeLoadFinished(module_script); | |
| 131 } | |
| 132 | |
| 133 void SetInstantiateShouldFail(bool b) { instantiate_should_fail_ = b; } | |
| 134 | |
| 135 private: | |
| 136 // Implements Modulator: | |
| 137 | |
| 138 void FetchSingle(const ModuleScriptFetchRequest& request, | |
| 139 ModuleGraphLevel, | |
| 140 SingleModuleClient* client) override { | |
| 141 pending_request_url_ = request.Url(); | |
| 142 EXPECT_FALSE(pending_client_); | |
| 143 pending_client_ = client; | |
| 144 } | |
| 145 | |
| 146 void FetchTreeInternal(const ModuleScriptFetchRequest& request, | |
| 147 const AncestorList& list, | |
| 148 ModuleGraphLevel level, | |
| 149 ModuleTreeClient* client) override { | |
| 150 const auto& url = request.Url(); | |
| 151 | |
| 152 auto ancestor_result = pending_tree_ancestor_list_.insert(url, list); | |
| 153 EXPECT_TRUE(ancestor_result.is_new_entry); | |
| 154 | |
| 155 EXPECT_EQ(ModuleGraphLevel::kDependentModuleFetch, level); | |
| 156 | |
| 157 auto result_map = pending_tree_client_map_.insert(url, client); | |
| 158 EXPECT_TRUE(result_map.is_new_entry); | |
| 159 } | |
| 160 | |
| 161 ModuleScript* GetFetchedModuleScript(const KURL& url) override { | |
| 162 const auto& it = module_map_.Find(url); | |
| 163 if (it == module_map_.end()) | |
| 164 return nullptr; | |
| 165 | |
| 166 return it->value; | |
| 167 } | |
| 168 | |
| 169 ScriptValue InstantiateModule(ScriptModule) override { | |
| 170 if (instantiate_should_fail_) { | |
| 171 ScriptState::Scope scope(script_state_.Get()); | |
| 172 v8::Local<v8::Value> error = V8ThrowException::CreateError( | |
| 173 script_state_->GetIsolate(), "Instantiation failure."); | |
| 174 return ScriptValue(script_state_.Get(), error); | |
| 175 } | |
| 176 return ScriptValue(); | |
| 177 } | |
| 178 | |
| 179 Vector<String> ModuleRequestsFromScriptModule( | |
| 180 ScriptModule script_module) override { | |
| 181 const auto& it = dependency_module_requests_map_.Find(script_module); | |
| 182 if (it == dependency_module_requests_map_.end()) | |
| 183 return Vector<String>(); | |
| 184 | |
| 185 return it->value; | |
| 186 } | |
| 187 | |
| 188 RefPtr<ScriptState> script_state_; | |
| 189 KURL pending_request_url_; | |
| 190 Member<SingleModuleClient> pending_client_; | |
| 191 HashMap<ScriptModule, Vector<String>> dependency_module_requests_map_; | |
| 192 HeapHashMap<KURL, Member<ModuleScript>> module_map_; | |
| 193 HeapHashMap<KURL, Member<ModuleTreeClient>> pending_tree_client_map_; | |
| 194 HashMap<KURL, AncestorList> pending_tree_ancestor_list_; | |
| 195 bool instantiate_should_fail_ = false; | |
| 196 }; | |
| 197 | |
| 198 DEFINE_TRACE(ModuleTreeLinkerTestModulator) { | |
| 199 visitor->Trace(pending_client_); | |
| 200 visitor->Trace(module_map_); | |
| 201 visitor->Trace(pending_tree_client_map_); | |
| 202 DummyModulator::Trace(visitor); | |
| 203 } | |
| 204 | |
| 205 } // namespace | |
| 206 | |
| 207 class ModuleTreeLinkerTest : public ::testing::Test { | |
| 208 DISALLOW_COPY_AND_ASSIGN(ModuleTreeLinkerTest); | |
| 209 | |
| 210 public: | |
| 211 ModuleTreeLinkerTest() = default; | |
| 212 void SetUp() override; | |
| 213 | |
| 214 ModuleTreeLinkerTestModulator* GetModulator() { return modulator_.Get(); } | |
| 215 | |
| 216 protected: | |
| 217 std::unique_ptr<DummyPageHolder> dummy_page_holder_; | |
| 218 Persistent<ModuleTreeLinkerTestModulator> modulator_; | |
| 219 }; | |
| 220 | |
| 221 void ModuleTreeLinkerTest::SetUp() { | |
| 222 dummy_page_holder_ = DummyPageHolder::Create(IntSize(500, 500)); | |
| 223 RefPtr<ScriptState> script_state = | |
| 224 ToScriptStateForMainWorld(&dummy_page_holder_->GetFrame()); | |
| 225 modulator_ = new ModuleTreeLinkerTestModulator(script_state); | |
| 226 } | |
| 227 | |
| 228 TEST_F(ModuleTreeLinkerTest, fetchTreeNoDeps) { | |
| 229 ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); | |
| 230 | |
| 231 KURL url(kParsedURLString, "http://example.com/root.js"); | |
| 232 ModuleScriptFetchRequest module_request( | |
| 233 url, String(), kParserInserted, WebURLRequest::kFetchCredentialsModeOmit); | |
| 234 TestModuleTreeClient* client = new TestModuleTreeClient; | |
| 235 registry->Fetch(module_request, AncestorList(), | |
| 236 ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), | |
| 237 client); | |
| 238 | |
| 239 EXPECT_FALSE(client->WasNotifyFinished()) | |
| 240 << "ModuleTreeLinker should always finish asynchronously."; | |
| 241 EXPECT_FALSE(client->GetModuleScript()); | |
| 242 | |
| 243 GetModulator()->ResolveSingleModuleScriptFetch(url, {}); | |
| 244 EXPECT_TRUE(client->WasNotifyFinished()); | |
| 245 ASSERT_TRUE(client->GetModuleScript()); | |
| 246 EXPECT_EQ(client->GetModuleScript()->InstantiationState(), | |
| 247 ModuleInstantiationState::kInstantiated); | |
| 248 } | |
| 249 | |
| 250 TEST_F(ModuleTreeLinkerTest, fetchTreeInstantiationFailure) { | |
| 251 GetModulator()->SetInstantiateShouldFail(true); | |
| 252 | |
| 253 ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); | |
| 254 | |
| 255 KURL url(kParsedURLString, "http://example.com/root.js"); | |
| 256 ModuleScriptFetchRequest module_request( | |
| 257 url, String(), kParserInserted, WebURLRequest::kFetchCredentialsModeOmit); | |
| 258 TestModuleTreeClient* client = new TestModuleTreeClient; | |
| 259 registry->Fetch(module_request, AncestorList(), | |
| 260 ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), | |
| 261 client); | |
| 262 | |
| 263 EXPECT_FALSE(client->WasNotifyFinished()) | |
| 264 << "ModuleTreeLinker should always finish asynchronously."; | |
| 265 EXPECT_FALSE(client->GetModuleScript()); | |
| 266 | |
| 267 GetModulator()->ResolveSingleModuleScriptFetch(url, {}); | |
| 268 EXPECT_TRUE(client->WasNotifyFinished()); | |
| 269 ASSERT_TRUE(client->GetModuleScript()); | |
| 270 EXPECT_EQ(client->GetModuleScript()->InstantiationState(), | |
| 271 ModuleInstantiationState::kErrored); | |
| 272 } | |
| 273 | |
| 274 TEST_F(ModuleTreeLinkerTest, fetchTreeWithSingleDependency) { | |
| 275 ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); | |
| 276 | |
| 277 KURL url(kParsedURLString, "http://example.com/root.js"); | |
| 278 ModuleScriptFetchRequest module_request( | |
| 279 url, String(), kParserInserted, WebURLRequest::kFetchCredentialsModeOmit); | |
| 280 TestModuleTreeClient* client = new TestModuleTreeClient; | |
| 281 registry->Fetch(module_request, AncestorList(), | |
| 282 ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), | |
| 283 client); | |
| 284 | |
| 285 EXPECT_FALSE(client->WasNotifyFinished()) | |
| 286 << "ModuleTreeLinker should always finish asynchronously."; | |
| 287 EXPECT_FALSE(client->GetModuleScript()); | |
| 288 | |
| 289 GetModulator()->ResolveSingleModuleScriptFetch(url, {"./dep1.js"}); | |
| 290 EXPECT_FALSE(client->WasNotifyFinished()); | |
| 291 | |
| 292 KURL url_dep1(kParsedURLString, "http://example.com/dep1.js"); | |
| 293 auto ancestor_list = GetModulator()->GetAncestorListForTreeFetch(url_dep1); | |
| 294 EXPECT_EQ(1u, ancestor_list.size()); | |
| 295 EXPECT_TRUE(ancestor_list.Contains( | |
| 296 KURL(kParsedURLString, "http://example.com/root.js"))); | |
| 297 | |
| 298 GetModulator()->ResolveDependentTreeFetch( | |
| 299 url_dep1, ModuleTreeLinkerTestModulator::ResolveResult::kSuccess); | |
| 300 EXPECT_TRUE(client->WasNotifyFinished()); | |
| 301 | |
| 302 ASSERT_TRUE(client->GetModuleScript()); | |
| 303 EXPECT_EQ(client->GetModuleScript()->InstantiationState(), | |
| 304 ModuleInstantiationState::kInstantiated); | |
| 305 } | |
| 306 | |
| 307 TEST_F(ModuleTreeLinkerTest, fetchTreeWith3Deps) { | |
| 308 ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); | |
| 309 | |
| 310 KURL url(kParsedURLString, "http://example.com/root.js"); | |
| 311 ModuleScriptFetchRequest module_request( | |
| 312 url, String(), kParserInserted, WebURLRequest::kFetchCredentialsModeOmit); | |
| 313 TestModuleTreeClient* client = new TestModuleTreeClient; | |
| 314 registry->Fetch(module_request, AncestorList(), | |
| 315 ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), | |
| 316 client); | |
| 317 | |
| 318 EXPECT_FALSE(client->WasNotifyFinished()) | |
| 319 << "ModuleTreeLinker should always finish asynchronously."; | |
| 320 EXPECT_FALSE(client->GetModuleScript()); | |
| 321 | |
| 322 GetModulator()->ResolveSingleModuleScriptFetch( | |
| 323 url, {"./dep1.js", "./dep2.js", "./dep3.js"}); | |
| 324 EXPECT_FALSE(client->WasNotifyFinished()); | |
| 325 | |
| 326 Vector<KURL> url_deps; | |
| 327 for (int i = 1; i <= 3; ++i) { | |
| 328 StringBuilder url_dep_str; | |
| 329 url_dep_str.Append("http://example.com/dep"); | |
| 330 url_dep_str.AppendNumber(i); | |
| 331 url_dep_str.Append(".js"); | |
| 332 | |
| 333 KURL url_dep(kParsedURLString, url_dep_str.ToString()); | |
| 334 url_deps.push_back(url_dep); | |
| 335 } | |
| 336 | |
| 337 for (const auto& url_dep : url_deps) { | |
| 338 SCOPED_TRACE(url_dep.GetString()); | |
| 339 auto ancestor_list = GetModulator()->GetAncestorListForTreeFetch(url_dep); | |
| 340 EXPECT_EQ(1u, ancestor_list.size()); | |
| 341 EXPECT_TRUE(ancestor_list.Contains( | |
| 342 KURL(kParsedURLString, "http://example.com/root.js"))); | |
| 343 } | |
| 344 | |
| 345 for (const auto& url_dep : url_deps) { | |
|
yhirano
2017/04/19 05:25:08
EXPECT_FALSE(client->WasNotifyFinished());
kouhei (in TOK)
2017/04/19 05:50:35
Done.
| |
| 346 GetModulator()->ResolveDependentTreeFetch( | |
| 347 url_dep, ModuleTreeLinkerTestModulator::ResolveResult::kSuccess); | |
| 348 } | |
| 349 | |
| 350 EXPECT_TRUE(client->WasNotifyFinished()); | |
| 351 ASSERT_TRUE(client->GetModuleScript()); | |
| 352 EXPECT_EQ(client->GetModuleScript()->InstantiationState(), | |
| 353 ModuleInstantiationState::kInstantiated); | |
| 354 } | |
| 355 | |
| 356 TEST_F(ModuleTreeLinkerTest, fetchTreeWith3Deps1Fail) { | |
| 357 ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); | |
| 358 | |
| 359 KURL url(kParsedURLString, "http://example.com/root.js"); | |
| 360 ModuleScriptFetchRequest module_request( | |
| 361 url, String(), kParserInserted, WebURLRequest::kFetchCredentialsModeOmit); | |
| 362 TestModuleTreeClient* client = new TestModuleTreeClient; | |
| 363 registry->Fetch(module_request, AncestorList(), | |
| 364 ModuleGraphLevel::kTopLevelModuleFetch, GetModulator(), | |
| 365 client); | |
| 366 | |
| 367 EXPECT_FALSE(client->WasNotifyFinished()) | |
| 368 << "ModuleTreeLinker should always finish asynchronously."; | |
| 369 EXPECT_FALSE(client->GetModuleScript()); | |
| 370 | |
| 371 GetModulator()->ResolveSingleModuleScriptFetch( | |
| 372 url, {"./dep1.js", "./dep2.js", "./dep3.js"}); | |
| 373 EXPECT_FALSE(client->WasNotifyFinished()); | |
| 374 | |
| 375 Vector<KURL> url_deps; | |
| 376 for (int i = 1; i <= 3; ++i) { | |
| 377 StringBuilder url_dep_str; | |
| 378 url_dep_str.Append("http://example.com/dep"); | |
| 379 url_dep_str.AppendNumber(i); | |
| 380 url_dep_str.Append(".js"); | |
| 381 | |
| 382 KURL url_dep(kParsedURLString, url_dep_str.ToString()); | |
| 383 url_deps.push_back(url_dep); | |
| 384 } | |
| 385 | |
| 386 for (const auto& url_dep : url_deps) { | |
| 387 SCOPED_TRACE(url_dep.GetString()); | |
| 388 auto ancestor_list = GetModulator()->GetAncestorListForTreeFetch(url_dep); | |
| 389 EXPECT_EQ(1u, ancestor_list.size()); | |
| 390 EXPECT_TRUE(ancestor_list.Contains( | |
| 391 KURL(kParsedURLString, "http://example.com/root.js"))); | |
| 392 } | |
| 393 | |
| 394 auto url_dep = url_deps.back(); | |
| 395 url_deps.pop_back(); | |
| 396 GetModulator()->ResolveDependentTreeFetch( | |
| 397 url_dep, ModuleTreeLinkerTestModulator::ResolveResult::kSuccess); | |
| 398 url_dep = url_deps.back(); | |
| 399 url_deps.pop_back(); | |
|
yhirano
2017/04/19 05:25:08
EXPECT_FALSE(client->WasNotifyFinished());
kouhei (in TOK)
2017/04/19 05:50:35
Done.
| |
| 400 GetModulator()->ResolveDependentTreeFetch( | |
| 401 url_dep, ModuleTreeLinkerTestModulator::ResolveResult::kFailure); | |
| 402 | |
| 403 EXPECT_TRUE(client->WasNotifyFinished()); | |
| 404 EXPECT_FALSE(client->GetModuleScript()); | |
| 405 | |
| 406 // Check below doesn't crash. | |
| 407 url_dep = url_deps.back(); | |
| 408 url_deps.pop_back(); | |
| 409 GetModulator()->ResolveDependentTreeFetch( | |
| 410 url_dep, ModuleTreeLinkerTestModulator::ResolveResult::kSuccess); | |
| 411 EXPECT_TRUE(url_deps.IsEmpty()); | |
| 412 } | |
| 413 | |
| 414 TEST_F(ModuleTreeLinkerTest, fetchDependencyTree) { | |
| 415 ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); | |
| 416 | |
| 417 KURL url(kParsedURLString, "http://example.com/depth1.js"); | |
| 418 ModuleScriptFetchRequest module_request( | |
| 419 url, String(), kParserInserted, WebURLRequest::kFetchCredentialsModeOmit); | |
| 420 TestModuleTreeClient* client = new TestModuleTreeClient; | |
| 421 registry->Fetch( | |
| 422 module_request, | |
| 423 AncestorList{KURL(kParsedURLString, "http://example.com/root.js")}, | |
| 424 ModuleGraphLevel::kDependentModuleFetch, GetModulator(), client); | |
| 425 | |
| 426 EXPECT_FALSE(client->WasNotifyFinished()) | |
| 427 << "ModuleTreeLinker should always finish asynchronously."; | |
| 428 EXPECT_FALSE(client->GetModuleScript()); | |
| 429 | |
| 430 GetModulator()->ResolveSingleModuleScriptFetch(url, {"./depth2.js"}); | |
| 431 | |
| 432 KURL url_dep2(kParsedURLString, "http://example.com/depth2.js"); | |
| 433 auto ancestor_list = GetModulator()->GetAncestorListForTreeFetch(url_dep2); | |
| 434 EXPECT_EQ(2u, ancestor_list.size()); | |
| 435 EXPECT_TRUE(ancestor_list.Contains( | |
| 436 KURL(kParsedURLString, "http://example.com/root.js"))); | |
| 437 EXPECT_TRUE(ancestor_list.Contains( | |
| 438 KURL(kParsedURLString, "http://example.com/depth1.js"))); | |
| 439 | |
| 440 GetModulator()->ResolveDependentTreeFetch( | |
| 441 url_dep2, ModuleTreeLinkerTestModulator::ResolveResult::kSuccess); | |
| 442 | |
| 443 EXPECT_TRUE(client->WasNotifyFinished()); | |
| 444 ASSERT_TRUE(client->GetModuleScript()); | |
| 445 EXPECT_EQ(client->GetModuleScript()->InstantiationState(), | |
| 446 ModuleInstantiationState::kInstantiated); | |
| 447 } | |
| 448 | |
| 449 } // namespace blink | |
| OLD | NEW |