dom.spec.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. import { describe, expect, it } from "vitest";
  2. import { addGlobalStyle, addParent, getSiblingsFrame, getUnsafeWindow, interceptEvent, isDomLoaded, isScrollable, observeElementProp, openInNewTab, preloadImages, probeElementStyle, setInnerHtmlUnsafe } from "./dom.js";
  3. //#region getUnsafeWindow
  4. describe("dom/getUnsafeWindow", () => {
  5. it("Returns the correct window objects", () => {
  6. expect(getUnsafeWindow()).toBe(window);
  7. var unsafeWindow = window;
  8. expect(getUnsafeWindow()).toBe(unsafeWindow);
  9. });
  10. });
  11. //#region addParent
  12. describe("dom/addParent", () => {
  13. it("Adds a parent to an element", () => {
  14. const container = document.createElement("div");
  15. container.id = "container";
  16. const child = document.createElement("div");
  17. child.id = "child";
  18. document.body.appendChild(child);
  19. addParent(child, container);
  20. expect(child.parentNode).toBe(container);
  21. container.remove();
  22. });
  23. });
  24. //#region addGlobalStyle
  25. describe("dom/addGlobalStyle", () => {
  26. it("Adds a global style to the document", () => {
  27. const el = addGlobalStyle(`body { background-color: red; }`);
  28. el.id = "test-style";
  29. expect(document.querySelector("head #test-style")).toBe(el);
  30. });
  31. });
  32. //#region preloadImages
  33. //TODO:FIXME: no workis
  34. describe.skip("dom/preloadImages", () => {
  35. it("Preloads images", async () => {
  36. const res = await preloadImages(["https://picsum.photos/50/50"]);
  37. expect(Array.isArray(res)).toBe(true);
  38. expect(res.every(r => r.status === "fulfilled")).toBe(true);
  39. });
  40. });
  41. //#region openInNewTab
  42. describe("dom/openInNewTab", () => {
  43. it("Via GM.openInTab", () => {
  44. let link = "", bg;
  45. // @ts-expect-error
  46. window.GM = {
  47. openInTab(href: string, background?: boolean) {
  48. link = href;
  49. bg = background;
  50. }
  51. };
  52. openInNewTab("https://example.org", true);
  53. expect(link).toBe("https://example.org");
  54. expect(bg).toBe(true);
  55. // @ts-expect-error
  56. delete window.GM;
  57. });
  58. });
  59. //#region interceptEvent
  60. describe("dom/interceptEvent", () => {
  61. it("Intercepts an event", () => {
  62. const el = document.createElement("div");
  63. el.id = "test-intercept";
  64. document.body.appendChild(el);
  65. let clickedTimes = 0;
  66. el.addEventListener("click", () => ++clickedTimes);
  67. interceptEvent(el, "click", () => true);
  68. el.addEventListener("click", () => ++clickedTimes);
  69. el.click();
  70. expect(clickedTimes).toBe(1);
  71. document.body.removeChild(el);
  72. });
  73. });
  74. //#region interceptWindowEvent
  75. describe("dom/interceptWindowEvent", () => {
  76. it("Intercepts a window event", () => {
  77. let clickedTimes = 0;
  78. const inc = () => clickedTimes++;
  79. window.addEventListener("foo", inc);
  80. interceptEvent(window, "foo", () => true);
  81. window.addEventListener("foo", inc);
  82. window.dispatchEvent(new Event("foo"));
  83. expect(clickedTimes).toBe(1);
  84. window.removeEventListener("foo", inc);
  85. });
  86. });
  87. //#region observeElementProp
  88. //TODO:FIXME: no workio
  89. describe.skip("dom/observeElementProp", () => {
  90. it("Observes an element property", () => {
  91. const el = document.createElement("input");
  92. el.type = "text";
  93. document.body.appendChild(el);
  94. let newVal = "";
  95. observeElementProp(el, "value", (_oldVal, newVal) => {
  96. newVal = newVal;
  97. });
  98. el.value = "foo";
  99. expect(newVal).toBe("foo");
  100. });
  101. });
  102. //#region getSiblingsFrame
  103. describe("dom/getSiblingsFrame", () => {
  104. it("Returns the correct frame", () => {
  105. const container = document.createElement("div");
  106. for(let i = 0; i < 10; i++) {
  107. const el = document.createElement("div");
  108. el.id = `e${i}`;
  109. container.appendChild(el);
  110. }
  111. const cntrEl = container.querySelector<HTMLElement>("#e5")!;
  112. expect(getSiblingsFrame(cntrEl, 2).map(e => e.id)).toEqual(["e5", "e6"]);
  113. expect(getSiblingsFrame(cntrEl, 2, "top", false).map(e => e.id)).toEqual(["e6", "e7"]);
  114. expect(getSiblingsFrame(cntrEl, 2, "bottom", false).map(e => e.id)).toEqual(["e3", "e4"]);
  115. expect(getSiblingsFrame(cntrEl, 2, "center-top", false).map(e => e.id)).toEqual(["e4", "e6"]);
  116. expect(getSiblingsFrame(cntrEl, 3, "center-top", true).map(e => e.id)).toEqual(["e4", "e5", "e6"]);
  117. expect(getSiblingsFrame(cntrEl, 4, "center-top", true).map(e => e.id)).toEqual(["e4", "e5", "e6", "e7"]);
  118. expect(getSiblingsFrame(cntrEl, 4, "center-bottom", true).map(e => e.id)).toEqual(["e3", "e4", "e5", "e6"]);
  119. });
  120. });
  121. //#region setInnerHtmlUnsafe
  122. describe("dom/setInnerHtmlUnsafe", () => {
  123. it("Sets inner HTML", () => {
  124. const el = document.createElement("div");
  125. setInnerHtmlUnsafe(el, "<div>foo</div>");
  126. expect(el.querySelector("div")?.textContent).toBe("foo");
  127. });
  128. });
  129. //#region probeElementStyle
  130. //TODO:FIXME: no workiong
  131. describe.skip("dom/probeElementStyle", () => {
  132. it("Resolves a CSS variable", async () => {
  133. addGlobalStyle(`:root { --foo: #f00; --bar: var(--foo, #00f); }`);
  134. const tryResolveCol = (i = 0) => new Promise<string>((res, rej) => {
  135. if(i > 100)
  136. return rej(new Error("Could not resolve color after 100 tries"));
  137. const probedCol = probeElementStyle(
  138. (style) => style.backgroundColor,
  139. () => {
  140. const elem = document.createElement("span");
  141. elem.style.backgroundColor = "var(--foo, #000)";
  142. return elem;
  143. },
  144. true,
  145. );
  146. if(probedCol.length === 0 || probedCol.match(/^rgba?\((?:(?:255,\s?255,\s?255)|(?:0,\s?0,\s?0))/) || probedCol.match(/^#(?:fff(?:fff)?|000(?:000)?)/))
  147. return setTimeout(async () => res(await tryResolveCol(++i)), 100);
  148. return res(probedCol);
  149. });
  150. const val = await tryResolveCol();
  151. expect(val).toBe("rgb(255, 0, 0)");
  152. });
  153. });
  154. const initialState = document.readyState;
  155. //#region isDomLoaded
  156. describe.skip("dom/isDomLoaded", () => {
  157. it("Returns the correct state", () => {
  158. // doesn't work cause the lib isn't loaded before DOMContentLoaded
  159. expect(isDomLoaded()).toBe(initialState === "complete");
  160. });
  161. });
  162. //#region onDomLoad
  163. describe.skip("dom/onDomLoad", () => {
  164. // see above
  165. });