a reactive (signals based) hypermedia web framework (wip) stormlightlabs.github.io/volt/
hypermedia frontend signals
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 223 lines 6.6 kB view raw
1import { 2 createScopeMetadata, 3 getPin, 4 getPins, 5 getScopeMetadata, 6 incrementUidCounter, 7 registerPin, 8} from "$core/scope-metadata"; 9import type { Scope } from "$types/volt"; 10import { beforeEach, describe, expect, it } from "vitest"; 11 12describe("Scope Metadata", () => { 13 let testElement: HTMLDivElement; 14 let testScope: Scope; 15 16 beforeEach(() => { 17 testElement = document.createElement("div"); 18 testScope = {}; 19 }); 20 21 describe("createScopeMetadata", () => { 22 it("creates metadata for a scope", () => { 23 const metadata = createScopeMetadata(testScope, testElement); 24 25 expect(metadata).toBeDefined(); 26 expect(metadata.origin).toBe(testElement); 27 expect(metadata.pins).toBeInstanceOf(Map); 28 expect(metadata.uidCounter).toBe(0); 29 }); 30 31 it("stores metadata in WeakMap", () => { 32 createScopeMetadata(testScope, testElement); 33 34 const retrieved = getScopeMetadata(testScope); 35 expect(retrieved).toBeDefined(); 36 expect(retrieved?.origin).toBe(testElement); 37 }); 38 39 it("supports optional parent scope", () => { 40 const parentScope: Scope = {}; 41 const metadata = createScopeMetadata(testScope, testElement, parentScope); 42 43 expect(metadata.parent).toBe(parentScope); 44 }); 45 46 it("initializes empty pin registry", () => { 47 createScopeMetadata(testScope, testElement); 48 49 const metadata = getScopeMetadata(testScope); 50 expect(metadata?.pins.size).toBe(0); 51 }); 52 }); 53 54 describe("getScopeMetadata", () => { 55 it("returns undefined for scope without metadata", () => { 56 const emptyScope: Scope = {}; 57 expect(getScopeMetadata(emptyScope)).toBeUndefined(); 58 }); 59 60 it("returns metadata for scope with metadata", () => { 61 createScopeMetadata(testScope, testElement); 62 63 const metadata = getScopeMetadata(testScope); 64 expect(metadata).toBeDefined(); 65 }); 66 }); 67 68 describe("registerPin", () => { 69 beforeEach(() => { 70 createScopeMetadata(testScope, testElement); 71 }); 72 73 it("registers an element with a name", () => { 74 const input = document.createElement("input"); 75 registerPin(testScope, "username", input); 76 77 const metadata = getScopeMetadata(testScope); 78 expect(metadata?.pins.get("username")).toBe(input); 79 }); 80 81 it("allows multiple pins with different names", () => { 82 const input1 = document.createElement("input"); 83 const input2 = document.createElement("input"); 84 85 registerPin(testScope, "username", input1); 86 registerPin(testScope, "email", input2); 87 88 const metadata = getScopeMetadata(testScope); 89 expect(metadata?.pins.size).toBe(2); 90 expect(metadata?.pins.get("username")).toBe(input1); 91 expect(metadata?.pins.get("email")).toBe(input2); 92 }); 93 94 it("overwrites existing pin with same name", () => { 95 const input1 = document.createElement("input"); 96 const input2 = document.createElement("input"); 97 98 registerPin(testScope, "username", input1); 99 registerPin(testScope, "username", input2); 100 101 const metadata = getScopeMetadata(testScope); 102 expect(metadata?.pins.get("username")).toBe(input2); 103 }); 104 105 it("does nothing if scope has no metadata", () => { 106 const emptyScope: Scope = {}; 107 const input = document.createElement("input"); 108 109 // Should not throw 110 registerPin(emptyScope, "username", input); 111 112 expect(getScopeMetadata(emptyScope)).toBeUndefined(); 113 }); 114 }); 115 116 describe("getPin", () => { 117 beforeEach(() => { 118 createScopeMetadata(testScope, testElement); 119 }); 120 121 it("returns registered pin by name", () => { 122 const input = document.createElement("input"); 123 registerPin(testScope, "username", input); 124 125 expect(getPin(testScope, "username")).toBe(input); 126 }); 127 128 it("returns undefined for unregistered pin", () => { 129 expect(getPin(testScope, "unknown")).toBeUndefined(); 130 }); 131 132 it("returns undefined if scope has no metadata", () => { 133 const emptyScope: Scope = {}; 134 expect(getPin(emptyScope, "username")).toBeUndefined(); 135 }); 136 }); 137 138 describe("getPins", () => { 139 beforeEach(() => { 140 createScopeMetadata(testScope, testElement); 141 }); 142 143 it("returns empty object for scope with no pins", () => { 144 const pins = getPins(testScope); 145 146 expect(pins).toEqual({}); 147 }); 148 149 it("returns all pins as record object", () => { 150 const input1 = document.createElement("input"); 151 const input2 = document.createElement("input"); 152 153 registerPin(testScope, "username", input1); 154 registerPin(testScope, "email", input2); 155 156 const pins = getPins(testScope); 157 158 expect(pins.username).toBe(input1); 159 expect(pins.email).toBe(input2); 160 expect(Object.keys(pins)).toHaveLength(2); 161 }); 162 163 it("returns empty object if scope has no metadata", () => { 164 const emptyScope: Scope = {}; 165 const pins = getPins(emptyScope); 166 167 expect(pins).toEqual({}); 168 }); 169 }); 170 171 describe("incrementUidCounter", () => { 172 beforeEach(() => { 173 createScopeMetadata(testScope, testElement); 174 }); 175 176 it("increments counter and returns new value", () => { 177 const id1 = incrementUidCounter(testScope); 178 const id2 = incrementUidCounter(testScope); 179 const id3 = incrementUidCounter(testScope); 180 181 expect(id1).toBe(1); 182 expect(id2).toBe(2); 183 expect(id3).toBe(3); 184 }); 185 186 it("returns 0 for scope without metadata", () => { 187 const emptyScope: Scope = {}; 188 expect(incrementUidCounter(emptyScope)).toBe(0); 189 }); 190 191 it("maintains separate counters per scope", () => { 192 const scope1: Scope = {}; 193 const scope2: Scope = {}; 194 const elem1 = document.createElement("div"); 195 const elem2 = document.createElement("div"); 196 197 createScopeMetadata(scope1, elem1); 198 createScopeMetadata(scope2, elem2); 199 200 expect(incrementUidCounter(scope1)).toBe(1); 201 expect(incrementUidCounter(scope2)).toBe(1); 202 expect(incrementUidCounter(scope1)).toBe(2); 203 expect(incrementUidCounter(scope2)).toBe(2); 204 }); 205 }); 206 207 describe("Memory Management", () => { 208 it("allows garbage collection of scope", () => { 209 // This test verifies WeakMap behavior 210 let scope: Scope | null = {}; 211 const element = document.createElement("div"); 212 213 createScopeMetadata(scope, element); 214 expect(getScopeMetadata(scope)).toBeDefined(); 215 216 // Clear reference - metadata should be GC-able 217 scope = null; 218 219 // Cannot directly test GC, but at least verify no errors 220 expect(true).toBe(true); 221 }); 222 }); 223});