summaryrefslogtreecommitdiff
path: root/Libraries/LibJS/Tests/builtins/Proxy/Proxy.handler-set.js
blob: dd45c51b4bbc3f2f42fe7db269d228a68b8967f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
describe("[[Set]] trap normal behavior", () => {
    test("forwarding when not defined in handler", () => {
        expect((new Proxy({}, { set: undefined }).foo = 1)).toBe(1);
        expect((new Proxy({}, { set: null }).foo = 1)).toBe(1);
        expect((new Proxy({}, {}).foo = 1)).toBe(1);
    });

    test("correct arguments supplied to trap", () => {
        let o = {};
        let p = new Proxy(o, {
            set(target, prop, value, receiver) {
                expect(target).toBe(o);
                expect(prop).toBe("foo");
                expect(value).toBe(10);
                expect(receiver).toBe(p);
                return true;
            },
        });

        p.foo = 10;
    });

    test("conditional return value", () => {
        let p = new Proxy(
            {},
            {
                set(target, prop, value) {
                    if (target[prop] === value) {
                        target[prop] *= 2;
                    } else {
                        target[prop] = value;
                    }
                },
            }
        );

        p.foo = 10;
        expect(p.foo).toBe(10);
        p.foo = 10;
        expect(p.foo).toBe(20);
        p.foo = 10;
        expect(p.foo).toBe(10);
        p[Symbol.hasInstance] = "foo";
        expect(p[Symbol.hasInstance]).toBe("foo");
    });

    test("custom receiver value", () => {
        const o = {};
        const r = {};
        let p = new Proxy(o, {
            set(target, property, value, receiver) {
                receiver[property] = value;
                return true;
            },
        });

        expect(Reflect.set(p, "foo", 42, r)).toBe(true);
        expect(o.foo).toBeUndefined();
        expect(r.foo).toBe(42);
    });
});

describe("[[Set]] invariants", () => {
    test("cannot return true for a non-configurable, non-writable property", () => {
        let o = {};
        Object.defineProperty(o, "foo", { value: 10 });

        let p = new Proxy(o, {
            set() {
                return true;
            },
        });

        expect(() => {
            p.foo = 12;
        }).toThrowWithMessage(
            TypeError,
            "Proxy handler's set trap violates invariant: cannot return true for a property on the target which is a non-configurable, non-writable own data property"
        );
    });

    test("cannot return true for a non-configurable accessor property with no setter", () => {
        let o = {};
        Object.defineProperty(o, "foo", { get() {} });

        let p = new Proxy(o, {
            set() {
                return true;
            },
        });

        expect(() => {
            p.foo = 12;
        }).toThrowWithMessage(
            TypeError,
            "Proxy handler's set trap violates invariant: cannot return true for a property on the target which is a non-configurable own accessor property with an undefined set attribute"
        );
    });
});