Skip to content

Commit 196fe5e

Browse files
committed
add tests for navigation extensions
1 parent f8d2e44 commit 196fe5e

2 files changed

Lines changed: 641 additions & 18 deletions

File tree

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
import {withSanitizedDeepLinkParams} from '@libs/Navigation/AppNavigator/createRootStackNavigator/GetStateForActionHandlers';
2+
3+
describe('withSanitizedDeepLinkParams', () => {
4+
describe('deep-link chain detection (gated on `params.screen` presence)', () => {
5+
it('strips the full RN initial-state chain when `params.screen` is set, preserving non-chain keys', () => {
6+
const route = {
7+
key: 'k-1',
8+
name: 'WorkspaceSplit',
9+
params: {
10+
screen: 'WorkspaceOverview',
11+
params: {nested: true},
12+
path: '/workspace/123',
13+
initial: false,
14+
state: {routes: [{name: 'X'}]},
15+
policyID: 'p1',
16+
customFlag: 'preserve-me',
17+
},
18+
};
19+
20+
const result = withSanitizedDeepLinkParams(route, undefined);
21+
22+
expect(result.params).toEqual({policyID: 'p1', customFlag: 'preserve-me'});
23+
expect('params' in result).toBe(true);
24+
});
25+
26+
it('OMITS `params` from the result entirely when `params.screen` is set AND every key is part of the chain', () => {
27+
// Identity / shape regression: previously this case silently set `params: undefined`,
28+
// flipping `'params' in result` from false to true downstream. New behaviour is to
29+
// remove the property entirely.
30+
const route = {
31+
key: 'k-1',
32+
name: 'WorkspaceSplit',
33+
params: {
34+
screen: 'WorkspaceOverview',
35+
initial: false,
36+
path: '/workspace/123',
37+
},
38+
};
39+
40+
const result = withSanitizedDeepLinkParams(route, undefined);
41+
42+
expect('params' in result).toBe(false);
43+
expect(result.params).toBeUndefined();
44+
});
45+
46+
it('PRESERVES `params` as-is when `params.screen` is absent, even if other "chain-like" keys are present', () => {
47+
// False-positive defence: legitimate user-set `path`, `initial`, etc. on a route
48+
// that was NOT created by deep-link hydration must survive untouched.
49+
const route = {
50+
key: 'k-1',
51+
name: 'CustomScreen',
52+
params: {
53+
path: 'user/data', // user data, not a deep-link path hint
54+
initial: true, // user data, not RN's initial flag
55+
customKey: 'preserve-me',
56+
},
57+
};
58+
59+
const result = withSanitizedDeepLinkParams(route, undefined);
60+
61+
expect(result.params).toEqual(route.params);
62+
expect('params' in result).toBe(true);
63+
});
64+
65+
it('PRESERVES `params` containing the legitimate user key `pop` when no `screen` is set', () => {
66+
// Specific regression: the prior `STALE_DEEP_LINK_PARAM_KEYS` included `'pop'`,
67+
// which is too generic - some screens may use `pop` as a real param name. The
68+
// shape-detection (gated on `screen`) means `pop` is now safely preserved here.
69+
const route = {
70+
key: 'k-1',
71+
name: 'AnimatedScreen',
72+
params: {pop: true, foo: 1},
73+
};
74+
75+
const result = withSanitizedDeepLinkParams(route, undefined);
76+
77+
expect(result.params).toEqual({pop: true, foo: 1});
78+
});
79+
});
80+
81+
describe('focus-supplied params take precedence', () => {
82+
it('writes `focusParams` even when no deep-link chain is present on the route', () => {
83+
const route = {
84+
key: 'k-1',
85+
name: 'CustomScreen',
86+
params: {existing: 'value'},
87+
};
88+
89+
const result = withSanitizedDeepLinkParams(route, {newKey: 'newValue'});
90+
91+
expect(result.params).toEqual({newKey: 'newValue'});
92+
});
93+
94+
it('writes `focusParams` and ignores the existing chain when both are present', () => {
95+
const route = {
96+
key: 'k-1',
97+
name: 'CustomScreen',
98+
params: {screen: 'X', initial: false, custom: 'preserve'},
99+
};
100+
101+
const result = withSanitizedDeepLinkParams(route, {policyID: 'p1'});
102+
103+
expect(result.params).toEqual({policyID: 'p1'});
104+
});
105+
});
106+
107+
describe('identity-preservation when no rewrite is required', () => {
108+
it('does not introduce a `params` property when both `r.params` and `focusParams` are absent', () => {
109+
const route: {key: string; name: string; params?: Record<string, unknown>} = {key: 'k-1', name: 'CustomScreen'};
110+
111+
const result = withSanitizedDeepLinkParams(route, undefined);
112+
113+
expect('params' in result).toBe(false);
114+
expect(result.params).toBeUndefined();
115+
});
116+
117+
it('does not introduce a `params: undefined` shape when chain is present but missing the `screen` trigger', () => {
118+
// Edge: `path` and `initial` set without `screen` is NOT a deep-link hint per RN,
119+
// so no stripping happens; existing params survive verbatim.
120+
const route = {
121+
key: 'k-1',
122+
name: 'CustomScreen',
123+
params: {path: '/foo', initial: true},
124+
};
125+
126+
const result = withSanitizedDeepLinkParams(route, undefined);
127+
128+
expect(result.params).toEqual({path: '/foo', initial: true});
129+
expect('params' in result).toBe(true);
130+
});
131+
});
132+
});

0 commit comments

Comments
 (0)