1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 16:58:11 +00:00

test-js: Allow skipping tests with "test.skip(name, callback)"

Skipped tests count as a "pass" rather than a "fail" (i.e. a test suite
with a skipped test will pass), however it does display a message when
the test is printing.

This is intended for tests which _should_ work, but currently do not.
This should be preferred over "// FIXME" notes if possible.
This commit is contained in:
Matthew Olsson 2020-07-04 12:57:12 -07:00 committed by Andreas Kling
parent cf537311e4
commit 82fa65135a
2 changed files with 70 additions and 22 deletions

View file

@ -415,7 +415,7 @@ class Expector {
expect = value => new Expector(value); expect = value => new Expector(value);
// describe is able to lump test results inside of it by using this context // describe is able to lump test results inside of it by using this context
// variable. Top level tests are assumed to be in the default context // variable. Top level tests have the default suite message
const defaultSuiteMessage = "__$$TOP_LEVEL$$__"; const defaultSuiteMessage = "__$$TOP_LEVEL$$__";
let suiteMessage = defaultSuiteMessage; let suiteMessage = defaultSuiteMessage;
@ -425,19 +425,18 @@ describe = (message, callback) => {
suiteMessage = defaultSuiteMessage; suiteMessage = defaultSuiteMessage;
} }
const getTestFunction = successMessage => (message, callback) => { test = (message, callback) => {
if (!__TestResults__[suiteMessage]) if (!__TestResults__[suiteMessage])
__TestResults__[suiteMessage] = {}; __TestResults__[suiteMessage] = {};
const suite = __TestResults__[suiteMessage]; const suite = __TestResults__[suiteMessage];
if (suite[message])
if (!suite[message]) throw new Error("Duplicate test name: " + message);
suite[message] = {};
try { try {
callback(); callback();
suite[message] = { suite[message] = {
result: successMessage, result: "pass",
}; };
} catch (e) { } catch (e) {
suite[message] = { suite[message] = {
@ -446,6 +445,20 @@ const getTestFunction = successMessage => (message, callback) => {
} }
} }
test = getTestFunction("pass"); test.skip = (message, callback) => {
if (typeof callback !== "function")
throw new Error("test.skip has invalid second argument (must be a function)");
if (!__TestResults__[suiteMessage])
__TestResults__[suiteMessage] = {};
const suite = __TestResults__[suiteMessage];
if (suite[message])
throw new Error("Duplicate test name: " + message);
suite[message] = {
result: "skip",
}
}
})(); })();

View file

@ -192,6 +192,7 @@ Vector<String> tests_to_run = {
enum class TestResult { enum class TestResult {
Pass, Pass,
Fail, Fail,
Skip,
}; };
struct JSTest { struct JSTest {
@ -201,7 +202,9 @@ struct JSTest {
struct JSSuite { struct JSSuite {
String name; String name;
bool has_failed_tests { false }; // A failed test takes precedence over a skipped test, which both have
// precedence over a passed test
TestResult most_severe_test_result { TestResult::Pass };
Vector<JSTest> tests {}; Vector<JSTest> tests {};
}; };
@ -213,13 +216,16 @@ struct ParserError {
struct JSFileResult { struct JSFileResult {
String name; String name;
Optional<ParserError> error {}; Optional<ParserError> error {};
bool has_failed_tests { false }; // A failed test takes precedence over a skipped test, which both have
// precedence over a passed test
TestResult most_severe_test_result { TestResult::Pass };
Vector<JSSuite> suites {}; Vector<JSSuite> suites {};
}; };
struct JSTestRunnerCounts { struct JSTestRunnerCounts {
int tests_failed { 0 }; int tests_failed { 0 };
int tests_passed { 0 }; int tests_passed { 0 };
int tests_skipped { 0 };
int suites_failed { 0 }; int suites_failed { 0 };
int suites_passed { 0 }; int suites_passed { 0 };
int files_total { 0 }; int files_total { 0 };
@ -361,19 +367,26 @@ JSFileResult TestRunner::run_file_test(const String& test_path)
if (result_string == "pass") { if (result_string == "pass") {
test.result = TestResult::Pass; test.result = TestResult::Pass;
m_counts.tests_passed++; m_counts.tests_passed++;
} else { } else if (result_string == "fail") {
test.result = TestResult::Fail; test.result = TestResult::Fail;
m_counts.tests_failed++; m_counts.tests_failed++;
suite.has_failed_tests = true; suite.most_severe_test_result = TestResult::Fail;
} else {
test.result = TestResult::Skip;
if (suite.most_severe_test_result == TestResult::Pass)
suite.most_severe_test_result = TestResult::Skip;
m_counts.tests_skipped++;
} }
suite.tests.append(test); suite.tests.append(test);
}); });
if (suite.has_failed_tests) { if (suite.most_severe_test_result == TestResult::Fail) {
m_counts.suites_failed++; m_counts.suites_failed++;
file_result.has_failed_tests = true; file_result.most_severe_test_result = TestResult::Fail;
} else { } else {
if (suite.most_severe_test_result == TestResult::Skip && file_result.most_severe_test_result == TestResult::Pass)
file_result.most_severe_test_result = TestResult::Skip;
m_counts.suites_passed++; m_counts.suites_passed++;
} }
@ -390,6 +403,7 @@ enum Modifier {
BG_GREEN, BG_GREEN,
FG_RED, FG_RED,
FG_GREEN, FG_GREEN,
FG_ORANGE,
FG_GRAY, FG_GRAY,
FG_BLACK, FG_BLACK,
FG_BOLD, FG_BOLD,
@ -409,6 +423,8 @@ void print_modifiers(Vector<Modifier> modifiers)
return "\033[38;2;255;0;102m"; return "\033[38;2;255;0;102m";
case FG_GREEN: case FG_GREEN:
return "\033[38;2;102;255;0m"; return "\033[38;2;102;255;0m";
case FG_ORANGE:
return "\033[38;2;255;102;0m";
case FG_GRAY: case FG_GRAY:
return "\033[38;2;135;139;148m"; return "\033[38;2;135;139;148m";
case FG_BLACK: case FG_BLACK:
@ -426,7 +442,8 @@ void print_modifiers(Vector<Modifier> modifiers)
void TestRunner::print_file_result(const JSFileResult& file_result) void TestRunner::print_file_result(const JSFileResult& file_result)
{ {
if (file_result.has_failed_tests || file_result.error.has_value()) {
if (file_result.most_severe_test_result == TestResult::Fail || file_result.error.has_value()) {
print_modifiers({ BG_RED, FG_BLACK, FG_BOLD }); print_modifiers({ BG_RED, FG_BLACK, FG_BOLD });
printf(" FAIL "); printf(" FAIL ");
print_modifiers({ CLEAR }); print_modifiers({ CLEAR });
@ -453,18 +470,26 @@ void TestRunner::print_file_result(const JSFileResult& file_result)
return; return;
} }
if (file_result.has_failed_tests) { if (file_result.most_severe_test_result != TestResult::Pass) {
for (auto& suite : file_result.suites) { for (auto& suite : file_result.suites) {
if (!suite.has_failed_tests) if (suite.most_severe_test_result == TestResult::Pass)
continue; continue;
bool failed = suite.most_severe_test_result == TestResult::Fail;
print_modifiers({ FG_GRAY, FG_BOLD }); print_modifiers({ FG_GRAY, FG_BOLD });
if (failed) {
printf(" ❌ Suite: "); printf(" ❌ Suite: ");
if (suite.name == TOP_LEVEL_TEST_NAME) { } else {
printf(" ⚠️️ Suite: ");
}
print_modifiers({ CLEAR, FG_GRAY }); print_modifiers({ CLEAR, FG_GRAY });
if (suite.name == TOP_LEVEL_TEST_NAME) {
printf("<top-level>\n"); printf("<top-level>\n");
} else { } else {
print_modifiers({ CLEAR, FG_RED });
printf("%s\n", suite.name.characters()); printf("%s\n", suite.name.characters());
} }
print_modifiers({ CLEAR }); print_modifiers({ CLEAR });
@ -475,8 +500,13 @@ void TestRunner::print_file_result(const JSFileResult& file_result)
print_modifiers({ FG_GRAY, FG_BOLD }); print_modifiers({ FG_GRAY, FG_BOLD });
printf(" Test: "); printf(" Test: ");
if (test.result == TestResult::Fail) {
print_modifiers({ CLEAR, FG_RED }); print_modifiers({ CLEAR, FG_RED });
printf("%s\n", test.name.characters()); printf("%s (failed)\n", test.name.characters());
} else {
print_modifiers({ CLEAR, FG_ORANGE });
printf("%s (skipped)\n", test.name.characters());
}
print_modifiers({ CLEAR }); print_modifiers({ CLEAR });
} }
} }
@ -504,6 +534,11 @@ void TestRunner::print_test_results() const
printf("%d failed, ", m_counts.tests_failed); printf("%d failed, ", m_counts.tests_failed);
print_modifiers({ CLEAR }); print_modifiers({ CLEAR });
} }
if (m_counts.tests_skipped) {
print_modifiers({ FG_ORANGE });
printf("%d skipped, ", m_counts.tests_skipped);
print_modifiers({ CLEAR });
}
if (m_counts.tests_passed) { if (m_counts.tests_passed) {
print_modifiers({ FG_GREEN }); print_modifiers({ FG_GREEN });
printf("%d passed, ", m_counts.tests_passed); printf("%d passed, ", m_counts.tests_passed);