mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:27:35 +00:00
LibJS: Add test-common.js tests, remove unused matchers
Now that test-common.js is quite a bit more complicated, we need tests for test-common to make sure all of the matchers behave correctly
This commit is contained in:
parent
eea6041302
commit
b86faeaeef
3 changed files with 261 additions and 76 deletions
224
Libraries/LibJS/Tests/test-common-tests.js
Normal file
224
Libraries/LibJS/Tests/test-common-tests.js
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
test("toBe", () => {
|
||||||
|
expect(null).toBe(null);
|
||||||
|
expect(undefined).toBe(undefined);
|
||||||
|
expect(null).not.toBe(undefined);
|
||||||
|
|
||||||
|
expect(1).toBe(1);
|
||||||
|
expect(1).not.toBe(2);
|
||||||
|
|
||||||
|
expect("1").toBe("1");
|
||||||
|
expect("1").not.toBe("2");
|
||||||
|
|
||||||
|
expect(true).toBe(true);
|
||||||
|
expect(true).not.toBe(false);
|
||||||
|
|
||||||
|
expect({}).not.toBe({});
|
||||||
|
expect([]).not.toBe([]);
|
||||||
|
|
||||||
|
function foo() {};
|
||||||
|
expect(foo).toBe(foo);
|
||||||
|
expect(function(){}).not.toBe(function(){});
|
||||||
|
|
||||||
|
let s = Symbol("foo");
|
||||||
|
expect(s).toBe(s);
|
||||||
|
expect(Symbol("foo")).not.toBe(Symbol("foo"));
|
||||||
|
|
||||||
|
expect(1n).toBe(1n);
|
||||||
|
expect(1n).not.toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toHaveLength", () => {
|
||||||
|
expect([]).toHaveLength(0);
|
||||||
|
expect([]).not.toHaveLength(1);
|
||||||
|
expect([1]).toHaveLength(1);
|
||||||
|
expect({ length: 1 }).toHaveLength(1);
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
expect(1).toHaveLength();
|
||||||
|
}).toThrow(ExpectationError);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toHaveProperty", () => {
|
||||||
|
expect([]).toHaveProperty("length");
|
||||||
|
expect([]).toHaveProperty("length", 0);
|
||||||
|
expect([1]).not.toHaveProperty("length", 0);
|
||||||
|
expect({ foo: "bar" }).toHaveProperty("foo")
|
||||||
|
expect({ foo: "bar" }).toHaveProperty("foo", "bar");
|
||||||
|
|
||||||
|
expect({ foo: { bar: "baz" } }).toHaveProperty(["foo", "bar"]);
|
||||||
|
expect({ foo: { bar: "baz" } }).toHaveProperty(["foo", "bar"], "baz");
|
||||||
|
expect({ foo: { bar: "baz" } }).toHaveProperty("foo.bar");
|
||||||
|
expect({ foo: { bar: "baz" } }).toHaveProperty("foo.bar", "baz");
|
||||||
|
|
||||||
|
expect({ foo: { bar: "baz" } }).toHaveProperty(["foo", "bar"]);
|
||||||
|
expect({ foo: { bar: "baz" } }).toHaveProperty(["foo", "bar"], "baz");
|
||||||
|
expect({ foo: { bar: "baz" } }).not.toHaveProperty(["foo", "baz"]);
|
||||||
|
expect({ foo: { bar: "baz" } }).not.toHaveProperty(["foo", "baz"], "qux");
|
||||||
|
expect({ foo: { bar: "baz" } }).not.toHaveProperty("foo.baz");
|
||||||
|
expect({ foo: { bar: "baz" } }).not.toHaveProperty("foo.baz", "qux");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toBeDefined", () => {
|
||||||
|
expect(1).toBeDefined();
|
||||||
|
expect(true).toBeDefined();
|
||||||
|
expect(false).toBeDefined();
|
||||||
|
expect({}).toBeDefined();
|
||||||
|
expect([]).toBeDefined();
|
||||||
|
expect("a").toBeDefined();
|
||||||
|
expect(null).toBeDefined();
|
||||||
|
expect(undefined).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toBeInstanceOf", () => {
|
||||||
|
expect(new Error).toBeInstanceOf(Error);
|
||||||
|
expect(Error).not.toBeInstanceOf(Error);
|
||||||
|
|
||||||
|
class Parent {};
|
||||||
|
class Child extends Parent {};
|
||||||
|
|
||||||
|
expect(new Child).toBeInstanceOf(Child);
|
||||||
|
expect(new Child).toBeInstanceOf(Parent);
|
||||||
|
expect(new Parent).toBeInstanceOf(Parent);
|
||||||
|
expect(new Parent).not.toBeInstanceOf(Child);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toBeNull", () => {
|
||||||
|
expect(null).toBeNull();
|
||||||
|
expect(undefined).not.toBeNull();
|
||||||
|
expect(5).not.toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toBeUndefined", () => {
|
||||||
|
expect(undefined).toBeUndefined();
|
||||||
|
expect(null).not.toBeUndefined();
|
||||||
|
expect().toBeUndefined();
|
||||||
|
expect(5).not.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toBeNaN", () => {
|
||||||
|
expect(NaN).toBeNaN();
|
||||||
|
expect(5).not.toBeNaN();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toContain", () => {
|
||||||
|
expect([1, 2, 3]).toContain(1);
|
||||||
|
expect([1, 2, 3]).toContain(2);
|
||||||
|
expect([1, 2, 3]).toContain(3);
|
||||||
|
expect([{ foo: 1 }]).not.toContain({ foo: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toContainEqual", () => {
|
||||||
|
expect([1, 2, 3]).toContainEqual(1);
|
||||||
|
expect([1, 2, 3]).toContainEqual(2);
|
||||||
|
expect([1, 2, 3]).toContainEqual(3);
|
||||||
|
expect([{ foo: 1 }]).toContainEqual({ foo: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toEqual", () => {
|
||||||
|
expect(undefined).toEqual(undefined);
|
||||||
|
expect(null).toEqual(null);
|
||||||
|
expect(undefined).not.toEqual(null);
|
||||||
|
expect(null).not.toEqual(undefined);
|
||||||
|
expect(NaN).toEqual(NaN);
|
||||||
|
|
||||||
|
expect(1).toEqual(1);
|
||||||
|
expect("abcd").toEqual("abcd");
|
||||||
|
|
||||||
|
let s = Symbol();
|
||||||
|
expect(s).toEqual(s);
|
||||||
|
expect(Symbol()).not.toEqual(Symbol());
|
||||||
|
expect(Symbol.for("foo")).toEqual(Symbol.for("foo"));
|
||||||
|
|
||||||
|
expect({ foo: 1, bar: { baz: [1, 2, 3 ] } })
|
||||||
|
.toEqual({ foo: 1, bar: { baz: [1, 2, 3 ] } });
|
||||||
|
expect([1, 2, { foo: 1 }, [3, [4, 5]]])
|
||||||
|
.toEqual([1, 2, { foo: 1 }, [3, [4, 5]]]);
|
||||||
|
|
||||||
|
function foo() {}
|
||||||
|
expect(foo).toEqual(foo);
|
||||||
|
expect(function(){}).not.toEqual(function(){});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toThrow", () => {
|
||||||
|
expect(() => {}).not.toThrow();
|
||||||
|
expect(() => {}).not.toThrow("foo");
|
||||||
|
expect(() => {}).not.toThrow(TypeError);
|
||||||
|
expect(() => {}).not.toThrow(new TypeError("foo"));
|
||||||
|
|
||||||
|
let thrower = () => {
|
||||||
|
throw new TypeError("foo bar");
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(thrower).toThrow();
|
||||||
|
expect(thrower).toThrow(TypeError);
|
||||||
|
expect(thrower).toThrow("o ba");
|
||||||
|
expect(thrower).toThrow("foo bar");
|
||||||
|
expect(thrower).not.toThrow("baz");
|
||||||
|
expect(thrower).not.toThrow(ReferenceError);
|
||||||
|
expect(thrower).toThrow(new TypeError("foo bar"));
|
||||||
|
expect(thrower).not.toThrow(new TypeError("o ba"));
|
||||||
|
expect(thrower).toThrow(new ReferenceError("foo bar"));
|
||||||
|
expect(thrower).toThrow({ message: "foo bar" });
|
||||||
|
});
|
||||||
|
|
||||||
|
test("pass", () => {
|
||||||
|
expect().pass();
|
||||||
|
expect({}).pass();
|
||||||
|
});
|
||||||
|
|
||||||
|
test("fail", () => {
|
||||||
|
// FIXME: Doesn't really make sense; this is a great candidate
|
||||||
|
// for expect.assertions()
|
||||||
|
try {
|
||||||
|
expect().fail();
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.name).toBe("ExpectationError");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("toThrowWithMessage", () => {
|
||||||
|
let incorrectUsages = [
|
||||||
|
[1, undefined, undefined],
|
||||||
|
[() => {}, undefined, undefined],
|
||||||
|
[() => {}, function(){}, undefined],
|
||||||
|
[() => {}, undefined, "test"]
|
||||||
|
];
|
||||||
|
|
||||||
|
incorrectUsages.forEach(arr => {
|
||||||
|
expect(() => {
|
||||||
|
expect(arr[0]).toThrowWithMessage(arr[1], arr[2]);
|
||||||
|
}).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
let thrower = () => {
|
||||||
|
throw new TypeError("foo bar");
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(thrower).toThrowWithMessage(TypeError, "foo bar");
|
||||||
|
expect(thrower).toThrowWithMessage(TypeError, "foo");
|
||||||
|
expect(thrower).toThrowWithMessage(TypeError, "o ba");
|
||||||
|
expect(thrower).not.toThrowWithMessage(ReferenceError, "foo bar");
|
||||||
|
expect(thrower).not.toThrowWithMessage(TypeError, "foo baz");
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: Will have to change when this matcher changes to use the
|
||||||
|
// "eval" function
|
||||||
|
test("toEval", () => {
|
||||||
|
expect("let a = 1").toEval();
|
||||||
|
expect("a < 1").not.toEval();
|
||||||
|
expect("&&*^%#%@").not.toEval();
|
||||||
|
expect("function foo() { return 1; }; return foo();").toEval();
|
||||||
|
});
|
||||||
|
|
||||||
|
// FIXME: Will have to change when this matcher changes to use the
|
||||||
|
// "eval" function
|
||||||
|
test("toEvalTo", () => {
|
||||||
|
expect("let a = 1").toEvalTo();
|
||||||
|
expect("let a = 1").toEvalTo(undefined);
|
||||||
|
expect("return 10").toEvalTo(10);
|
||||||
|
expect("return 10").not.toEvalTo(5);
|
||||||
|
|
||||||
|
expect(() => {
|
||||||
|
expect("*^&%%").not.toEvalTo();
|
||||||
|
}).toThrow();
|
||||||
|
});
|
|
@ -16,6 +16,13 @@ console.log = (...args) => {
|
||||||
__UserOutput__.push(args.join(" "));
|
__UserOutput__.push(args.join(" "));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExpectationError extends Error {
|
||||||
|
constructor(message, fileName, lineNumber) {
|
||||||
|
super(message, fileName, lineNumber);
|
||||||
|
this.name = "ExpectationError";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Use an IIFE to avoid polluting the global namespace as much as possible
|
// Use an IIFE to avoid polluting the global namespace as much as possible
|
||||||
(() => {
|
(() => {
|
||||||
|
|
||||||
|
@ -48,13 +55,6 @@ const deepObjectEquals = (a, b) => {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExpectationError extends Error {
|
|
||||||
constructor(message, fileName, lineNumber) {
|
|
||||||
super(message, fileName, lineNumber);
|
|
||||||
this.name = "ExpectationError";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Expector {
|
class Expector {
|
||||||
constructor(target, inverted) {
|
constructor(target, inverted) {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
|
@ -72,6 +72,8 @@ class Expector {
|
||||||
}
|
}
|
||||||
|
|
||||||
toHaveLength(length) {
|
toHaveLength(length) {
|
||||||
|
this.__expect(typeof this.target.length === "number");
|
||||||
|
|
||||||
this.__doMatcher(() => {
|
this.__doMatcher(() => {
|
||||||
this.__expect(Object.is(this.target.length, length));
|
this.__expect(Object.is(this.target.length, length));
|
||||||
});
|
});
|
||||||
|
@ -80,31 +82,26 @@ class Expector {
|
||||||
toHaveProperty(property, value) {
|
toHaveProperty(property, value) {
|
||||||
this.__doMatcher(() => {
|
this.__doMatcher(() => {
|
||||||
let object = this.target;
|
let object = this.target;
|
||||||
|
|
||||||
if (typeof property === "string" && property.includes(".")) {
|
if (typeof property === "string" && property.includes(".")) {
|
||||||
let propertyArray = [];
|
let propertyArray = [];
|
||||||
|
|
||||||
while (true) {
|
while (property.includes(".")) {
|
||||||
let index = property.indexOf(".");
|
let index = property.indexOf(".");
|
||||||
if (index === -1) {
|
|
||||||
propertyArray.push(property);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
propertyArray.push(property.substring(0, index));
|
propertyArray.push(property.substring(0, index));
|
||||||
property = property.substring(index, property.length);
|
if (index + 1 >= property.length)
|
||||||
|
break;
|
||||||
|
property = property.substring(index + 1, property.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
propertyArray.push(property);
|
||||||
|
|
||||||
property = propertyArray;
|
property = propertyArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(property)) {
|
if (Array.isArray(property)) {
|
||||||
for (let key of property) {
|
for (let key of property) {
|
||||||
if (object === undefined || object === null) {
|
this.__expect(object !== undefined && object !== null);
|
||||||
if (this.inverted)
|
|
||||||
return;
|
|
||||||
throw new ExpectationError();
|
|
||||||
}
|
|
||||||
object = object[key];
|
object = object[key];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -117,51 +114,12 @@ class Expector {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toBeCloseTo(number, numDigits) {
|
|
||||||
if (numDigits === undefined)
|
|
||||||
numDigits = 2;
|
|
||||||
|
|
||||||
this.__doMatcher(() => {
|
|
||||||
this.__expect(Math.abs(number - this.target) < (10 ** -numDigits / numDigits));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toBeDefined() {
|
toBeDefined() {
|
||||||
this.__doMatcher(() => {
|
this.__doMatcher(() => {
|
||||||
this.__expect(this.target !== undefined);
|
this.__expect(this.target !== undefined);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toBeFalsey() {
|
|
||||||
this.__doMatcher(() => {
|
|
||||||
this.__expect(!this.target);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toBeGreaterThan(number) {
|
|
||||||
this.__doMatcher(() => {
|
|
||||||
this.__expect(this.target > number);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toBeGreaterThanOrEqual(number) {
|
|
||||||
this.__doMatcher(() => {
|
|
||||||
this.__expect(this.target >= number);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toBeLessThan(number) {
|
|
||||||
this.__doMatcher(() => {
|
|
||||||
this.__expect(this.target < number);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toBeLessThanOrEqual(number) {
|
|
||||||
this.__doMatcher(() => {
|
|
||||||
this.__expect(this.target <= number);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toBeInstanceOf(class_) {
|
toBeInstanceOf(class_) {
|
||||||
this.__doMatcher(() => {
|
this.__doMatcher(() => {
|
||||||
this.__expect(this.target instanceof class_);
|
this.__expect(this.target instanceof class_);
|
||||||
|
@ -174,12 +132,6 @@ class Expector {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toBeTruthy() {
|
|
||||||
this.__doMatcher(() => {
|
|
||||||
this.__expect(!!this.target);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
toBeUndefined() {
|
toBeUndefined() {
|
||||||
this.__doMatcher(() => {
|
this.__doMatcher(() => {
|
||||||
this.__expect(this.target === undefined);
|
this.__expect(this.target === undefined);
|
||||||
|
@ -199,7 +151,7 @@ class Expector {
|
||||||
if (item === element)
|
if (item === element)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ExpectationError();
|
throw new ExpectationError();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -211,7 +163,7 @@ class Expector {
|
||||||
if (deepEquals(item, element))
|
if (deepEquals(item, element))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ExpectationError();
|
throw new ExpectationError();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -224,19 +176,26 @@ class Expector {
|
||||||
|
|
||||||
toThrow(value) {
|
toThrow(value) {
|
||||||
this.__expect(typeof this.target === "function");
|
this.__expect(typeof this.target === "function");
|
||||||
this.__expect(typeof value === "string" || typeof value === "function" || value === undefined);
|
this.__expect(typeof value === "string"
|
||||||
|
|| typeof value === "function"
|
||||||
|
|| typeof value === "object"
|
||||||
|
|| value === undefined);
|
||||||
|
|
||||||
this.__doMatcher(() => {
|
this.__doMatcher(() => {
|
||||||
|
let threw = true;
|
||||||
try {
|
try {
|
||||||
this.target();
|
this.target();
|
||||||
this.__expect(false);
|
threw = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (typeof value === "string") {
|
if (typeof value === "string") {
|
||||||
this.__expect(e.message.includes(value));
|
this.__expect(e.message.includes(value));
|
||||||
} else if (typeof value === "function") {
|
} else if (typeof value === "function") {
|
||||||
this.__expect(e instanceof value);
|
this.__expect(e instanceof value);
|
||||||
|
} else if (typeof value === "object") {
|
||||||
|
this.__expect(e.message === value.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.__expect(threw);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,13 +240,14 @@ class Expector {
|
||||||
throw new ExpectationError();
|
throw new ExpectationError();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let threw;
|
||||||
try {
|
try {
|
||||||
new Function(this.target)();
|
new Function(this.target)();
|
||||||
throw new ExpectationError();
|
threw = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.name !== "SyntaxError")
|
threw = true;
|
||||||
throw new ExpectationError();
|
|
||||||
}
|
}
|
||||||
|
this.__expect(threw);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ Vector<String> tests_to_run = {
|
||||||
"object-method-shorthand.js",
|
"object-method-shorthand.js",
|
||||||
"object-spread.js",
|
"object-spread.js",
|
||||||
"tagged-template-literals.js",
|
"tagged-template-literals.js",
|
||||||
|
"test-common-tests.js",
|
||||||
"switch-basic.js",
|
"switch-basic.js",
|
||||||
"update-expression-on-member-expression.js",
|
"update-expression-on-member-expression.js",
|
||||||
};
|
};
|
||||||
|
@ -131,7 +132,7 @@ FileResults run_test(const String& path, const String& test_root)
|
||||||
// FIXME: Should be printed to stdout in a nice format
|
// FIXME: Should be printed to stdout in a nice format
|
||||||
auto& arr = interpreter->get_variable("__UserOutput__", interpreter->global_object()).as_array();
|
auto& arr = interpreter->get_variable("__UserOutput__", interpreter->global_object()).as_array();
|
||||||
for (auto& entry : arr.indexed_properties()) {
|
for (auto& entry : arr.indexed_properties()) {
|
||||||
dbg() << "OUTPUT: " << entry.value_and_attributes(&interpreter->global_object()).value.to_string(*interpreter);
|
dbg() << "OUTPUT: " << entry.value_and_attributes(&interpreter->global_object()).value.to_string_without_side_effects();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This is _so_ scuffed
|
// FIXME: This is _so_ scuffed
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue