Skip to content

Commit 1819ba3

Browse files
committed
add tests
1 parent e465cac commit 1819ba3

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

src/utils.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ export const mergeDeep = <
107107
} catch {}
108108
}
109109

110+
seen.delete(source)
111+
110112
return target as A & B
111113
}
112114
export const mergeCookie = <const A extends Object, const B extends Object>(

test/units/merge-deep.test.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,78 @@ describe('mergeDeep', () => {
8686
.decorate('db', Object.freeze({ hello: 'world' }))
8787
.guard({}, (app) => app)
8888
})
89+
90+
it('handle circular references', () => {
91+
const a: {
92+
x: number
93+
toB?: typeof b
94+
} = { x: 1 }
95+
const b: {
96+
y: number
97+
toA?: typeof a
98+
} = { y: 2 }
99+
100+
a.toB = b
101+
b.toA = a
102+
103+
const target = {}
104+
const source = { prop: a }
105+
106+
const result = mergeDeep(target, source)
107+
108+
expect(result.prop.x).toBe(1)
109+
expect(result.prop.toB?.y).toBe(2)
110+
})
111+
112+
it('handle shared references in different branches', () => {
113+
const shared = { value: 123 }
114+
const target = { x: {}, y: {} }
115+
const source = { x: shared, y: shared }
116+
117+
const result = mergeDeep(target, source)
118+
119+
expect(result.x.value).toBe(123)
120+
expect(result.y.value).toBe(123)
121+
})
122+
123+
it('deduplicate plugin with circular decorators', async () => {
124+
const a: {
125+
x: number
126+
toB?: typeof b
127+
} = { x: 1 }
128+
const b: {
129+
y: number
130+
toA?: typeof a
131+
} = { y: 2 }
132+
a.toB = b
133+
b.toA = a
134+
135+
const complex = { a }
136+
137+
const Plugin = new Elysia({ name: 'Plugin', seed: 'seed' })
138+
.decorate('dep', complex)
139+
.as('scoped')
140+
141+
const ModuleA = new Elysia({ name: 'ModuleA' })
142+
.use(Plugin)
143+
.get('/moda/a', ({ dep }) => dep.a.x)
144+
.get('/moda/b', ({ dep }) => dep.a.toB?.y)
145+
146+
const ModuleB = new Elysia({ name: 'ModuleB' })
147+
.use(Plugin)
148+
.get('/modb/a', ({ dep }) => dep.a.x)
149+
.get('/modb/b', ({ dep }) => dep.a.toB?.y)
150+
151+
const app = new Elysia().use(ModuleA).use(ModuleB)
152+
153+
const resA = await app.handle(req('/moda/a')).then((x) => x.text())
154+
const resB = await app.handle(req('/modb/a')).then((x) => x.text())
155+
const resC = await app.handle(req('/moda/b')).then((x) => x.text())
156+
const resD = await app.handle(req('/modb/b')).then((x) => x.text())
157+
158+
expect(resA).toBe('1')
159+
expect(resB).toBe('1')
160+
expect(resC).toBe('2')
161+
expect(resD).toBe('2')
162+
})
89163
})

0 commit comments

Comments
 (0)