Ver Fonte

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
Matthew Olsson há 5 anos atrás
pai
commit
b86faeaeef

+ 224 - 0
Libraries/LibJS/Tests/test-common-tests.js

@@ -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();
+});

+ 35 - 75
Libraries/LibJS/Tests/test-common.js

@@ -16,6 +16,13 @@ console.log = (...args) => {
     __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
 (() => {
 
@@ -48,13 +55,6 @@ const deepObjectEquals = (a, b) => {
     return true;
 }
 
-class ExpectationError extends Error {
-    constructor(message, fileName, lineNumber) {
-        super(message, fileName, lineNumber);
-        this.name = "ExpectationError";
-    }
-}
-
 class Expector {
     constructor(target, inverted) {
         this.target = target;
@@ -72,6 +72,8 @@ class Expector {
     }
 
     toHaveLength(length) {
+        this.__expect(typeof this.target.length === "number");
+
         this.__doMatcher(() => {
             this.__expect(Object.is(this.target.length, length));
         });
@@ -80,31 +82,26 @@ class Expector {
     toHaveProperty(property, value) {
         this.__doMatcher(() => {
             let object = this.target;
-    
+
             if (typeof property === "string" && property.includes(".")) {
                 let propertyArray = [];
-    
-                while (true) {
+
+                while (property.includes(".")) {
                     let index = property.indexOf(".");
-                    if (index === -1) {
-                        propertyArray.push(property);
-                        break;
-                    }
-    
                     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;
             }
-    
+
             if (Array.isArray(property)) {
                 for (let key of property) {
-                    if (object === undefined || object === null) {
-                        if (this.inverted)
-                            return;
-                        throw new ExpectationError();
-                    }
+                    this.__expect(object !== undefined && object !== null);
                     object = object[key];
                 }
             } 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() {
         this.__doMatcher(() => {
             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_) {
         this.__doMatcher(() => {
             this.__expect(this.target instanceof class_);
@@ -174,12 +132,6 @@ class Expector {
         });
     }
 
-    toBeTruthy() {
-        this.__doMatcher(() => {
-            this.__expect(!!this.target);
-        });
-    }
-
     toBeUndefined() {
         this.__doMatcher(() => {
             this.__expect(this.target === undefined);
@@ -199,7 +151,7 @@ class Expector {
                 if (item === element)
                     return;
             }
-            
+
             throw new ExpectationError();
         });
     }
@@ -211,7 +163,7 @@ class Expector {
                 if (deepEquals(item, element))
                     return;
             }
-            
+
             throw new ExpectationError();
         });
     }
@@ -224,19 +176,26 @@ class Expector {
 
     toThrow(value) {
         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(() => {
+            let threw = true;
             try {
                 this.target();
-                this.__expect(false);
+                threw = false;
             } catch (e) {
                 if (typeof value === "string") {
                     this.__expect(e.message.includes(value));
                 } else if (typeof value === "function") {
                     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();
             }
         } else {
+            let threw;
             try {
                 new Function(this.target)();
-                throw new ExpectationError();
+                threw = false;
             } catch (e) {
-                if (e.name !== "SyntaxError") 
-                    throw new ExpectationError();
+                threw = true;
             }
+            this.__expect(threw);
         }
     }
 

+ 2 - 1
Userland/test-js.cpp

@@ -58,6 +58,7 @@ Vector<String> tests_to_run = {
     "object-method-shorthand.js",
     "object-spread.js",
     "tagged-template-literals.js",
+    "test-common-tests.js",
     "switch-basic.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
     auto& arr = interpreter->get_variable("__UserOutput__", interpreter->global_object()).as_array();
     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