@@ -4,7 +4,7 @@ import { resolve } from 'node:path'
44import { rm , writeFile } from 'node:fs/promises'
55import { spawnSync } from 'node:child_process'
66
7- import { modifyFile } from '../src/displayName.js'
7+ import { modify , modifyFile } from '../src/displayName.js'
88
99describe ( '@knighted/displayName' , ( ) => {
1010 it ( 'transforms files' , async t => {
@@ -22,6 +22,27 @@ describe('@knighted/displayName', () => {
2222 assert . ok ( code . indexOf ( "Foo.displayName = 'Foo'" ) === - 1 )
2323 assert . ok ( code . indexOf ( "NamedFuncExpr.displayName = 'NamedFuncExpr'" ) === - 1 )
2424
25+ // Ignored forwardRef wrapped in memo
26+ assert . ok (
27+ code . indexOf ( "MemoWrappedForward.displayName = 'MemoWrappedForward'" ) === - 1 ,
28+ )
29+
30+ // Ignores shadowed React/memo/forwardRef
31+ assert . ok ( code . indexOf ( "ShadowedMemo.displayName = 'ShadowedMemo'" ) === - 1 )
32+ assert . ok ( code . indexOf ( "ShadowedReactMemo.displayName = 'ShadowedReactMemo'" ) === - 1 )
33+ assert . ok (
34+ code . indexOf ( "ShadowedReactForward.displayName = 'ShadowedReactForward'" ) === - 1 ,
35+ )
36+ assert . ok ( code . indexOf ( "ShadowedForward.displayName = 'ShadowedForward'" ) === - 1 )
37+
38+ // Adds displayName to memo/forwardRef
39+ assert . ok ( code . indexOf ( "Memo.displayName = 'Memo'" ) !== - 1 )
40+ assert . ok ( code . indexOf ( "ForwardRef.displayName = 'ForwardRef'" ) !== - 1 )
41+
42+ // Adds displayName to React.memo/React.forwardRef
43+ assert . ok ( code . indexOf ( "ReactMemo.displayName = 'ReactMemo'" ) !== - 1 )
44+ assert . ok ( code . indexOf ( "ReactForwardRef.displayName = 'ReactForwardRef'" ) !== - 1 )
45+
2546 // Correctly identifies namespaced displayNames already present
2647 assert . equal (
2748 [
@@ -31,6 +52,7 @@ describe('@knighted/displayName', () => {
3152 ] . length ,
3253 1 ,
3354 )
55+
3456 const { status : lint } = spawnSync ( 'eslint' , [ write ] , { stdio : 'inherit' } )
3557 assert . equal ( lint , 0 )
3658 const { status : types } = spawnSync (
@@ -85,6 +107,74 @@ describe('@knighted/displayName', () => {
85107 assert . equal ( types , 0 )
86108 } )
87109
110+ it ( 'requires memo, forwardRef or React.memo/React.forwardRef to be in scope' , async ( ) => {
111+ const components = `
112+ const Foo = memo(() => {
113+ return <div>foo</div>
114+ })
115+ const Bar = forwardRef(() => {
116+ return <span>bar</span>
117+ })
118+ const Baz = React.memo(() => {
119+ return <p>baz</p>
120+ })
121+ const Qux = React.forwardRef(() => {
122+ return <p>qux</p>
123+ })
124+ `
125+ let code = await modify ( components )
126+
127+ assert . ok ( code . indexOf ( 'Foo.displayName = "Foo"' ) === - 1 )
128+ assert . ok ( code . indexOf ( 'Bar.displayName = "Bar"' ) === - 1 )
129+ assert . ok ( code . indexOf ( 'Baz.displayName = "Baz"' ) === - 1 )
130+ assert . ok ( code . indexOf ( 'Qux.displayName = "Qux"' ) === - 1 )
131+
132+ let src = `
133+ import React, { memo, forwardRef } from 'react'
134+ ${ components }
135+ `
136+ code = await modify ( src )
137+
138+ assert . ok ( code . indexOf ( "Foo.displayName = 'Foo'" ) !== - 1 )
139+ assert . ok ( code . indexOf ( "Bar.displayName = 'Bar'" ) !== - 1 )
140+ assert . ok ( code . indexOf ( "Baz.displayName = 'Baz'" ) !== - 1 )
141+ assert . ok ( code . indexOf ( "Qux.displayName = 'Qux'" ) !== - 1 )
142+
143+ // It ignores shadowed React/memo/forwardRef
144+ src = `
145+ import React, { memo, forwardRef } from 'react'
146+
147+ function Shadow() {
148+ const memo = (cb) => cb()
149+ const forwardRef = (cb) => cb()
150+ const React = { memo, forwardRef }
151+
152+ ${ components }
153+ }
154+ `
155+
156+ code = await modify ( src )
157+ assert . ok ( code . indexOf ( "Foo.displayName = 'Foo'" ) === - 1 )
158+ assert . ok ( code . indexOf ( "Bar.displayName = 'Bar'" ) === - 1 )
159+ assert . ok ( code . indexOf ( "Baz.displayName = 'Baz'" ) === - 1 )
160+ assert . ok ( code . indexOf ( "Qux.displayName = 'Qux'" ) === - 1 )
161+ } )
162+
163+ it ( 'has option to add displayName for wrapped forwardRef' , async ( ) => {
164+ const src = `
165+ import { forwardRef, memo } from 'react'
166+
167+ const WrappedForwardRef = memo(forwardRef(() => {
168+ return <div>foo</div>
169+ }))
170+ `
171+ let code = await modify ( src , { modifyNestedForwardRef : true } )
172+
173+ assert . ok ( code . indexOf ( "WrappedForwardRef.displayName = 'WrappedForwardRef'" ) !== - 1 )
174+ code = await modify ( src , { modifyNestedForwardRef : false } )
175+ assert . ok ( code . indexOf ( "WrappedForwardRef.displayName = 'WrappedForwardRef'" ) === - 1 )
176+ } )
177+
88178 it . skip ( 'works with params shadowing' , async t => {
89179 // @TODO collect coverage for params scopes
90180 const read = resolve ( import . meta. dirname , './fixtures/params.tsx' )
0 commit comments