Skip to content

Commit 270f680

Browse files
committed
test: cover qrl and serialization edge cases
1 parent 883d618 commit 270f680

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

test/utils.test.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { afterEach, describe, expect, it } from 'vitest'
2+
3+
import { createReactQrl } from '../src'
4+
import { isReactActionRef, reactActionFromQrl } from '../src/action'
5+
import { parseQrl, resolveModuleUrl } from '../src/qrl'
6+
import { decodePropsFromAttribute, encodePropsForAttribute } from '../src/serialization'
7+
8+
const runtimeHost = globalThis as { __FICT_MANIFEST__?: Record<string, string> }
9+
10+
afterEach(() => {
11+
runtimeHost.__FICT_MANIFEST__ = undefined
12+
})
13+
14+
describe('qrl utils', () => {
15+
it('parses empty and malformed qrl strings safely', () => {
16+
expect(parseQrl('')).toEqual({ url: '', exportName: 'default' })
17+
expect(parseQrl('#')).toEqual({ url: '', exportName: 'default' })
18+
expect(parseQrl('##foo')).toEqual({ url: '#', exportName: 'foo' })
19+
expect(parseQrl('/mod.ts#')).toEqual({ url: '/mod.ts', exportName: 'default' })
20+
})
21+
22+
it('parses qrl strings with serialized suffix segments', () => {
23+
expect(parseQrl('/mod.ts#run[scope]')).toEqual({ url: '/mod.ts', exportName: 'run' })
24+
})
25+
26+
it('resolves module URL through manifest mapping when present', () => {
27+
runtimeHost.__FICT_MANIFEST__ = {
28+
'/src/widget.tsx': '/assets/widget.abcd1234.js',
29+
}
30+
31+
expect(resolveModuleUrl('/src/widget.tsx')).toBe('/assets/widget.abcd1234.js')
32+
expect(resolveModuleUrl('/src/missing.tsx')).toBe('/src/missing.tsx')
33+
})
34+
})
35+
36+
describe('serialization utils', () => {
37+
it('round-trips serializable props through attribute payload encoding', () => {
38+
const input = { label: 'demo', count: 3, nested: { ok: true } }
39+
const encoded = encodePropsForAttribute(input)
40+
41+
expect(decodePropsFromAttribute(encoded)).toEqual(input)
42+
})
43+
44+
it('returns empty object for missing, corrupted, and invalid payloads', () => {
45+
expect(decodePropsFromAttribute(null)).toEqual({})
46+
expect(decodePropsFromAttribute('%')).toEqual({})
47+
expect(decodePropsFromAttribute(encodeURIComponent('{not-json'))).toEqual({})
48+
expect(decodePropsFromAttribute(encodeURIComponent('123'))).toEqual({})
49+
})
50+
})
51+
52+
describe('action ref guard', () => {
53+
it('accepts both marker-based and legacy action ref payloads', () => {
54+
expect(isReactActionRef(reactActionFromQrl('/mod.ts#run'))).toBe(true)
55+
expect(isReactActionRef({ __fictReactAction: '/legacy.ts#run' })).toBe(true)
56+
})
57+
58+
it('rejects non-action payloads', () => {
59+
expect(isReactActionRef({ __fictReactActionQrl: '/mod.ts#run' })).toBe(false)
60+
expect(isReactActionRef({ __fictReactAction: '/legacy.ts#run', extra: true })).toBe(false)
61+
expect(isReactActionRef(null)).toBe(false)
62+
expect(isReactActionRef('')).toBe(false)
63+
})
64+
})
65+
66+
describe('createReactQrl', () => {
67+
it('creates qrl with default and explicit export names', () => {
68+
expect(createReactQrl('/virtual/module.ts')).toBe('/virtual/module.ts#default')
69+
expect(createReactQrl('/virtual/module.ts', 'Widget')).toBe('/virtual/module.ts#Widget')
70+
})
71+
})

0 commit comments

Comments
 (0)