| Index: third_party/WebKit/Source/core/dom/ModuleMapTest.cpp
|
| diff --git a/third_party/WebKit/Source/core/dom/ModuleMapTest.cpp b/third_party/WebKit/Source/core/dom/ModuleMapTest.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ac18a9940f510dd5e6ca150dadceafb21f51b119
|
| --- /dev/null
|
| +++ b/third_party/WebKit/Source/core/dom/ModuleMapTest.cpp
|
| @@ -0,0 +1,248 @@
|
| +// 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 "core/dom/ModuleMap.h"
|
| +
|
| +#include "core/dom/Document.h"
|
| +#include "core/dom/Modulator.h"
|
| +#include "core/dom/ModuleScript.h"
|
| +#include "core/dom/ScriptModuleResolver.h"
|
| +#include "core/loader/modulescript/ModuleScriptFetchRequest.h"
|
| +#include "core/loader/modulescript/ModuleScriptLoaderClient.h"
|
| +#include "core/testing/DummyModulator.h"
|
| +#include "core/testing/DummyPageHolder.h"
|
| +#include "platform/heap/Handle.h"
|
| +#include "platform/testing/TestingPlatformSupport.h"
|
| +#include "public/platform/Platform.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace blink {
|
| +
|
| +namespace {
|
| +
|
| +class TestSingleModuleClient final
|
| + : public GarbageCollectedFinalized<TestSingleModuleClient>,
|
| + public SingleModuleClient {
|
| + USING_GARBAGE_COLLECTED_MIXIN(TestSingleModuleClient);
|
| +
|
| + public:
|
| + TestSingleModuleClient() = default;
|
| + virtual ~TestSingleModuleClient() {}
|
| +
|
| + DEFINE_INLINE_TRACE() { visitor->trace(m_moduleScript); }
|
| +
|
| + void notifyModuleLoadFinished(ModuleScript* moduleScript) override {
|
| + m_wasNotifyFinished = true;
|
| + m_moduleScript = moduleScript;
|
| + }
|
| +
|
| + bool wasNotifyFinished() const { return m_wasNotifyFinished; }
|
| + ModuleScript* moduleScript() { return m_moduleScript; }
|
| +
|
| + private:
|
| + bool m_wasNotifyFinished = false;
|
| + Member<ModuleScript> m_moduleScript;
|
| +};
|
| +
|
| +class TestScriptModuleResolver final : public ScriptModuleResolver {
|
| + public:
|
| + TestScriptModuleResolver() {}
|
| +
|
| + int registerModuleScriptCallCount() const {
|
| + return m_registerModuleScriptCallCount;
|
| + }
|
| +
|
| + void registerModuleScript(ModuleScript*) override {
|
| + m_registerModuleScriptCallCount++;
|
| + }
|
| +
|
| + ScriptModule resolve(const String& specifier,
|
| + const ScriptModule& referrer,
|
| + ExceptionState&) override {
|
| + NOTREACHED();
|
| + return ScriptModule();
|
| + }
|
| +
|
| + private:
|
| + int m_registerModuleScriptCallCount = 0;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +class ModuleMapTestModulator final : public DummyModulator {
|
| + public:
|
| + ModuleMapTestModulator();
|
| + virtual ~ModuleMapTestModulator() {}
|
| +
|
| + DECLARE_TRACE();
|
| +
|
| + TestScriptModuleResolver* testScriptModuleResolver() {
|
| + return m_resolver.get();
|
| + }
|
| + void resolveFetches();
|
| +
|
| + private:
|
| + // Implements Modulator:
|
| +
|
| + ScriptModuleResolver* scriptModuleResolver() override {
|
| + return m_resolver.get();
|
| + }
|
| +
|
| + WebTaskRunner* taskRunner() override {
|
| + return Platform::current()->currentThread()->getWebTaskRunner();
|
| + };
|
| +
|
| + void fetchNewSingleModule(const ModuleScriptFetchRequest&,
|
| + ModuleGraphLevel,
|
| + ModuleScriptLoaderClient*) override;
|
| +
|
| + struct TestRequest : public GarbageCollectedFinalized<TestRequest> {
|
| + KURL url;
|
| + String nonce;
|
| + Member<ModuleScriptLoaderClient> client;
|
| +
|
| + DEFINE_INLINE_TRACE() { visitor->trace(client); }
|
| + };
|
| + HeapVector<Member<TestRequest>> m_testRequests;
|
| +
|
| + Member<TestScriptModuleResolver> m_resolver;
|
| +};
|
| +
|
| +ModuleMapTestModulator::ModuleMapTestModulator()
|
| + : m_resolver(new TestScriptModuleResolver) {}
|
| +
|
| +DEFINE_TRACE(ModuleMapTestModulator) {
|
| + visitor->trace(m_testRequests);
|
| + visitor->trace(m_resolver);
|
| + DummyModulator::trace(visitor);
|
| +}
|
| +
|
| +void ModuleMapTestModulator::fetchNewSingleModule(
|
| + const ModuleScriptFetchRequest& request,
|
| + ModuleGraphLevel,
|
| + ModuleScriptLoaderClient* client) {
|
| + TestRequest* testRequest = new TestRequest;
|
| + testRequest->url = request.url();
|
| + testRequest->nonce = request.nonce();
|
| + testRequest->client = client;
|
| + m_testRequests.push_back(testRequest);
|
| +}
|
| +
|
| +void ModuleMapTestModulator::resolveFetches() {
|
| + for (const auto& testRequest : m_testRequests) {
|
| + ModuleScript* moduleScript = ModuleScript::create(
|
| + ScriptModule(), testRequest->url, testRequest->nonce, ParserInserted,
|
| + WebURLRequest::FetchCredentialsModeOmit);
|
| + taskRunner()->postTask(
|
| + BLINK_FROM_HERE,
|
| + WTF::bind(&ModuleScriptLoaderClient::notifyNewSingleModuleFinished,
|
| + wrapPersistent(testRequest->client.get()),
|
| + wrapPersistent(moduleScript)));
|
| + }
|
| + m_testRequests.clear();
|
| +}
|
| +
|
| +class ModuleMapTest : public testing::Test {
|
| + public:
|
| + void SetUp() override;
|
| +
|
| + ModuleMapTestModulator* modulator() { return m_modulator.get(); }
|
| + ModuleMap* map() { return m_map; }
|
| +
|
| + protected:
|
| + Persistent<ModuleMapTestModulator> m_modulator;
|
| + Persistent<ModuleMap> m_map;
|
| +};
|
| +
|
| +void ModuleMapTest::SetUp() {
|
| + m_modulator = new ModuleMapTestModulator();
|
| + m_map = ModuleMap::create(m_modulator.get());
|
| +}
|
| +
|
| +TEST_F(ModuleMapTest, sequentialRequests) {
|
| + ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
|
| + platform;
|
| + platform->advanceClockSeconds(1.); // For non-zero DocumentParserTimings
|
| +
|
| + KURL url(KURL(), "https://example.com/foo.js");
|
| + ModuleScriptFetchRequest moduleRequest(
|
| + url, String(), ParserInserted, WebURLRequest::FetchCredentialsModeOmit);
|
| +
|
| + // First request
|
| + TestSingleModuleClient* client = new TestSingleModuleClient;
|
| + map()->fetchSingleModuleScript(moduleRequest,
|
| + ModuleGraphLevel::TopLevelModuleFetch, client);
|
| + modulator()->resolveFetches();
|
| + EXPECT_FALSE(client->wasNotifyFinished())
|
| + << "fetchSingleModuleScript shouldn't complete synchronously";
|
| + platform->runUntilIdle();
|
| +
|
| + EXPECT_EQ(
|
| + modulator()->testScriptModuleResolver()->registerModuleScriptCallCount(),
|
| + 1);
|
| + EXPECT_TRUE(client->wasNotifyFinished());
|
| + EXPECT_TRUE(client->moduleScript());
|
| + EXPECT_EQ(client->moduleScript()->instantiationState(),
|
| + ModuleInstantiationState::Uninstantiated);
|
| +
|
| + // Secondary request
|
| + TestSingleModuleClient* client2 = new TestSingleModuleClient;
|
| + map()->fetchSingleModuleScript(
|
| + moduleRequest, ModuleGraphLevel::TopLevelModuleFetch, client2);
|
| + modulator()->resolveFetches();
|
| + EXPECT_FALSE(client2->wasNotifyFinished())
|
| + << "fetchSingleModuleScript shouldn't complete synchronously";
|
| + platform->runUntilIdle();
|
| +
|
| + EXPECT_EQ(
|
| + modulator()->testScriptModuleResolver()->registerModuleScriptCallCount(),
|
| + 1)
|
| + << "registerModuleScript sholudn't be called in secondary request.";
|
| + EXPECT_TRUE(client2->wasNotifyFinished());
|
| + EXPECT_TRUE(client2->moduleScript());
|
| + EXPECT_EQ(client2->moduleScript()->instantiationState(),
|
| + ModuleInstantiationState::Uninstantiated);
|
| +}
|
| +
|
| +TEST_F(ModuleMapTest, concurrentRequestsShouldJoin) {
|
| + ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
|
| + platform;
|
| + platform->advanceClockSeconds(1.); // For non-zero DocumentParserTimings
|
| +
|
| + KURL url(KURL(), "https://example.com/foo.js");
|
| + ModuleScriptFetchRequest moduleRequest(
|
| + url, String(), ParserInserted, WebURLRequest::FetchCredentialsModeOmit);
|
| +
|
| + // First request
|
| + TestSingleModuleClient* client = new TestSingleModuleClient;
|
| + map()->fetchSingleModuleScript(moduleRequest,
|
| + ModuleGraphLevel::TopLevelModuleFetch, client);
|
| +
|
| + // Secondary request (which should join the first request)
|
| + TestSingleModuleClient* client2 = new TestSingleModuleClient;
|
| + map()->fetchSingleModuleScript(
|
| + moduleRequest, ModuleGraphLevel::TopLevelModuleFetch, client2);
|
| +
|
| + modulator()->resolveFetches();
|
| + EXPECT_FALSE(client->wasNotifyFinished())
|
| + << "fetchSingleModuleScript shouldn't complete synchronously";
|
| + EXPECT_FALSE(client2->wasNotifyFinished())
|
| + << "fetchSingleModuleScript shouldn't complete synchronously";
|
| + platform->runUntilIdle();
|
| +
|
| + EXPECT_EQ(
|
| + modulator()->testScriptModuleResolver()->registerModuleScriptCallCount(),
|
| + 1);
|
| +
|
| + EXPECT_TRUE(client->wasNotifyFinished());
|
| + EXPECT_TRUE(client->moduleScript());
|
| + EXPECT_EQ(client->moduleScript()->instantiationState(),
|
| + ModuleInstantiationState::Uninstantiated);
|
| + EXPECT_TRUE(client2->wasNotifyFinished());
|
| + EXPECT_TRUE(client2->moduleScript());
|
| + EXPECT_EQ(client2->moduleScript()->instantiationState(),
|
| + ModuleInstantiationState::Uninstantiated);
|
| +}
|
| +
|
| +} // namespace blink
|
|
|