react-component-snapshot 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -3
- package/src/index.mjs +13 -11
- package/src/symbols.mjs +1 -0
- package/src/react/ReactSymbols.mjs +0 -28
- package/src/react/getComponentNameFromType.mjs +0 -145
- package/src/react.mjs +0 -182
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-component-snapshot",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Transform a React component to match its snapshot in Jest",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -26,10 +26,12 @@
|
|
|
26
26
|
"scripts": {
|
|
27
27
|
"lint": "eslint",
|
|
28
28
|
"lint:fix": "npm run lint -- --fix",
|
|
29
|
+
"prepare": "husky",
|
|
29
30
|
"test": "NODE_ENV=test jest"
|
|
30
31
|
},
|
|
31
32
|
"dependencies": {
|
|
32
|
-
"debug": "^4.4.0"
|
|
33
|
+
"debug": "^4.4.0",
|
|
34
|
+
"react-component-name": "^0.0.0"
|
|
33
35
|
},
|
|
34
36
|
"devDependencies": {
|
|
35
37
|
"@babel/core": "^7.26.10",
|
|
@@ -42,13 +44,13 @@
|
|
|
42
44
|
"@testing-library/react": "^16.2.0",
|
|
43
45
|
"@types/debug": "^4.1.12",
|
|
44
46
|
"@types/jest": "^29.5.14",
|
|
45
|
-
"@types/prop-types": "^15.7.14",
|
|
46
47
|
"@types/react": "^19.0.11",
|
|
47
48
|
"@typescript-eslint/parser": "^8.26.1",
|
|
48
49
|
"core-js": "^3.41.0",
|
|
49
50
|
"eslint": "^9.22.0",
|
|
50
51
|
"eslint-plugin-react": "^7.37.4",
|
|
51
52
|
"globals": "^16.0.0",
|
|
53
|
+
"husky": "^9.1.7",
|
|
52
54
|
"jest": "^29.7.0",
|
|
53
55
|
"jest-environment-jsdom": "^29.7.0",
|
|
54
56
|
"react": "19.0.0"
|
package/src/index.mjs
CHANGED
|
@@ -3,10 +3,20 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import {
|
|
6
|
-
getType
|
|
7
|
-
} from '
|
|
6
|
+
getComponentNameFromFiber as getType
|
|
7
|
+
} from 'react-component-name'
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
import {
|
|
10
|
+
REACT_COMPONENT_SNAPSHOT
|
|
11
|
+
} from './symbols.mjs'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {unknown} v
|
|
15
|
+
* @returns {v is object}
|
|
16
|
+
*/
|
|
17
|
+
function isObject (v) {
|
|
18
|
+
return (v || false) instanceof Object && !Array.isArray(v)
|
|
19
|
+
}
|
|
10
20
|
|
|
11
21
|
/**
|
|
12
22
|
* @param {PropertyKey} key
|
|
@@ -24,14 +34,6 @@ export function isReactPropsKey (key) {
|
|
|
24
34
|
return String(key).startsWith('__reactProps$')
|
|
25
35
|
}
|
|
26
36
|
|
|
27
|
-
/**
|
|
28
|
-
* @param {unknown} v
|
|
29
|
-
* @returns {v is object}
|
|
30
|
-
*/
|
|
31
|
-
function isObject (v) {
|
|
32
|
-
return (v || false) instanceof Object && !Array.isArray(v)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
37
|
/**
|
|
36
38
|
* @param {Element | Text | React.Component<any, any, any>} stateNode
|
|
37
39
|
* @returns {string | undefined}
|
package/src/symbols.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const REACT_COMPONENT_SNAPSHOT = Symbol.for('react.test.json')
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export const REACT_LEGACY_ELEMENT_TYPE = Symbol.for('react.element')
|
|
9
|
-
export const REACT_ELEMENT_TYPE = Symbol.for('react.transitional.element')
|
|
10
|
-
export const REACT_PORTAL_TYPE = Symbol.for('react.portal')
|
|
11
|
-
export const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment')
|
|
12
|
-
export const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode')
|
|
13
|
-
export const REACT_PROFILER_TYPE = Symbol.for('react.profiler')
|
|
14
|
-
export const REACT_PROVIDER_TYPE = Symbol.for('react.provider')
|
|
15
|
-
export const REACT_CONSUMER_TYPE = Symbol.for('react.consumer')
|
|
16
|
-
export const REACT_CONTEXT_TYPE = Symbol.for('react.context')
|
|
17
|
-
export const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref')
|
|
18
|
-
export const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense')
|
|
19
|
-
export const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list')
|
|
20
|
-
export const REACT_MEMO_TYPE = Symbol.for('react.memo')
|
|
21
|
-
export const REACT_LAZY_TYPE = Symbol.for('react.lazy')
|
|
22
|
-
export const REACT_SCOPE_TYPE = Symbol.for('react.scope')
|
|
23
|
-
export const REACT_ACTIVITY_TYPE = Symbol.for('react.activity')
|
|
24
|
-
export const REACT_LEGACY_HIDDEN_TYPE = Symbol.for('react.legacy_hidden')
|
|
25
|
-
export const REACT_TRACING_MARKER_TYPE = Symbol.for('react.tracing_marker')
|
|
26
|
-
export const REACT_MEMO_CACHE_SENTINEL = Symbol.for('react.memo_cache_sentinel')
|
|
27
|
-
export const REACT_POSTPONE_TYPE = Symbol.for('react.postpone')
|
|
28
|
-
export const REACT_VIEW_TRANSITION_TYPE = Symbol.for('react.view_transition')
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
-
*
|
|
4
|
-
* This source code is licensed under the MIT license found in the
|
|
5
|
-
* LICENSE file in the root directory of this source tree.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
REACT_CONTEXT_TYPE,
|
|
10
|
-
REACT_CONSUMER_TYPE,
|
|
11
|
-
REACT_FORWARD_REF_TYPE,
|
|
12
|
-
REACT_FRAGMENT_TYPE,
|
|
13
|
-
REACT_PORTAL_TYPE,
|
|
14
|
-
REACT_MEMO_TYPE,
|
|
15
|
-
REACT_PROFILER_TYPE,
|
|
16
|
-
REACT_PROVIDER_TYPE,
|
|
17
|
-
REACT_STRICT_MODE_TYPE,
|
|
18
|
-
REACT_SUSPENSE_TYPE,
|
|
19
|
-
REACT_SUSPENSE_LIST_TYPE,
|
|
20
|
-
REACT_LAZY_TYPE,
|
|
21
|
-
REACT_TRACING_MARKER_TYPE,
|
|
22
|
-
REACT_VIEW_TRANSITION_TYPE,
|
|
23
|
-
REACT_ACTIVITY_TYPE
|
|
24
|
-
} from './ReactSymbols.mjs'
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* @param {{displayName?: string | null}} outerType
|
|
28
|
-
* @param {{displayName?: string | null, name?: string | null}} innerType
|
|
29
|
-
* @param {string} wrapperName
|
|
30
|
-
* @returns
|
|
31
|
-
*/
|
|
32
|
-
function getWrappedName (
|
|
33
|
-
outerType,
|
|
34
|
-
innerType,
|
|
35
|
-
wrapperName
|
|
36
|
-
) {
|
|
37
|
-
const outerDisplayName = outerType.displayName
|
|
38
|
-
|
|
39
|
-
if (outerDisplayName) {
|
|
40
|
-
return outerDisplayName
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const innerDisplayName = innerType.displayName || innerType.name || null
|
|
44
|
-
|
|
45
|
-
if (innerDisplayName) {
|
|
46
|
-
return `${wrapperName}(${innerDisplayName})`
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return wrapperName
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* @param {{displayName?: string | null}} type
|
|
54
|
-
* @returns {string}
|
|
55
|
-
*/
|
|
56
|
-
function getContextName (type) {
|
|
57
|
-
return type.displayName || 'Context'
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference')
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* @param {unknown} type
|
|
64
|
-
* @returns {string | null}
|
|
65
|
-
*/
|
|
66
|
-
export default function getComponentNameFromType (type) {
|
|
67
|
-
if (type == null) return null
|
|
68
|
-
|
|
69
|
-
if (typeof type === 'function') { // @ts-expect-error
|
|
70
|
-
if (type.$$typeof === REACT_CLIENT_REFERENCE) return null
|
|
71
|
-
return ( // @ts-expect-error
|
|
72
|
-
type.displayName || type.name || null
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
if (typeof type === 'string') return type
|
|
77
|
-
|
|
78
|
-
switch (type) {
|
|
79
|
-
case REACT_FRAGMENT_TYPE:
|
|
80
|
-
return 'Fragment'
|
|
81
|
-
case REACT_PROFILER_TYPE:
|
|
82
|
-
return 'Profiler'
|
|
83
|
-
case REACT_STRICT_MODE_TYPE:
|
|
84
|
-
return 'StrictMode'
|
|
85
|
-
case REACT_SUSPENSE_TYPE:
|
|
86
|
-
return 'Suspense'
|
|
87
|
-
case REACT_SUSPENSE_LIST_TYPE:
|
|
88
|
-
return 'SuspenseList'
|
|
89
|
-
case REACT_ACTIVITY_TYPE:
|
|
90
|
-
return 'Activity'
|
|
91
|
-
case REACT_VIEW_TRANSITION_TYPE:
|
|
92
|
-
return 'ViewTransition'
|
|
93
|
-
case REACT_TRACING_MARKER_TYPE:
|
|
94
|
-
return 'TracingMarker'
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (typeof type === 'object') { // @ts-expect-error
|
|
98
|
-
switch (type.$$typeof) {
|
|
99
|
-
case REACT_PORTAL_TYPE:
|
|
100
|
-
return 'Portal'
|
|
101
|
-
|
|
102
|
-
case REACT_PROVIDER_TYPE: // @ts-expect-error
|
|
103
|
-
return getContextName(type._context) + '.Provider'
|
|
104
|
-
|
|
105
|
-
case REACT_CONTEXT_TYPE:
|
|
106
|
-
return getContextName(type) + '.Context'
|
|
107
|
-
|
|
108
|
-
case REACT_CONSUMER_TYPE: // @ts-expect-error
|
|
109
|
-
return getContextName(type._context) + '.Consumer'
|
|
110
|
-
|
|
111
|
-
case REACT_FORWARD_REF_TYPE: // @ts-expect-error
|
|
112
|
-
return getWrappedName(type, type.render, 'ForwardRef')
|
|
113
|
-
|
|
114
|
-
case REACT_MEMO_TYPE:
|
|
115
|
-
{
|
|
116
|
-
// @ts-expect-error
|
|
117
|
-
const outerName = type.displayName || null
|
|
118
|
-
|
|
119
|
-
if (outerName !== null) {
|
|
120
|
-
return outerName
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// @ts-expect-error
|
|
124
|
-
return getComponentNameFromType(type.type) || 'Memo'
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
case REACT_LAZY_TYPE:
|
|
128
|
-
{
|
|
129
|
-
// @ts-expect-error
|
|
130
|
-
const payload = type._payload
|
|
131
|
-
|
|
132
|
-
// @ts-expect-error
|
|
133
|
-
const init = type._init
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
return getComponentNameFromType(init(payload))
|
|
137
|
-
} catch {
|
|
138
|
-
return null
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return null
|
|
145
|
-
}
|
package/src/react.mjs
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {ReactComponentSnapshotTypes.FiberNode} FiberNode
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import debug from 'debug'
|
|
8
|
-
|
|
9
|
-
const log = debug('react-component-snapshot')
|
|
10
|
-
|
|
11
|
-
export const REACT_PORTAL_TYPE = Symbol.for('react.portal')
|
|
12
|
-
export const REACT_FRAGMENT_TYPE = Symbol.for('react.fragment')
|
|
13
|
-
export const REACT_STRICT_MODE_TYPE = Symbol.for('react.strict_mode')
|
|
14
|
-
export const REACT_PROFILER_TYPE = Symbol.for('react.profiler')
|
|
15
|
-
export const REACT_CONSUMER_TYPE = Symbol.for('react.consumer')
|
|
16
|
-
export const REACT_CONTEXT_TYPE = Symbol.for('react.context')
|
|
17
|
-
export const REACT_FORWARD_REF_TYPE = Symbol.for('react.forward_ref')
|
|
18
|
-
export const REACT_SUSPENSE_TYPE = Symbol.for('react.suspense')
|
|
19
|
-
export const REACT_SUSPENSE_LIST_TYPE = Symbol.for('react.suspense_list')
|
|
20
|
-
export const REACT_MEMO_TYPE = Symbol.for('react.memo')
|
|
21
|
-
export const REACT_LAZY_TYPE = Symbol.for('react.lazy')
|
|
22
|
-
export const REACT_CLIENT_REFERENCE = Symbol.for('react.client.reference')
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @param {{displayName?: string | null}} outerType
|
|
26
|
-
* @param {{displayName?: string | null, name?: string | null}} innerType
|
|
27
|
-
* @param {string} refKey
|
|
28
|
-
* @returns {string | null}
|
|
29
|
-
*/
|
|
30
|
-
function getNameFromRef (outerType, innerType, refKey) {
|
|
31
|
-
const outerName = outerType.displayName || null
|
|
32
|
-
|
|
33
|
-
if (outerName) return outerName
|
|
34
|
-
|
|
35
|
-
const innerName = innerType.displayName || innerType.name || null
|
|
36
|
-
|
|
37
|
-
if (innerName) return `${refKey}(${innerName})`
|
|
38
|
-
|
|
39
|
-
return refKey
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* @param {FiberNode['type']} type
|
|
44
|
-
* @returns {string | null}
|
|
45
|
-
*/
|
|
46
|
-
export function getNameFromType (type) {
|
|
47
|
-
if (type == null) return null
|
|
48
|
-
|
|
49
|
-
if (typeof type === 'function') {
|
|
50
|
-
return (
|
|
51
|
-
type.$$typeof === REACT_CLIENT_REFERENCE
|
|
52
|
-
? null
|
|
53
|
-
: type.displayName || type.name || null
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (typeof type === 'string') return type
|
|
58
|
-
|
|
59
|
-
switch (type) {
|
|
60
|
-
case REACT_FRAGMENT_TYPE:
|
|
61
|
-
return 'Fragment'
|
|
62
|
-
case REACT_PORTAL_TYPE:
|
|
63
|
-
return 'Portal'
|
|
64
|
-
case REACT_PROFILER_TYPE:
|
|
65
|
-
return 'Profiler'
|
|
66
|
-
case REACT_STRICT_MODE_TYPE:
|
|
67
|
-
return 'StrictMode'
|
|
68
|
-
case REACT_SUSPENSE_TYPE:
|
|
69
|
-
return 'Suspense'
|
|
70
|
-
case REACT_SUSPENSE_LIST_TYPE:
|
|
71
|
-
return 'SuspenseList'
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (typeof type === 'object') {
|
|
75
|
-
switch (type.$$typeof) {
|
|
76
|
-
case REACT_CONTEXT_TYPE:
|
|
77
|
-
return (type.displayName || 'Context') + '.Provider'
|
|
78
|
-
case REACT_CONSUMER_TYPE:
|
|
79
|
-
return (type._context.displayName || 'Context') + '.Consumer'
|
|
80
|
-
case REACT_FORWARD_REF_TYPE:
|
|
81
|
-
return getNameFromRef(type, type.render, 'ForwardRef')
|
|
82
|
-
|
|
83
|
-
case REACT_MEMO_TYPE:
|
|
84
|
-
return (
|
|
85
|
-
type.displayName || getNameFromType(type.type) || 'Memo'
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
case REACT_LAZY_TYPE:
|
|
89
|
-
{
|
|
90
|
-
const payload = type._payload
|
|
91
|
-
const init = type._init
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
return getNameFromType(init(payload))
|
|
95
|
-
} catch ({ message }) {
|
|
96
|
-
log(`Lazy Component error. Message was "${message}"`)
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
return null
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* @param {FiberNode} fiberNode
|
|
107
|
-
* @returns {string | null}
|
|
108
|
-
*/
|
|
109
|
-
export function getType (fiberNode) {
|
|
110
|
-
const type = fiberNode.type
|
|
111
|
-
|
|
112
|
-
switch (fiberNode.tag) {
|
|
113
|
-
case 24:
|
|
114
|
-
return 'Cache'
|
|
115
|
-
case 9:
|
|
116
|
-
return (type._context.displayName || 'Context') + '.Consumer'
|
|
117
|
-
case 10:
|
|
118
|
-
return (type.displayName || 'Context') + '.Provider'
|
|
119
|
-
case 18:
|
|
120
|
-
return 'DehydratedFragment'
|
|
121
|
-
case 11:
|
|
122
|
-
return getNameFromRef(type, type.render, 'ForwardRef')
|
|
123
|
-
case 7:
|
|
124
|
-
return 'Fragment'
|
|
125
|
-
case 26:
|
|
126
|
-
case 27:
|
|
127
|
-
case 5:
|
|
128
|
-
return type
|
|
129
|
-
case 4:
|
|
130
|
-
return 'Portal'
|
|
131
|
-
case 3:
|
|
132
|
-
return 'Root'
|
|
133
|
-
case 6:
|
|
134
|
-
return 'Text'
|
|
135
|
-
case 16:
|
|
136
|
-
return getNameFromType(type)
|
|
137
|
-
case 8:
|
|
138
|
-
return (
|
|
139
|
-
type === REACT_STRICT_MODE_TYPE
|
|
140
|
-
? 'StrictMode'
|
|
141
|
-
: 'Mode'
|
|
142
|
-
)
|
|
143
|
-
case 22:
|
|
144
|
-
return 'Offscreen'
|
|
145
|
-
case 12:
|
|
146
|
-
return 'Profiler'
|
|
147
|
-
case 21:
|
|
148
|
-
return 'Scope'
|
|
149
|
-
case 13:
|
|
150
|
-
return 'Suspense'
|
|
151
|
-
case 19:
|
|
152
|
-
return 'SuspenseList'
|
|
153
|
-
case 25:
|
|
154
|
-
return 'TracingMarker'
|
|
155
|
-
case 1:
|
|
156
|
-
case 0:
|
|
157
|
-
case 14:
|
|
158
|
-
case 15:
|
|
159
|
-
if (typeof type === 'function') return type.displayName || type.name || null
|
|
160
|
-
if (typeof type === 'string') return type
|
|
161
|
-
return null
|
|
162
|
-
case 29:
|
|
163
|
-
{
|
|
164
|
-
const info = fiberNode._debugInfo || null
|
|
165
|
-
|
|
166
|
-
if (info != null) {
|
|
167
|
-
let i = info.length - 1
|
|
168
|
-
|
|
169
|
-
for (i; i >= 0; i--) {
|
|
170
|
-
const t = info[i]
|
|
171
|
-
const n = t.name
|
|
172
|
-
|
|
173
|
-
if (typeof n === 'string') return n
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (fiberNode.return !== null) return getType(fiberNode.return)
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return null
|
|
182
|
-
}
|