diff options
author | 2022-11-01 21:25:30 -0700 | |
---|---|---|
committer | 2022-11-01 21:25:30 -0700 | |
commit | 54e7a6f57a80ac3a9e96348f0f796b219c958b73 (patch) | |
tree | 5155a900fb7d371a564c7e5c79d78f5518d19348 /test | |
parent | 32826119fc69feb07faa581bed0b3fd76a154744 (diff) | |
download | bun-54e7a6f57a80ac3a9e96348f0f796b219c958b73.tar.gz bun-54e7a6f57a80ac3a9e96348f0f796b219c958b73.tar.zst bun-54e7a6f57a80ac3a9e96348f0f796b219c958b73.zip |
typescript decorators round 2 (#1445)
* __decorateClass, __decorateParam, lit test, wiptest test
* decorator factories test
* parameter decorator test
* test for decorators with constructor parameter properties
* Fix issue with `CryptoKey` and `SubtleCrypto` constructors
* Limit concurrency for GitHub Actions due to issues with cache poisoning
If multiple actions are running, sometimes the cache is poisoned from another action. We need to fix this, but this is an interim measure to make actions less flaky
* Make these tests better
* Move this to dependencies so the .a files upload
* Fixup
* temporary fix
* Limit concurrency for MacOS Object actions
* try againn
* againn
* Make `"tls"` an explicit object we pass instead of implicit top-level options
cc @Electroid @colinhacks
* Update server.zig
* Prefer `BUN_PORT` over `PORT`
* Fix typo in homebrew action
* Run homebrew action when release is edited
* Check published_at instead of draft in GitHub action
* Implement `process.release`
* Add missing dependencies to `make devcontainer`
* Allow overriding node polyfills via `BUN_OVERRIDE_MODULE_PATH`
* Add a stub for io_darwin on linux
cc @sno2 hopefully this helps but i'm not sure
* Add missing `break`
* Download more RAM
* feat(core): optimize zig slice (#1408)
* feat(core): optimize zig slice
* address concerns
* Remove webcrypto from vendor-without-check
* Update default tsconfig (#1418)
Co-authored-by: Colin McDonnell <colinmcd@alum.mit.edu>
* Enable `BUN_OVERRIDE_MODULE_PATH` in `bun wiptest`
* Upgrade WebKit
* space
* Support getting cached values and pending activity in the bindings generator
* Remove :scissors: function
* constructor creation, initializers, handle static and computed fields with decorators
* Updating libuwebsockets C API (#1423)
* fix for repeated regex match calls and fix for '^' in character classes (#1419)
* tests and formatting
* fix for ^ in character class
* formatting
* test for repeated match and exec calls
* create oniguruma regex for each exec/test
* check errorCode from creating oniguruma regexp and always return {} on failure
* oops
* call onig_initialize once
* fix incorrect escaping, removed unnecessary oniguruma settings
* tests for "-" and "^" in character classes
* free regex object before returns
* force gc for some tests
* Update React fizz server (#1432)
* Update fizz server
* Use production build
Co-authored-by: Colin McDonnell <colinmcd@alum.mit.edu>
* more decorator tests
* optional setup function for loading elements, simulate clicks in lit test
* fix createWriteStream (#1433)
* fix createWriteStream
* remove comment
* Update build docs and commands for dev containers (#1438)
* Update build documentation for dev containers
* Add devcontainer-rebuild make target
* Add make devcontainer-sh target
* Fix missing .PHONY for vendor-without-check (#1437)
* Fix check for ninja on Debian/Ubuntu (#1436)
Even though the package is named ninja-build, the ninja binary is still
named ninja, so use `which ninja` to check for it
* Fix #1410
woops
* await on DOMContentLoaded for elements instead of setup function
* avoid lowering class if no decorators
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Co-authored-by: Ashcon Partovi <ashcon@partovi.net>
Co-authored-by: Carter Snook <cartersnook04@gmail.com>
Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
Co-authored-by: Colin McDonnell <colinmcd@alum.mit.edu>
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: Joรฃo Paquim <jpaquim@users.noreply.github.com>
Diffstat (limited to 'test')
-rw-r--r-- | test/bun.js/decorators.test.ts | 787 | ||||
-rw-r--r-- | test/scripts/snippets.json | 1 | ||||
-rw-r--r-- | test/snippets/package.json | 1 | ||||
-rw-r--r-- | test/snippets/simple-lit-example.ts | 76 |
4 files changed, 865 insertions, 0 deletions
diff --git a/test/bun.js/decorators.test.ts b/test/bun.js/decorators.test.ts new file mode 100644 index 000000000..545030ef1 --- /dev/null +++ b/test/bun.js/decorators.test.ts @@ -0,0 +1,787 @@ +import { test, expect } from "bun:test"; + +test("decorator order of evaluation", () => { + let counter = 0; + const computedProp: unique symbol = Symbol("computedProp"); + + @decorator1 + @decorator2 + class BugReport { + @decorator7 + type: string; + + @decorator3 + x: number = 20; + + @decorator5 + private _y: number = 12; + + @decorator10 + get y() { + return this._y; + } + @decorator11 + set y(newY: number) { + this._y = newY; + } + + @decorator9 + [computedProp]: string = "yes"; + + constructor(@decorator8 type: string) { + this.type = type; + } + + @decorator6 + move(newX: number, @decorator12 newY: number) { + this.x = newX; + this._y = newY; + } + + @decorator4 + jump() { + this._y += 30; + } + } + + function decorator1(target, propertyKey) { + expect(counter++).toBe(11); + expect(target === BugReport).toBe(true); + expect(propertyKey).toBe(undefined); + } + + function decorator2(target, propertyKey) { + expect(counter++).toBe(10); + expect(target === BugReport).toBe(true); + expect(propertyKey).toBe(undefined); + } + + function decorator3(target, propertyKey) { + expect(counter++).toBe(1); + expect(target === BugReport.prototype).toBe(true); + expect(propertyKey).toBe("x"); + } + + function decorator4(target, propertyKey) { + expect(counter++).toBe(8); + expect(target === BugReport.prototype).toBe(true); + expect(propertyKey).toBe("jump"); + } + + function decorator5(target, propertyKey) { + expect(counter++).toBe(2); + expect(target === BugReport.prototype).toBe(true); + expect(propertyKey).toBe("_y"); + } + + function decorator6(target, propertyKey) { + expect(counter++).toBe(7); + expect(target === BugReport.prototype).toBe(true); + expect(propertyKey).toBe("move"); + } + + function decorator7(target, propertyKey) { + expect(counter++).toBe(0); + expect(target === BugReport.prototype).toBe(true); + expect(propertyKey).toBe("type"); + } + + function decorator8(target, propertyKey) { + expect(counter++).toBe(9); + expect(target === BugReport).toBe(true); + expect(propertyKey).toBe(undefined); + } + + function decorator9(target, propertyKey) { + expect(counter++).toBe(5); + expect(target === BugReport.prototype).toBe(true); + expect(propertyKey).toBe(computedProp); + } + + function decorator10(target, propertyKey) { + expect(counter++).toBe(3); + expect(target === BugReport.prototype).toBe(true); + expect(propertyKey).toBe("y"); + } + + function decorator11(target, propertyKey) { + expect(counter++).toBe(4); + expect(target === BugReport.prototype).toBe(true); + expect(propertyKey).toBe("y"); + } + + function decorator12(target, propertyKey) { + expect(counter++).toBe(6); + expect(target === BugReport.prototype).toBe(true); + expect(propertyKey).toBe("move"); + } +}); + +test("decorator factories order of evaluation", () => { + let counter = 0; + const computedProp: unique symbol = Symbol("computedProp"); + + @decorator1() + @decorator2() + class BugReport { + @decorator7() + type: string; + + @decorator3() + x: number = 20; + + @decorator5() + private _y: number = 12; + + @decorator10() + get y() { + return this._y; + } + @decorator11() + set y(newY: number) { + this._y = newY; + } + + @decorator9() + [computedProp]: string = "yes"; + + constructor(@decorator8() type: string) { + this.type = type; + } + + @decorator6() + move(newX: number, @decorator12() newY: number) { + this.x = newX; + this._y = newY; + } + + @decorator4() + jump() { + this._y += 30; + } + } + + function decorator1() { + expect(counter++).toBe(18); + return function (target, descriptorKey) { + expect(counter++).toBe(23); + }; + } + + function decorator2() { + expect(counter++).toBe(19); + return function (target, descriptorKey) { + expect(counter++).toBe(22); + }; + } + + function decorator3() { + expect(counter++).toBe(2); + return function (target, descriptorKey) { + expect(counter++).toBe(3); + }; + } + + function decorator4() { + expect(counter++).toBe(16); + return function (target, descriptorKey) { + expect(counter++).toBe(17); + }; + } + + function decorator5() { + expect(counter++).toBe(4); + return function (target, descriptorKey) { + expect(counter++).toBe(5); + }; + } + + function decorator6() { + expect(counter++).toBe(12); + return function (target, descriptorKey) { + expect(counter++).toBe(15); + }; + } + + function decorator7() { + expect(counter++).toBe(0); + return function (target, descriptorKey) { + expect(counter++).toBe(1); + }; + } + + function decorator8() { + expect(counter++).toBe(20); + return function (target, descriptorKey) { + expect(counter++).toBe(21); + }; + } + + function decorator9() { + expect(counter++).toBe(10); + return function (target, descriptorKey) { + expect(counter++).toBe(11); + }; + } + + function decorator10() { + expect(counter++).toBe(6); + return function (target, descriptorKey) { + expect(counter++).toBe(7); + }; + } + + function decorator11() { + expect(counter++).toBe(8); + return function (target, descriptorKey) { + expect(counter++).toBe(9); + }; + } + + function decorator12() { + expect(counter++).toBe(13); + return function (target, descriptorKey) { + expect(counter++).toBe(14); + }; + } +}); + +test("parameter decorators", () => { + let counter = 0; + class HappyDecorator { + width: number; + height: number; + x: number; + y: number; + + move(@d4 x: number, @d5 @d6 y: number) { + this.x = x; + this.y = y; + } + + constructor( + one: number, + two: string, + three: boolean, + @d1 @d2 width: number, + @d3 height: number + ) { + this.width = width; + this.height = height; + } + + dance(@d7 @d8 intensity: number) { + this.width *= intensity; + this.height *= intensity; + } + } + + function d1(target, propertyKey, parameterIndex) { + expect(counter++).toBe(7); + expect(target === HappyDecorator).toBe(true); + expect(propertyKey).toBe(undefined); + expect(parameterIndex).toBe(3); + } + + function d2(target, propertyKey, parameterIndex) { + expect(counter++).toBe(6); + expect(target === HappyDecorator).toBe(true); + expect(propertyKey).toBe(undefined); + expect(parameterIndex).toBe(3); + } + + function d3(target, propertyKey, parameterIndex) { + expect(counter++).toBe(5); + expect(target === HappyDecorator).toBe(true); + expect(propertyKey).toBe(undefined); + expect(parameterIndex).toBe(4); + } + + function d4(target, propertyKey, parameterIndex) { + expect(counter++).toBe(2); + expect(target === HappyDecorator.prototype).toBe(true); + expect(propertyKey).toBe("move"); + expect(parameterIndex).toBe(0); + } + + function d5(target, propertyKey, parameterIndex) { + expect(counter++).toBe(1); + expect(target === HappyDecorator.prototype).toBe(true); + expect(propertyKey).toBe("move"); + expect(parameterIndex).toBe(1); + } + + function d6(target, propertyKey, parameterIndex) { + expect(counter++).toBe(0); + expect(target === HappyDecorator.prototype).toBe(true); + expect(propertyKey).toBe("move"); + expect(parameterIndex).toBe(1); + } + + function d7(target, propertyKey, parameterIndex) { + expect(counter++).toBe(4); + expect(target === HappyDecorator.prototype).toBe(true); + expect(propertyKey).toBe("dance"); + expect(parameterIndex).toBe(0); + } + + function d8(target, propertyKey, parameterIndex) { + expect(counter++).toBe(3); + expect(target === HappyDecorator.prototype).toBe(true); + expect(propertyKey).toBe("dance"); + expect(parameterIndex).toBe(0); + } + + class Maybe { + constructor( + @m1 private x: number, + @m2 public y: boolean, + @m3 protected z: string + ) {} + } + + function m1(target, propertyKey, index) { + expect(target === Maybe).toBe(true); + expect(propertyKey).toBe(undefined); + expect(index).toBe(0); + } + + function m2(target, propertyKey, index) { + expect(target === Maybe).toBe(true); + expect(propertyKey).toBe(undefined); + expect(index).toBe(1); + } + + function m3(target, propertyKey, index) { + expect(target === Maybe).toBe(true); + expect(propertyKey).toBe(undefined); + expect(index).toBe(2); + } +}); + +test("decorators random", () => { + @Frozen + class IceCream {} + + function Frozen(constructor: Function) { + Object.freeze(constructor); + Object.freeze(constructor.prototype); + } + + expect(Object.isFrozen(IceCream)).toBe(true); + + class IceCreamComponent { + @Emoji() + flavor = "vanilla"; + } + + // Property Decorator + function Emoji() { + return function (target: Object, key: string | symbol) { + let val = target[key]; + + const getter = () => { + return val; + }; + const setter = (next) => { + val = `๐ฆ ${next} ๐ฆ`; + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + }; + } + + const iceCream = new IceCreamComponent(); + expect(iceCream.flavor === "๐ฆ vanilla ๐ฆ").toBe(true); + iceCream.flavor = "chocolate"; + expect(iceCream.flavor === "๐ฆ chocolate ๐ฆ").toBe(true); + + const i: unique symbol = Symbol.for("i"); + const h: unique symbol = Symbol.for("h"); + const t: unique symbol = Symbol.for("t"); + const q: unique symbol = Symbol.for("q"); + const p: unique symbol = Symbol.for("p"); + const u3: unique symbol = Symbol.for("u3"); + const u5: unique symbol = Symbol.for("u5"); + const u6: unique symbol = Symbol.for("u6"); + const u8: unique symbol = Symbol.for("u8"); + + class S { + @StringAppender("๐") k = 35; + @StringAppender("๐ค ") static j = 4; + @StringAppender("๐ตโ๐ซ") private static [h] = 30; + @StringAppender("๐คฏ") private static u = 60; + @StringAppender("๐คช") private [t] = 32; + @StringAppender("๐ค") [i] = 8; + @StringAppender("๐") private e = 10; + @StringAppender("๐ป") static [q] = 202; + @StringAppender("๐") r = S[h]; + _y: number; + @StringAppender("๐คก") get y() { + return this._y; + } + set y(next) { + this._y = next; + } + #o = 100; + + @StringAppender("๐") u1: number; + @StringAppender("๐ฅณ") static u2: number; + @StringAppender("๐ค") private static [u3]: number; + @StringAppender("๐ฅบ") private static u4: number; + @StringAppender("๐คฏ") private [u5]: number; + @StringAppender("๐คฉ") [u6]: number; + @StringAppender("โน๏ธ") private u7: number; + @StringAppender("๐") static [u8]: number; + + @StringAppender("๐ค") u9 = this.u1; + @StringAppender("๐คจ") u10 = this.u2; + @StringAppender("๐") u11 = S[u3]; + @StringAppender("๐") u12 = S.u4; + @StringAppender("๐") u13 = this[u5]; + @StringAppender("๐") u14 = this[u6]; + @StringAppender("๐ถ") u15 = this.u7; + @StringAppender("๐") u16 = S[u8]; + + constructor() { + this.k = 3; + expect(this.k).toBe("3 ๐"); + expect(S.j).toBe(4); + expect(this[i]).toBe("8 ๐ค"); + expect(this.e).toBe("10 ๐"); + expect(S[h]).toBe(30); + expect(S.u).toBe(60); + expect(this[t]).toBe("32 ๐คช"); + expect(S[q]).toBe(202); + expect(this.#o).toBe(100); + expect(this.r).toBe("30 ๐"); + expect(this.y).toBe(undefined); + this.y = 100; + expect(this.y).toBe(100); + + expect(this.u1).toBe(undefined); + expect(S.u2).toBe(undefined); + expect(S[u3]).toBe(undefined); + expect(S.u4).toBe(undefined); + expect(this[u5]).toBe(undefined); + expect(this[u6]).toBe(undefined); + expect(this.u7).toBe(undefined); + expect(S[u8]).toBe(undefined); + + expect(this.u9).toBe("undefined ๐ค"); + expect(this.u10).toBe("undefined ๐คจ"); + expect(this.u11).toBe("undefined ๐"); + expect(this.u12).toBe("undefined ๐"); + expect(this.u13).toBe("undefined ๐"); + expect(this.u14).toBe("undefined ๐"); + expect(this.u15).toBe("undefined ๐ถ"); + expect(this.u16).toBe("undefined ๐"); + + this.u1 = 100; + expect(this.u1).toBe("100 ๐"); + S.u2 = 100; + expect(S.u2).toBe("100 ๐ฅณ"); + S[u3] = 100; + expect(S[u3]).toBe("100 ๐ค"); + S.u4 = 100; + expect(S.u4).toBe("100 ๐ฅบ"); + this[u5] = 100; + expect(this[u5]).toBe("100 ๐คฏ"); + this[u6] = 100; + expect(this[u6]).toBe("100 ๐คฉ"); + this.u7 = 100; + expect(this.u7).toBe("100 โน๏ธ"); + S[u8] = 100; + expect(S[u8]).toBe("100 ๐"); + + expect(this.u9).toBe("undefined ๐ค"); + expect(this.u10).toBe("undefined ๐คจ"); + expect(this.u11).toBe("undefined ๐"); + expect(this.u12).toBe("undefined ๐"); + expect(this.u13).toBe("undefined ๐"); + expect(this.u14).toBe("undefined ๐"); + expect(this.u15).toBe("undefined ๐ถ"); + expect(this.u16).toBe("undefined ๐"); + } + } + + let s = new S(); + expect(s.u9).toBe("undefined ๐ค"); + expect(s.u10).toBe("undefined ๐คจ"); + expect(s.u11).toBe("undefined ๐"); + expect(s.u12).toBe("undefined ๐"); + expect(s.u13).toBe("undefined ๐"); + expect(s.u14).toBe("undefined ๐"); + expect(s.u15).toBe("undefined ๐ถ"); + expect(s.u16).toBe("undefined ๐"); + + s.u9 = 35; + expect(s.u9).toBe("35 ๐ค"); + s.u10 = 36; + expect(s.u10).toBe("36 ๐คจ"); + s.u11 = 37; + expect(s.u11).toBe("37 ๐"); + s.u12 = 38; + expect(s.u12).toBe("38 ๐"); + s.u13 = 39; + expect(s.u13).toBe("39 ๐"); + s.u14 = 40; + expect(s.u14).toBe("40 ๐"); + s.u15 = 41; + expect(s.u15).toBe("41 ๐ถ"); + s.u16 = 42; + expect(s.u16).toBe("42 ๐"); + + function StringAppender(emoji: string) { + return function (target: Object, key: string | symbol) { + let val = target[key]; + + const getter = () => { + return val; + }; + const setter = (value) => { + val = `${value} ${emoji}`; + }; + + Object.defineProperty(target, key, { + get: getter, + set: setter, + enumerable: true, + configurable: true, + }); + }; + } +}); + +test("class field order", () => { + class N { + l = 455; + } + class M { + u = 4; + @d1 w = 9; + constructor() { + // this.w = 9 should be moved here + expect(this.u).toBe(4); + expect(this.w).toBe(9); + this.u = 3; + this.w = 6; + expect(this.u).toBe(3); + expect(this.w).toBe(6); + } + } + + function d1(target, propertyKey) { + expect(target === M.prototype).toBe(true); + expect(propertyKey).toBe("w"); + } + + let m = new M(); + expect(m.u).toBe(3); + expect(m.w).toBe(6); +}); + +test("changing static method", () => { + class A { + static bar() { + return 1; + } + } + + @changeMethodReturn("bar", 5) + class A_2 { + static bar() { + return 7; + } + } + + function changeMethodReturn(method, value) { + return function (target) { + target[method] = function () { + return value; + }; + return target; + }; + } + + @changeMethodReturn("bar", 2) + class B extends A {} + + @changeMethodReturn("bar", 9) + class C extends B {} + + expect(A_2.bar()).toBe(5); + expect(A.bar()).toBe(1); + expect(B.bar()).toBe(2); + expect(C.bar()).toBe(9); +}); + +test("class extending from another class", () => { + class A { + a: number; + constructor() { + this.a = 3; + } + } + + class B extends A { + a: number = 9; + } + + expect(new A().a).toBe(3); + expect(new B().a).toBe(9); + + class C { + a: number = 80; + } + + class D extends C { + a: number = 32; + constructor() { + super(); + } + } + + expect(new C().a).toBe(80); + expect(new D().a).toBe(32); + + class E { + a: number = 40; + constructor() { + expect(this.a).toBe(40); + } + } + + class F extends E { + @d1 a: number = 50; + constructor() { + super(); + expect(this.a).toBe(50); + this.a = 60; + expect(this.a).toBe(60); + } + } + + function d1(target) { + target.a = 100; + } +}); + +test("decorated fields moving to constructor", () => { + class A { + @d1 a = 3; + @d2 b = 4; + @d3 c = 5; + } + + function d1(target, propertyKey) { + expect(target === A.prototype).toBe(true); + expect(propertyKey).toBe("a"); + } + + function d2(target, propertyKey) { + expect(target === A.prototype).toBe(true); + expect(propertyKey).toBe("b"); + } + + function d3(target, propertyKey) { + expect(target === A.prototype).toBe(true); + expect(propertyKey).toBe("c"); + } + + let a = new A(); + expect(a.a).toBe(3); + expect(a.b).toBe(4); + expect(a.c).toBe(5); +}); + +test("only class decorator", () => { + let a = 0; + @d1 + class A {} + + let aa = new A(); + + function d1(target) { + a = 1; + expect(target).toBe(A); + } + + expect(a).toBe(1); +}); + +test("only property decorators", () => { + let a = 0; + class A { + @d1 a() {} + } + + let b = 0; + class B { + @d2 b = 3; + } + + let c = 0; + class C { + @d3 get c() { + return 3; + } + } + + function d1(target, propertyKey) { + a = 1; + expect(target === A.prototype).toBe(true); + expect(propertyKey).toBe("a"); + } + expect(a).toBe(1); + + function d2(target, propertyKey) { + b = 1; + expect(target === B.prototype).toBe(true); + expect(propertyKey).toBe("b"); + } + expect(b).toBe(1); + + function d3(target, propertyKey) { + c = 1; + expect(target === C.prototype).toBe(true); + expect(propertyKey).toBe("c"); + } + expect(c).toBe(1); +}); + +test("only argument decorators", () => { + let a = 0; + class A { + a(@d1 a: string) {} + } + + function d1(target, propertyKey, parameterIndex) { + a = 1; + expect(target === A.prototype).toBe(true); + expect(propertyKey).toBe("a"); + expect(parameterIndex).toBe(0); + } + + expect(a).toBe(1); +}); + +test("no decorators", () => { + let a = 0; + class A { + b: number; + constructor() { + a = 1; + this.b = 300000; + } + } + + let aa = new A(); + expect(a).toBe(1); + expect(aa.b).toBe(300000); +}); diff --git a/test/scripts/snippets.json b/test/scripts/snippets.json index ebdec23d3..1829eb9c4 100644 --- a/test/scripts/snippets.json +++ b/test/scripts/snippets.json @@ -25,6 +25,7 @@ "/optional-chain-with-function.js", "/template-literal.js", "/number-literal-bug.js", + "/simple-lit-example.ts", "/caught-require.js", "/package-json-utf8.js", "/multiple-var.js", diff --git a/test/snippets/package.json b/test/snippets/package.json index 07b349f86..0c05b97be 100644 --- a/test/snippets/package.json +++ b/test/snippets/package.json @@ -4,6 +4,7 @@ "dependencies": { "@emotion/core": "^11.0.0", "@emotion/react": "^11.4.1", + "lit": "^2.4.0", "lodash": "^4.17.21", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/test/snippets/simple-lit-example.ts b/test/snippets/simple-lit-example.ts new file mode 100644 index 000000000..34446e418 --- /dev/null +++ b/test/snippets/simple-lit-example.ts @@ -0,0 +1,76 @@ +import { LitElement, html, css } from "lit"; +import { customElement, property, eventOptions } from "lit/decorators.js"; + +var loadedResolve; +var loadedPromise = new Promise((resolve) => { + loadedResolve = resolve; +}); + +if (document?.readyState === "loading") { + document.addEventListener( + "DOMContentLoaded", + () => { + loadedResolve(); + }, + { once: true } + ); +} else { + loadedResolve(); +} + +@customElement("my-element") +export class MyElement extends LitElement { + static styles = css` + :host { + display: inline-block; + padding: 10px; + background: lightgray; + } + .planet { + color: var(--planet-color, blue); + } + `; + + @property() planet = "Earth"; + + render() { + return html` + <span @click=${this.togglePlanet} class="planet" id="planet-id" + >${this.planet}</span + > + `; + } + + @eventOptions({ once: true }) + togglePlanet() { + this.planet = this.planet === "Earth" ? "Mars" : "Earth"; + } +} + +function setup() { + let element = document.createElement("my-element"); + element.id = "my-element-id"; + document.body.appendChild(element); +} + +export async function test() { + setup(); + await loadedPromise; + + let element = document.getElementById("my-element-id"); + let shadowRoot = element.shadowRoot; + let planet = shadowRoot.getElementById("planet-id"); + if (element.__planet !== "Earth") { + throw new Error("Unexpected planet name: " + element.__planet); + } + planet.click(); + if (element.__planet !== "Mars") { + throw new Error("Unexpected planet name: " + element.__planet); + } + planet.click(); + if (element.__planet !== "Mars") { + throw new Error("Unexpected planet name: " + element.__planet); + } + + return testDone(import.meta.url); +} |