blob: a1ca08ca2f59bd44bda8881d7d59541c559fb4ee [file] [log] [blame]
// Copyright (c) 2012 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 <memory>
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "content/public/test/browser_test.h"
#include "extensions/test/result_catcher.h"
#include "extensions/test/test_extension_dir.h"
namespace extensions {
namespace {
constexpr char kManifestStub[] =
R"({
"name": "extension",
"version": "0.1",
"manifest_version": %d,
"background": { %s }
})";
constexpr char kPersistentBackground[] = R"("scripts": ["background.js"])";
constexpr char kServiceWorkerBackground[] =
R"("service_worker": "background.js")";
// NOTE(devlin): When running tests using the chrome.tests.runTests API, it's
// not possible to validate the failure message of individual sub-tests using
// the ResultCatcher interface. This is because the test suite always fail with
// an error message like `kExpectedFailureMessage` below without any
// information about the failure of the individual sub-tests. If we expand this
// suite significantly, we should investigate having more information available
// on the C++ side, so that we can assert failures with more specificity.
// TODO(devlin): Investigate using WebContentsConsoleObserver to watch for
// specific errors / patterns.
constexpr char kExpectedFailureMessage[] = "Failed 1 of 1 tests";
} // namespace
using ContextType = ExtensionApiTest::ContextType;
class TestAPITest : public ExtensionApiTest {
protected:
const Extension* LoadExtensionScriptWithContext(const char* background_script,
ContextType context_type,
int manifest_version);
std::vector<std::unique_ptr<TestExtensionDir>> test_dirs_;
};
const Extension* TestAPITest::LoadExtensionScriptWithContext(
const char* background_script,
ContextType context_type,
int manifest_version = 2) {
auto test_dir = std::make_unique<TestExtensionDir>();
const char* background_value = context_type == ContextType::kServiceWorker
? kServiceWorkerBackground
: kPersistentBackground;
const std::string manifest =
base::StringPrintf(kManifestStub, manifest_version, background_value);
test_dir->WriteManifest(manifest);
test_dir->WriteFile(FILE_PATH_LITERAL("background.js"), background_script);
const Extension* extension = LoadExtension(test_dir->UnpackedPath());
test_dirs_.push_back(std::move(test_dir));
return extension;
}
class TestAPITestWithContextType
: public TestAPITest,
public testing::WithParamInterface<ContextType> {};
INSTANTIATE_TEST_SUITE_P(
PersistentBackground,
TestAPITestWithContextType,
::testing::Values(ExtensionApiTest::ContextType::kPersistentBackground));
INSTANTIATE_TEST_SUITE_P(
ServiceWorker,
TestAPITestWithContextType,
::testing::Values(ExtensionApiTest::ContextType::kServiceWorker));
// TODO(devlin): This test name should be more descriptive.
IN_PROC_BROWSER_TEST_P(TestAPITestWithContextType, ApiTest) {
ASSERT_TRUE(RunExtensionTest(
{.name = "apitest"},
{.load_as_service_worker = GetParam() == ContextType::kServiceWorker}))
<< message_;
}
// Verifies that failing an assert in a promise will properly fail and end the
// test.
IN_PROC_BROWSER_TEST_P(TestAPITestWithContextType, FailedAssertsInPromises) {
ResultCatcher result_catcher;
constexpr char kBackgroundJs[] =
R"(chrome.test.runTests([
function failedAssertsInPromises() {
let p = new Promise((resolve, reject) => {
chrome.test.assertEq(1, 2);
resolve();
});
p.then(() => { chrome.test.succeed(); });
}
]);)";
ASSERT_TRUE(LoadExtensionScriptWithContext(kBackgroundJs, GetParam()));
EXPECT_FALSE(result_catcher.GetNextResult());
EXPECT_EQ(kExpectedFailureMessage, result_catcher.message());
}
// Verifies that using await and assert'ing aspects of the results succeeds.
IN_PROC_BROWSER_TEST_P(TestAPITestWithContextType,
AsyncAwaitAssertions_Succeed) {
ResultCatcher result_catcher;
constexpr char kBackgroundJs[] =
R"(chrome.test.runTests([
async function asyncAssertions() {
let tabs = await new Promise((resolve) => {
chrome.tabs.query({}, resolve);
});
chrome.test.assertTrue(tabs.length > 0);
chrome.test.succeed();
}
]);)";
ASSERT_TRUE(LoadExtensionScriptWithContext(kBackgroundJs, GetParam()));
EXPECT_TRUE(result_catcher.GetNextResult());
}
// Verifies that using await and having failed assertions properly fails the
// test.
IN_PROC_BROWSER_TEST_P(TestAPITestWithContextType,
AsyncAwaitAssertions_Failed) {
ResultCatcher result_catcher;
constexpr char kBackgroundJs[] =
R"(chrome.test.runTests([
async function asyncAssertions() {
let tabs = await new Promise((resolve) => {
chrome.tabs.query({}, resolve);
});
chrome.test.assertEq(0, tabs.length);
chrome.test.succeed();
}
]);)";
ASSERT_TRUE(LoadExtensionScriptWithContext(kBackgroundJs, GetParam()));
EXPECT_FALSE(result_catcher.GetNextResult());
EXPECT_EQ(kExpectedFailureMessage, result_catcher.message());
}
// Verifies that chrome.test.assertPromiseRejects() succeeds using
// promises that reject with the expected message.
IN_PROC_BROWSER_TEST_F(TestAPITest, AssertPromiseRejects_Successful) {
ResultCatcher result_catcher;
constexpr char kWorkerJs[] =
R"(const TEST_ERROR = 'Expected Error';
chrome.test.runTests([
async function successfulAssert_PromiseAlreadyRejected() {
let p = Promise.reject(TEST_ERROR);
await chrome.test.assertPromiseRejects(p, TEST_ERROR);
chrome.test.succeed();
},
async function successfulAssert_PromiseRejectedLater() {
let rejectPromise;
let p = new Promise(
(resolve, reject) => { rejectPromise = reject; });
let assertPromise =
chrome.test.assertPromiseRejects(p, TEST_ERROR);
rejectPromise(TEST_ERROR);
assertPromise.then(() => {
chrome.test.succeed();
}).catch(e => {
chrome.test.fail(e);
});
},
async function successfulAssert_RegExpMatching() {
const regexp = /.*pect.*rror/;
chrome.test.assertTrue(regexp.test(TEST_ERROR));
let p = Promise.reject(TEST_ERROR);
await chrome.test.assertPromiseRejects(p, regexp);
chrome.test.succeed();
},
]);)";
ASSERT_TRUE(LoadExtensionScriptWithContext(kWorkerJs,
ContextType::kServiceWorker,
/*manifest_version=*/3));
EXPECT_TRUE(result_catcher.GetNextResult());
}
// Tests that chrome.test.assertPromiseRejects() properly fails the test when
// the promise is rejected with an improper message.
IN_PROC_BROWSER_TEST_F(TestAPITest, AssertPromiseRejects_WrongErrorMessage) {
ResultCatcher result_catcher;
constexpr char kWorkerJs[] =
R"(chrome.test.runTests([
async function failedAssert_WrongErrorMessage() {
let p = Promise.reject('Wrong Error');
await chrome.test.assertPromiseRejects(p, 'Expected Error');
chrome.test.succeed();
},
]);)";
ASSERT_TRUE(LoadExtensionScriptWithContext(kWorkerJs,
ContextType::kServiceWorker,
/*manifest_version=*/3));
EXPECT_FALSE(result_catcher.GetNextResult());
EXPECT_EQ(kExpectedFailureMessage, result_catcher.message());
}
// Tests that chrome.test.assertPromiseRejects() properly fails the test when
// the promise resolves instead of rejects.
IN_PROC_BROWSER_TEST_F(TestAPITest, AssertPromiseRejects_PromiseResolved) {
ResultCatcher result_catcher;
constexpr char kWorkerJs[] =
R"(chrome.test.runTests([
async function failedAssert_PromiseResolved() {
let p = Promise.resolve(42);
await chrome.test.assertPromiseRejects(p, 'Expected Error');
chrome.test.succeed();
},
]);)";
ASSERT_TRUE(LoadExtensionScriptWithContext(kWorkerJs,
ContextType::kServiceWorker,
/*manifest_version=*/3));
EXPECT_FALSE(result_catcher.GetNextResult());
EXPECT_EQ(kExpectedFailureMessage, result_catcher.message());
}
// Tests that finishing the test without waiting for the result of
// chrome.test.assertPromiseRejects() properly fails the test.
IN_PROC_BROWSER_TEST_F(TestAPITest, AssertPromiseRejects_PromiseIgnored) {
ResultCatcher result_catcher;
constexpr char kWorkerJs[] =
R"(chrome.test.runTests([
async function failedAssert_PromiseIgnored() {
let p = new Promise((resolve, reject) => { });
chrome.test.assertPromiseRejects(p, 'Expected Error');
chrome.test.succeed();
},
]);)";
ASSERT_TRUE(LoadExtensionScriptWithContext(kWorkerJs,
ContextType::kServiceWorker,
/*manifest_version=*/3));
EXPECT_FALSE(result_catcher.GetNextResult());
EXPECT_EQ(kExpectedFailureMessage, result_catcher.message());
}
} // namespace extensions