require-default-props.js 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180
  1. /**
  2. * @fileoverview Enforce a defaultProps definition for every prop that is not a required prop.
  3. * @author Vitor Balocco
  4. */
  5. 'use strict';
  6. // ------------------------------------------------------------------------------
  7. // Requirements
  8. // ------------------------------------------------------------------------------
  9. const rule = require('../../../lib/rules/require-default-props');
  10. const RuleTester = require('eslint').RuleTester;
  11. const parserOptions = {
  12. ecmaVersion: 2018,
  13. sourceType: 'module',
  14. ecmaFeatures: {
  15. jsx: true
  16. }
  17. };
  18. require('babel-eslint');
  19. const ruleTester = new RuleTester({parserOptions});
  20. // ------------------------------------------------------------------------------
  21. // Tests
  22. // ------------------------------------------------------------------------------
  23. ruleTester.run('require-default-props', rule, {
  24. valid: [
  25. //
  26. // stateless components
  27. {
  28. code: [
  29. 'function MyStatelessComponent({ foo, bar }) {',
  30. ' return <div>{foo}{bar}</div>;',
  31. '}',
  32. 'MyStatelessComponent.propTypes = {',
  33. ' foo: PropTypes.string.isRequired,',
  34. ' bar: PropTypes.string.isRequired',
  35. '};'
  36. ].join('\n')
  37. },
  38. {
  39. code: [
  40. 'function MyStatelessComponent({ foo, bar }) {',
  41. ' return <div>{foo}{bar}</div>;',
  42. '}',
  43. 'MyStatelessComponent.propTypes = {',
  44. ' foo: PropTypes.string,',
  45. ' bar: PropTypes.string.isRequired',
  46. '};',
  47. 'MyStatelessComponent.defaultProps = {',
  48. ' foo: "foo"',
  49. '};'
  50. ].join('\n')
  51. },
  52. {
  53. code: [
  54. 'function MyStatelessComponent({ foo, bar }) {',
  55. ' return <div>{foo}{bar}</div>;',
  56. '}'
  57. ].join('\n')
  58. },
  59. {
  60. code: [
  61. 'function MyStatelessComponent({ foo, bar }) {',
  62. ' return <div>{foo}{bar}</div>;',
  63. '}',
  64. 'MyStatelessComponent.propTypes = {',
  65. ' bar: PropTypes.string.isRequired',
  66. '};',
  67. 'MyStatelessComponent.propTypes.foo = PropTypes.string;',
  68. 'MyStatelessComponent.defaultProps = {',
  69. ' foo: "foo"',
  70. '};'
  71. ].join('\n')
  72. },
  73. {
  74. code: [
  75. 'function MyStatelessComponent({ foo, bar }) {',
  76. ' return <div>{foo}{bar}</div>;',
  77. '}',
  78. 'MyStatelessComponent.propTypes = {',
  79. ' bar: PropTypes.string.isRequired',
  80. '};',
  81. 'MyStatelessComponent.propTypes.foo = PropTypes.string;',
  82. 'MyStatelessComponent.defaultProps = {};',
  83. 'MyStatelessComponent.defaultProps.foo = "foo";'
  84. ].join('\n')
  85. },
  86. {
  87. code: [
  88. 'function MyStatelessComponent({ foo }) {',
  89. ' return <div>{foo}</div>;',
  90. '}',
  91. 'MyStatelessComponent.propTypes = {};',
  92. 'MyStatelessComponent.propTypes.foo = PropTypes.string;',
  93. 'MyStatelessComponent.defaultProps = {};',
  94. 'MyStatelessComponent.defaultProps.foo = "foo";'
  95. ].join('\n')
  96. },
  97. {
  98. code: [
  99. 'const types = {',
  100. ' foo: PropTypes.string,',
  101. ' bar: PropTypes.string.isRequired',
  102. '};',
  103. 'function MyStatelessComponent({ foo, bar }) {',
  104. ' return <div>{foo}{bar}</div>;',
  105. '}',
  106. 'MyStatelessComponent.propTypes = types;',
  107. 'MyStatelessComponent.defaultProps = {',
  108. ' foo: "foo"',
  109. '};'
  110. ].join('\n')
  111. },
  112. {
  113. code: [
  114. 'const defaults = {',
  115. ' foo: "foo"',
  116. '};',
  117. 'function MyStatelessComponent({ foo, bar }) {',
  118. ' return <div>{foo}{bar}</div>;',
  119. '}',
  120. 'MyStatelessComponent.propTypes = {',
  121. ' foo: PropTypes.string,',
  122. ' bar: PropTypes.string.isRequired',
  123. '};',
  124. 'MyStatelessComponent.defaultProps = defaults;'
  125. ].join('\n')
  126. },
  127. {
  128. code: [
  129. 'const defaults = {',
  130. ' foo: "foo"',
  131. '};',
  132. 'const types = {',
  133. ' foo: PropTypes.string,',
  134. ' bar: PropTypes.string.isRequired',
  135. '};',
  136. 'function MyStatelessComponent({ foo, bar }) {',
  137. ' return <div>{foo}{bar}</div>;',
  138. '}',
  139. 'MyStatelessComponent.propTypes = types;',
  140. 'MyStatelessComponent.defaultProps = defaults;'
  141. ].join('\n')
  142. },
  143. //
  144. // createReactClass components
  145. {
  146. code: [
  147. 'var Greeting = createReactClass({',
  148. ' render: function() {',
  149. ' return <div>Hello {this.props.foo} {this.props.bar}</div>;',
  150. ' },',
  151. ' propTypes: {',
  152. ' foo: PropTypes.string.isRequired,',
  153. ' bar: PropTypes.string.isRequired',
  154. ' }',
  155. '});'
  156. ].join('\n')
  157. },
  158. {
  159. code: [
  160. 'var Greeting = createReactClass({',
  161. ' render: function() {',
  162. ' return <div>Hello {this.props.foo} {this.props.bar}</div>;',
  163. ' },',
  164. ' propTypes: {',
  165. ' foo: PropTypes.string,',
  166. ' bar: PropTypes.string.isRequired',
  167. ' },',
  168. ' getDefaultProps: function() {',
  169. ' return {',
  170. ' foo: "foo"',
  171. ' };',
  172. ' }',
  173. '});'
  174. ].join('\n')
  175. },
  176. {
  177. code: [
  178. 'var Greeting = createReactClass({',
  179. ' render: function() {',
  180. ' return <div>Hello {this.props.foo} {this.props.bar}</div>;',
  181. ' },',
  182. ' propTypes: {',
  183. ' foo: PropTypes.string,',
  184. ' bar: PropTypes.string',
  185. ' },',
  186. ' getDefaultProps: function() {',
  187. ' return {',
  188. ' foo: "foo",',
  189. ' bar: "bar"',
  190. ' };',
  191. ' }',
  192. '});'
  193. ].join('\n')
  194. },
  195. {
  196. code: [
  197. 'var Greeting = createReactClass({',
  198. ' render: function() {',
  199. ' return <div>Hello {this.props.foo} {this.props.bar}</div>;',
  200. ' }',
  201. '});'
  202. ].join('\n')
  203. },
  204. //
  205. // ES6 class component
  206. {
  207. code: [
  208. 'class Greeting extends React.Component {',
  209. ' render() {',
  210. ' return (',
  211. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  212. ' );',
  213. ' }',
  214. '}',
  215. 'Greeting.propTypes = {',
  216. ' foo: PropTypes.string.isRequired,',
  217. ' bar: PropTypes.string.isRequired',
  218. '};',
  219. 'Greeting.defaultProps = {',
  220. ' foo: "foo"',
  221. '};'
  222. ].join('\n')
  223. },
  224. {
  225. code: [
  226. 'class Greeting extends React.Component {',
  227. ' render() {',
  228. ' return (',
  229. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  230. ' );',
  231. ' }',
  232. '}',
  233. 'Greeting.propTypes = {',
  234. ' foo: PropTypes.string,',
  235. ' bar: PropTypes.string.isRequired',
  236. '};',
  237. 'Greeting.defaultProps = {',
  238. ' foo: "foo"',
  239. '};'
  240. ].join('\n')
  241. },
  242. {
  243. code: [
  244. 'class Greeting extends React.Component {',
  245. ' render() {',
  246. ' return (',
  247. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  248. ' );',
  249. ' }',
  250. '}'
  251. ].join('\n')
  252. },
  253. {
  254. code: [
  255. 'class Greeting extends React.Component {',
  256. ' render() {',
  257. ' return (',
  258. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  259. ' );',
  260. ' }',
  261. '}',
  262. 'Greeting.propTypes = {',
  263. ' bar: PropTypes.string.isRequired',
  264. '};',
  265. 'Greeting.propTypes.foo = PropTypes.string;',
  266. 'Greeting.defaultProps = {',
  267. ' foo: "foo"',
  268. '};'
  269. ].join('\n')
  270. },
  271. {
  272. code: [
  273. 'class Greeting extends React.Component {',
  274. ' render() {',
  275. ' return (',
  276. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  277. ' );',
  278. ' }',
  279. '}',
  280. 'Greeting.propTypes = {',
  281. ' bar: PropTypes.string.isRequired',
  282. '};',
  283. 'Greeting.propTypes.foo = PropTypes.string;',
  284. 'Greeting.defaultProps = {};',
  285. 'Greeting.defaultProps.foo = "foo";'
  286. ].join('\n')
  287. },
  288. {
  289. code: [
  290. 'class Greeting extends React.Component {',
  291. ' render() {',
  292. ' return (',
  293. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  294. ' );',
  295. ' }',
  296. '}',
  297. 'Greeting.propTypes = {};',
  298. 'Greeting.propTypes.foo = PropTypes.string;',
  299. 'Greeting.defaultProps = {};',
  300. 'Greeting.defaultProps.foo = "foo";'
  301. ].join('\n')
  302. },
  303. //
  304. // edge cases
  305. // not a react component
  306. {
  307. code: [
  308. 'function NotAComponent({ foo, bar }) {}',
  309. 'NotAComponent.propTypes = {',
  310. ' foo: PropTypes.string,',
  311. ' bar: PropTypes.string.isRequired',
  312. '};'
  313. ].join('\n')
  314. },
  315. {
  316. code: [
  317. 'class Greeting {',
  318. ' render() {',
  319. ' return (',
  320. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  321. ' );',
  322. ' }',
  323. '}',
  324. 'Greeting.propTypes = {',
  325. ' bar: PropTypes.string.isRequired',
  326. '};'
  327. ].join('\n')
  328. },
  329. // external references
  330. {
  331. code: [
  332. 'const defaults = require("./defaults");',
  333. 'const types = {',
  334. ' foo: PropTypes.string,',
  335. ' bar: PropTypes.string',
  336. '};',
  337. 'function MyStatelessComponent({ foo, bar }) {',
  338. ' return <div>{foo}{bar}</div>;',
  339. '}',
  340. 'MyStatelessComponent.propTypes = types;',
  341. 'MyStatelessComponent.defaultProps = defaults;'
  342. ].join('\n')
  343. },
  344. {
  345. code: [
  346. 'const defaults = {',
  347. ' foo: "foo"',
  348. '};',
  349. 'const types = require("./propTypes");',
  350. 'function MyStatelessComponent({ foo, bar }) {',
  351. ' return <div>{foo}{bar}</div>;',
  352. '}',
  353. 'MyStatelessComponent.propTypes = types;',
  354. 'MyStatelessComponent.defaultProps = defaults;'
  355. ].join('\n')
  356. },
  357. {
  358. code: [
  359. 'MyStatelessComponent.propTypes = {',
  360. ' foo: PropTypes.string',
  361. '};',
  362. 'MyStatelessComponent.defaultProps = require("./defaults").foo;',
  363. 'function MyStatelessComponent({ foo, bar }) {',
  364. ' return <div>{foo}{bar}</div>;',
  365. '}'
  366. ].join('\n')
  367. },
  368. {
  369. code: [
  370. 'MyStatelessComponent.propTypes = {',
  371. ' foo: PropTypes.string',
  372. '};',
  373. 'MyStatelessComponent.defaultProps = require("./defaults").foo;',
  374. 'MyStatelessComponent.defaultProps.bar = "bar";',
  375. 'function MyStatelessComponent({ foo, bar }) {',
  376. ' return <div>{foo}{bar}</div>;',
  377. '}'
  378. ].join('\n')
  379. },
  380. {
  381. code: [
  382. 'import defaults from "./defaults";',
  383. 'MyStatelessComponent.propTypes = {',
  384. ' foo: PropTypes.string',
  385. '};',
  386. 'MyStatelessComponent.defaultProps = defaults;',
  387. 'function MyStatelessComponent({ foo, bar }) {',
  388. ' return <div>{foo}{bar}</div>;',
  389. '}'
  390. ].join('\n'),
  391. parserOptions: Object.assign({sourceType: 'module'}, parserOptions)
  392. },
  393. {
  394. code: [
  395. 'import { foo } from "./defaults";',
  396. 'MyStatelessComponent.propTypes = {',
  397. ' foo: PropTypes.string',
  398. '};',
  399. 'MyStatelessComponent.defaultProps = foo;',
  400. 'function MyStatelessComponent({ foo, bar }) {',
  401. ' return <div>{foo}{bar}</div>;',
  402. '}'
  403. ].join('\n'),
  404. parserOptions: Object.assign({sourceType: 'module'}, parserOptions)
  405. },
  406. // using spread operator
  407. {
  408. code: [
  409. 'const component = rowsOfType(GuestlistEntry, (rowData, ownProps) => ({',
  410. ' ...rowData,',
  411. ' onPress: () => ownProps.onPress(rowData.id),',
  412. '}));'
  413. ].join('\n')
  414. },
  415. {
  416. code: [
  417. 'MyStatelessComponent.propTypes = {',
  418. ' ...stuff,',
  419. ' foo: PropTypes.string',
  420. '};',
  421. 'MyStatelessComponent.defaultProps = {',
  422. ' foo: "foo"',
  423. '};',
  424. 'function MyStatelessComponent({ foo, bar }) {',
  425. ' return <div>{foo}{bar}</div>;',
  426. '}'
  427. ].join('\n')
  428. },
  429. {
  430. code: [
  431. 'MyStatelessComponent.propTypes = {',
  432. ' foo: PropTypes.string',
  433. '};',
  434. 'MyStatelessComponent.defaultProps = {',
  435. ' ...defaults,',
  436. '};',
  437. 'function MyStatelessComponent({ foo, bar }) {',
  438. ' return <div>{foo}{bar}</div>;',
  439. '}'
  440. ].join('\n')
  441. },
  442. {
  443. code: [
  444. 'class Greeting extends React.Component {',
  445. ' render() {',
  446. ' return (',
  447. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  448. ' );',
  449. ' }',
  450. '}',
  451. 'Greeting.propTypes = {',
  452. ' ...someProps,',
  453. ' bar: PropTypes.string.isRequired',
  454. '};'
  455. ].join('\n')
  456. },
  457. {
  458. code: [
  459. 'class Greeting extends React.Component {',
  460. ' render() {',
  461. ' return (',
  462. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  463. ' );',
  464. ' }',
  465. '}',
  466. 'Greeting.propTypes = {',
  467. ' foo: PropTypes.string,',
  468. ' bar: PropTypes.string.isRequired',
  469. '};',
  470. 'Greeting.defaultProps = {',
  471. ' ...defaults,',
  472. ' bar: "bar"',
  473. '};'
  474. ].join('\n')
  475. },
  476. {
  477. code: [
  478. 'class Greeting extends React.Component {',
  479. ' render() {',
  480. ' return (',
  481. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  482. ' );',
  483. ' }',
  484. '}',
  485. 'Greeting.propTypes = {',
  486. ' foo: PropTypes.string,',
  487. ' bar: PropTypes.string.isRequired',
  488. '};',
  489. 'Greeting.defaultProps = {',
  490. ' ...defaults,',
  491. ' bar: "bar"',
  492. '};'
  493. ].join('\n')
  494. },
  495. //
  496. // with Flow annotations
  497. {
  498. code: [
  499. 'type Props = {',
  500. ' foo: string',
  501. '};',
  502. 'class Hello extends React.Component {',
  503. ' props: Props;',
  504. ' render() {',
  505. ' return <div>Hello {this.props.foo}</div>;',
  506. ' }',
  507. '}'
  508. ].join('\n'),
  509. parser: 'babel-eslint'
  510. },
  511. {
  512. code: [
  513. 'type Props = {',
  514. ' foo: string,',
  515. ' bar?: string',
  516. '};',
  517. 'class Hello extends React.Component {',
  518. ' props: Props;',
  519. ' render() {',
  520. ' return <div>Hello {this.props.foo}</div>;',
  521. ' }',
  522. '}',
  523. 'Hello.defaultProps = {',
  524. ' bar: "bar"',
  525. '};'
  526. ].join('\n'),
  527. parser: 'babel-eslint'
  528. },
  529. {
  530. code: [
  531. 'class Hello extends React.Component {',
  532. ' props: {',
  533. ' foo: string,',
  534. ' bar?: string',
  535. ' };',
  536. ' render() {',
  537. ' return <div>Hello {this.props.foo}</div>;',
  538. ' }',
  539. '}',
  540. 'Hello.defaultProps = {',
  541. ' bar: "bar"',
  542. '};'
  543. ].join('\n'),
  544. parser: 'babel-eslint'
  545. },
  546. {
  547. code: [
  548. 'class Hello extends React.Component {',
  549. ' props: {',
  550. ' foo: string',
  551. ' };',
  552. ' render() {',
  553. ' return <div>Hello {this.props.foo}</div>;',
  554. ' }',
  555. '}'
  556. ].join('\n'),
  557. parser: 'babel-eslint'
  558. },
  559. {
  560. code: [
  561. 'function Hello(props: { foo?: string }) {',
  562. ' return <div>Hello {props.foo}</div>;',
  563. '}',
  564. 'Hello.defaultProps = { foo: "foo" };'
  565. ].join('\n'),
  566. parser: 'babel-eslint'
  567. },
  568. {
  569. code: [
  570. 'function Hello(props: { foo: string }) {',
  571. ' return <div>Hello {foo}</div>;',
  572. '}'
  573. ].join('\n'),
  574. parser: 'babel-eslint'
  575. },
  576. {
  577. code: [
  578. 'const Hello = (props: { foo?: string }) => {',
  579. ' return <div>Hello {props.foo}</div>;',
  580. '};',
  581. 'Hello.defaultProps = { foo: "foo" };'
  582. ].join('\n'),
  583. parser: 'babel-eslint'
  584. },
  585. {
  586. code: [
  587. 'const Hello = (props: { foo: string }) => {',
  588. ' return <div>Hello {foo}</div>;',
  589. '};'
  590. ].join('\n'),
  591. parser: 'babel-eslint'
  592. },
  593. {
  594. code: [
  595. 'const Hello = function(props: { foo?: string }) {',
  596. ' return <div>Hello {props.foo}</div>;',
  597. '};',
  598. 'Hello.defaultProps = { foo: "foo" };'
  599. ].join('\n'),
  600. parser: 'babel-eslint'
  601. },
  602. {
  603. code: [
  604. 'const Hello = function(props: { foo: string }) {',
  605. ' return <div>Hello {foo}</div>;',
  606. '};'
  607. ].join('\n'),
  608. parser: 'babel-eslint'
  609. },
  610. {
  611. code: [
  612. 'type Props = {',
  613. ' foo: string,',
  614. ' bar?: string',
  615. '};',
  616. 'type Props2 = {',
  617. ' foo: string,',
  618. ' baz?: string',
  619. '}',
  620. 'function Hello(props: Props | Props2) {',
  621. ' return <div>Hello {props.foo}</div>;',
  622. '}',
  623. 'Hello.defaultProps = {',
  624. ' bar: "bar",',
  625. ' baz: "baz"',
  626. '};'
  627. ].join('\n'),
  628. parser: 'babel-eslint'
  629. },
  630. {
  631. code: [
  632. 'import type Props from "fake";',
  633. 'class Hello extends React.Component {',
  634. ' props: Props;',
  635. ' render () {',
  636. ' return <div>Hello {this.props.name.firstname}</div>;',
  637. ' }',
  638. '}'
  639. ].join('\n'),
  640. parser: 'babel-eslint'
  641. },
  642. {
  643. code: [
  644. 'type Props = any;',
  645. 'const Hello = function({ foo }: Props) {',
  646. ' return <div>Hello {foo}</div>;',
  647. '};'
  648. ].join('\n'),
  649. parser: 'babel-eslint'
  650. },
  651. {
  652. code: [
  653. 'import type ImportedProps from "fake";',
  654. 'type Props = ImportedProps;',
  655. 'function Hello(props: Props) {',
  656. ' return <div>Hello {props.name.firstname}</div>;',
  657. '}'
  658. ].join('\n'),
  659. parser: 'babel-eslint'
  660. },
  661. // don't error when variable is not in scope
  662. {
  663. code: [
  664. 'import type { ImportedType } from "fake";',
  665. 'type Props = ImportedType;',
  666. 'function Hello(props: Props) {',
  667. ' return <div>Hello {props.name.firstname}</div>;',
  668. '}'
  669. ].join('\n'),
  670. parser: 'babel-eslint'
  671. },
  672. // make sure error is not thrown with multiple assignments
  673. {
  674. code: [
  675. 'import type ImportedProps from "fake";',
  676. 'type NestedProps = ImportedProps;',
  677. 'type Props = NestedProps;',
  678. 'function Hello(props: Props) {',
  679. ' return <div>Hello {props.name.firstname}</div>;',
  680. '}'
  681. ].join('\n'),
  682. parser: 'babel-eslint'
  683. },
  684. // make sure defaultProps are correctly detected with quoted properties
  685. {
  686. code: [
  687. 'function Hello(props) {',
  688. ' return <div>Hello {props.bar}</div>;',
  689. '}',
  690. 'Hello.propTypes = {',
  691. ' bar: PropTypes.string',
  692. '};',
  693. 'Hello.defaultProps = {',
  694. ' "bar": "bar"',
  695. '};'
  696. ].join('\n'),
  697. parser: 'babel-eslint'
  698. },
  699. {
  700. code: [
  701. 'class Hello extends React.Component {',
  702. ' static propTypes = {',
  703. ' foo: PropTypes.string.isRequired',
  704. ' }',
  705. ' render() {',
  706. ' return <div>Hello {this.props.foo}</div>;',
  707. ' }',
  708. '}'
  709. ].join('\n'),
  710. parser: 'babel-eslint',
  711. options: [{forbidDefaultForRequired: true}]
  712. },
  713. // test support for React PropTypes as Component's class generic
  714. {
  715. code: [
  716. 'type HelloProps = {',
  717. ' foo: string,',
  718. ' bar?: string',
  719. '};',
  720. 'class Hello extends React.Component<HelloProps> {',
  721. ' static defaultProps = {',
  722. ' bar: "bar"',
  723. ' }',
  724. ' render() {',
  725. ' return <div>Hello {this.props.foo}</div>;',
  726. ' }',
  727. '}'
  728. ].join('\n'),
  729. parser: 'babel-eslint',
  730. options: [{forbidDefaultForRequired: true}]
  731. },
  732. {
  733. code: [
  734. 'type HelloProps = {',
  735. ' foo: string,',
  736. ' bar?: string',
  737. '};',
  738. 'class Hello extends Component<HelloProps> {',
  739. ' static defaultProps = {',
  740. ' bar: "bar"',
  741. ' }',
  742. ' render() {',
  743. ' return <div>Hello {this.props.foo}</div>;',
  744. ' }',
  745. '}'
  746. ].join('\n'),
  747. parser: 'babel-eslint',
  748. options: [{forbidDefaultForRequired: true}]
  749. },
  750. {
  751. code: [
  752. 'type HelloProps = {',
  753. ' foo: string,',
  754. ' bar?: string',
  755. '};',
  756. 'type HelloState = {',
  757. ' dummyState: string',
  758. '};',
  759. 'class Hello extends Component<HelloProps, HelloState> {',
  760. ' static defaultProps = {',
  761. ' bar: "bar"',
  762. ' }',
  763. ' render() {',
  764. ' return <div>Hello {this.props.foo}</div>;',
  765. ' }',
  766. '}'
  767. ].join('\n'),
  768. parser: 'babel-eslint',
  769. options: [{forbidDefaultForRequired: true}]
  770. },
  771. {
  772. code: [
  773. 'type HelloProps = {',
  774. ' foo?: string,',
  775. ' bar?: string',
  776. '};',
  777. 'class Hello extends Component<HelloProps> {',
  778. ' static defaultProps = {',
  779. ' foo: "foo",',
  780. ' bar: "bar"',
  781. ' }',
  782. ' render() {',
  783. ' return <div>Hello {this.props.foo}</div>;',
  784. ' }',
  785. '}'
  786. ].join('\n'),
  787. parser: 'babel-eslint',
  788. options: [{forbidDefaultForRequired: true}]
  789. }
  790. ],
  791. invalid: [
  792. //
  793. // stateless components
  794. {
  795. code: [
  796. 'function MyStatelessComponent({ foo, bar }) {',
  797. ' return <div>{foo}{bar}</div>;',
  798. '}',
  799. 'MyStatelessComponent.propTypes = {',
  800. ' foo: PropTypes.string,',
  801. ' bar: PropTypes.string.isRequired',
  802. '};'
  803. ].join('\n'),
  804. errors: [{
  805. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  806. line: 5,
  807. column: 3
  808. }]
  809. },
  810. {
  811. code: [
  812. 'function MyStatelessComponent({ foo, bar }) {',
  813. ' return <div>{foo}{bar}</div>;',
  814. '}',
  815. 'MyStatelessComponent.propTypes = forbidExtraProps({',
  816. ' foo: PropTypes.string,',
  817. ' bar: PropTypes.string.isRequired',
  818. '});'
  819. ].join('\n'),
  820. errors: [{
  821. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  822. line: 5,
  823. column: 3
  824. }],
  825. settings: {
  826. propWrapperFunctions: ['forbidExtraProps']
  827. }
  828. },
  829. {
  830. code: [
  831. 'function MyStatelessComponent({ foo, bar }) {',
  832. ' return <div>{foo}{bar}</div>;',
  833. '}',
  834. 'const propTypes = {',
  835. ' foo: PropTypes.string,',
  836. ' bar: PropTypes.string.isRequired',
  837. '};',
  838. 'MyStatelessComponent.propTypes = forbidExtraProps(propTypes);'
  839. ].join('\n'),
  840. errors: [{
  841. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  842. line: 5,
  843. column: 3
  844. }],
  845. settings: {
  846. propWrapperFunctions: ['forbidExtraProps']
  847. }
  848. },
  849. {
  850. code: [
  851. 'function MyStatelessComponent({ foo, bar }) {',
  852. ' return <div>{foo}{bar}</div>;',
  853. '}',
  854. 'MyStatelessComponent.propTypes = {',
  855. ' foo: PropTypes.string,',
  856. ' bar: PropTypes.string.isRequired',
  857. '};',
  858. 'MyStatelessComponent.propTypes.baz = React.propTypes.string;'
  859. ].join('\n'),
  860. errors: [
  861. {
  862. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  863. line: 5,
  864. column: 3
  865. },
  866. {
  867. message: 'propType "baz" is not required, but has no corresponding defaultProp declaration.',
  868. line: 8,
  869. column: 1
  870. }
  871. ]
  872. },
  873. {
  874. code: [
  875. 'const types = {',
  876. ' foo: PropTypes.string,',
  877. ' bar: PropTypes.string.isRequired',
  878. '};',
  879. 'function MyStatelessComponent({ foo, bar }) {',
  880. ' return <div>{foo}{bar}</div>;',
  881. '}',
  882. 'MyStatelessComponent.propTypes = types;'
  883. ].join('\n'),
  884. errors: [{
  885. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  886. line: 2,
  887. column: 3
  888. }]
  889. },
  890. {
  891. code: [
  892. 'const defaults = {',
  893. ' foo: "foo"',
  894. '};',
  895. 'function MyStatelessComponent({ foo, bar }) {',
  896. ' return <div>{foo}{bar}</div>;',
  897. '}',
  898. 'MyStatelessComponent.propTypes = {',
  899. ' foo: PropTypes.string,',
  900. ' bar: PropTypes.string',
  901. '};',
  902. 'MyStatelessComponent.defaultProps = defaults;'
  903. ].join('\n'),
  904. errors: [{
  905. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  906. line: 9,
  907. column: 3
  908. }]
  909. },
  910. {
  911. code: [
  912. 'const defaults = {',
  913. ' foo: "foo"',
  914. '};',
  915. 'const types = {',
  916. ' foo: PropTypes.string,',
  917. ' bar: PropTypes.string',
  918. '};',
  919. 'function MyStatelessComponent({ foo, bar }) {',
  920. ' return <div>{foo}{bar}</div>;',
  921. '}',
  922. 'MyStatelessComponent.propTypes = types;',
  923. 'MyStatelessComponent.defaultProps = defaults;'
  924. ].join('\n'),
  925. errors: [{
  926. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  927. line: 6,
  928. column: 3
  929. }]
  930. },
  931. //
  932. // createReactClass components
  933. {
  934. code: [
  935. 'var Greeting = createReactClass({',
  936. ' render: function() {',
  937. ' return <div>Hello {this.props.foo} {this.props.bar}</div>;',
  938. ' },',
  939. ' propTypes: {',
  940. ' foo: PropTypes.string,',
  941. ' bar: PropTypes.string.isRequired',
  942. ' }',
  943. '});'
  944. ].join('\n'),
  945. errors: [{
  946. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  947. line: 6,
  948. column: 5
  949. }]
  950. },
  951. {
  952. code: [
  953. 'var Greeting = createReactClass({',
  954. ' render: function() {',
  955. ' return <div>Hello {this.props.foo} {this.props.bar}</div>;',
  956. ' },',
  957. ' propTypes: {',
  958. ' foo: PropTypes.string,',
  959. ' bar: PropTypes.string',
  960. ' },',
  961. ' getDefaultProps: function() {',
  962. ' return {',
  963. ' foo: "foo"',
  964. ' };',
  965. ' }',
  966. '});'
  967. ].join('\n'),
  968. errors: [{
  969. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  970. line: 7,
  971. column: 5
  972. }]
  973. },
  974. //
  975. // ES6 class component
  976. {
  977. code: [
  978. 'class Greeting extends React.Component {',
  979. ' render() {',
  980. ' return (',
  981. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  982. ' );',
  983. ' }',
  984. '}',
  985. 'Greeting.propTypes = {',
  986. ' foo: PropTypes.string,',
  987. ' bar: PropTypes.string.isRequired',
  988. '};'
  989. ].join('\n'),
  990. errors: [{
  991. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  992. line: 9,
  993. column: 3
  994. }]
  995. },
  996. {
  997. code: [
  998. 'class Greeting extends React.Component {',
  999. ' render() {',
  1000. ' return (',
  1001. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  1002. ' );',
  1003. ' }',
  1004. '}',
  1005. 'Greeting.propTypes = {',
  1006. ' foo: PropTypes.string,',
  1007. ' bar: PropTypes.string',
  1008. '};',
  1009. 'Greeting.defaultProps = {',
  1010. ' foo: "foo"',
  1011. '};'
  1012. ].join('\n'),
  1013. errors: [{
  1014. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1015. line: 10,
  1016. column: 3
  1017. }]
  1018. },
  1019. {
  1020. code: [
  1021. 'class Greeting extends React.Component {',
  1022. ' render() {',
  1023. ' return (',
  1024. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  1025. ' );',
  1026. ' }',
  1027. '}',
  1028. 'Greeting.propTypes = {',
  1029. ' bar: PropTypes.string.isRequired',
  1030. '};',
  1031. 'Greeting.propTypes.foo = PropTypes.string;'
  1032. ].join('\n'),
  1033. errors: [{
  1034. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1035. line: 11,
  1036. column: 1
  1037. }]
  1038. },
  1039. {
  1040. code: [
  1041. 'class Greeting extends React.Component {',
  1042. ' render() {',
  1043. ' return (',
  1044. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  1045. ' );',
  1046. ' }',
  1047. '}',
  1048. 'Greeting.propTypes = {',
  1049. ' bar: PropTypes.string',
  1050. '};',
  1051. 'Greeting.propTypes.foo = PropTypes.string;',
  1052. 'Greeting.defaultProps = {};',
  1053. 'Greeting.defaultProps.foo = "foo";'
  1054. ].join('\n'),
  1055. errors: [{
  1056. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1057. line: 9,
  1058. column: 3
  1059. }]
  1060. },
  1061. {
  1062. code: [
  1063. 'class Greeting extends React.Component {',
  1064. ' render() {',
  1065. ' return (',
  1066. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  1067. ' );',
  1068. ' }',
  1069. '}',
  1070. 'Greeting.propTypes = {};',
  1071. 'Greeting.propTypes.foo = PropTypes.string;',
  1072. 'Greeting.defaultProps = {};',
  1073. 'Greeting.defaultProps.bar = "bar";'
  1074. ].join('\n'),
  1075. errors: [{
  1076. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1077. line: 9,
  1078. column: 1
  1079. }]
  1080. },
  1081. {
  1082. code: [
  1083. 'class Greeting extends React.Component {',
  1084. ' render() {',
  1085. ' return (',
  1086. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  1087. ' );',
  1088. ' }',
  1089. '}',
  1090. 'const props = {',
  1091. ' foo: PropTypes.string,',
  1092. ' bar: PropTypes.string.isRequired',
  1093. '};',
  1094. 'Greeting.propTypes = props;'
  1095. ].join('\n'),
  1096. errors: [{
  1097. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1098. line: 9,
  1099. column: 3
  1100. }]
  1101. },
  1102. {
  1103. code: [
  1104. 'class Greeting extends React.Component {',
  1105. ' render() {',
  1106. ' return (',
  1107. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  1108. ' );',
  1109. ' }',
  1110. '}',
  1111. 'const props = {',
  1112. ' foo: PropTypes.string,',
  1113. ' bar: PropTypes.string',
  1114. '};',
  1115. 'const defaults = {',
  1116. ' foo: "foo"',
  1117. '};',
  1118. 'Greeting.propTypes = props;',
  1119. 'Greeting.defaultProps = defaults;'
  1120. ].join('\n'),
  1121. errors: [{
  1122. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1123. line: 10,
  1124. column: 3
  1125. }]
  1126. },
  1127. //
  1128. // ES6 classes with static getter methods
  1129. {
  1130. code: [
  1131. 'class Hello extends React.Component {',
  1132. ' static get propTypes() {',
  1133. ' return {',
  1134. ' name: PropTypes.string',
  1135. ' };',
  1136. ' }',
  1137. ' render() {',
  1138. ' return <div>Hello {this.props.name}</div>;',
  1139. ' }',
  1140. '}'
  1141. ].join('\n'),
  1142. errors: [{
  1143. message: 'propType "name" is not required, but has no corresponding defaultProp declaration.',
  1144. line: 4,
  1145. column: 7
  1146. }]
  1147. },
  1148. {
  1149. code: [
  1150. 'class Hello extends React.Component {',
  1151. ' static get propTypes() {',
  1152. ' return {',
  1153. ' foo: PropTypes.string,',
  1154. ' bar: PropTypes.string',
  1155. ' };',
  1156. ' }',
  1157. ' static get defaultProps() {',
  1158. ' return {',
  1159. ' bar: "world"',
  1160. ' };',
  1161. ' }',
  1162. ' render() {',
  1163. ' return <div>Hello {this.props.name}</div>;',
  1164. ' }',
  1165. '}'
  1166. ].join('\n'),
  1167. errors: [{
  1168. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1169. line: 4,
  1170. column: 7
  1171. }]
  1172. },
  1173. {
  1174. code: [
  1175. 'const props = {',
  1176. ' foo: PropTypes.string',
  1177. '};',
  1178. 'class Hello extends React.Component {',
  1179. ' static get propTypes() {',
  1180. ' return props;',
  1181. ' }',
  1182. ' render() {',
  1183. ' return <div>Hello {this.props.name}</div>;',
  1184. ' }',
  1185. '}'
  1186. ].join('\n'),
  1187. errors: [{
  1188. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1189. line: 2,
  1190. column: 3
  1191. }]
  1192. },
  1193. {
  1194. code: [
  1195. 'const defaults = {',
  1196. ' bar: "world"',
  1197. '};',
  1198. 'class Hello extends React.Component {',
  1199. ' static get propTypes() {',
  1200. ' return {',
  1201. ' foo: PropTypes.string,',
  1202. ' bar: PropTypes.string',
  1203. ' };',
  1204. ' }',
  1205. ' static get defaultProps() {',
  1206. ' return defaults;',
  1207. ' }',
  1208. ' render() {',
  1209. ' return <div>Hello {this.props.name}</div>;',
  1210. ' }',
  1211. '}'
  1212. ].join('\n'),
  1213. errors: [{
  1214. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1215. line: 7,
  1216. column: 7
  1217. }]
  1218. },
  1219. //
  1220. // ES6 classes with property initializers
  1221. {
  1222. code: [
  1223. 'class Greeting extends React.Component {',
  1224. ' render() {',
  1225. ' return (',
  1226. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  1227. ' );',
  1228. ' }',
  1229. ' static propTypes = {',
  1230. ' foo: PropTypes.string,',
  1231. ' bar: PropTypes.string.isRequired',
  1232. ' };',
  1233. '}'
  1234. ].join('\n'),
  1235. parser: 'babel-eslint',
  1236. errors: [{
  1237. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1238. line: 8,
  1239. column: 5
  1240. }]
  1241. },
  1242. {
  1243. code: [
  1244. 'class Greeting extends React.Component {',
  1245. ' render() {',
  1246. ' return (',
  1247. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  1248. ' );',
  1249. ' }',
  1250. ' static propTypes = {',
  1251. ' foo: PropTypes.string,',
  1252. ' bar: PropTypes.string',
  1253. ' };',
  1254. ' static defaultProps = {',
  1255. ' foo: "foo"',
  1256. ' };',
  1257. '}'
  1258. ].join('\n'),
  1259. parser: 'babel-eslint',
  1260. errors: [{
  1261. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1262. line: 9,
  1263. column: 5
  1264. }]
  1265. },
  1266. {
  1267. code: [
  1268. 'const props = {',
  1269. ' foo: PropTypes.string,',
  1270. ' bar: PropTypes.string.isRequired',
  1271. '};',
  1272. 'class Greeting extends React.Component {',
  1273. ' render() {',
  1274. ' return (',
  1275. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  1276. ' );',
  1277. ' }',
  1278. ' static propTypes = props;',
  1279. '}'
  1280. ].join('\n'),
  1281. parser: 'babel-eslint',
  1282. errors: [{
  1283. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1284. line: 2,
  1285. column: 3
  1286. }]
  1287. },
  1288. {
  1289. code: [
  1290. 'const props = {',
  1291. ' foo: PropTypes.string,',
  1292. ' bar: PropTypes.string',
  1293. '};',
  1294. 'const defaults = {',
  1295. ' foo: "foo"',
  1296. '};',
  1297. 'class Greeting extends React.Component {',
  1298. ' render() {',
  1299. ' return (',
  1300. ' <h1>Hello, {this.props.foo} {this.props.bar}</h1>',
  1301. ' );',
  1302. ' }',
  1303. ' static propTypes = props;',
  1304. ' static defaultProps = defaults;',
  1305. '}'
  1306. ].join('\n'),
  1307. parser: 'babel-eslint',
  1308. errors: [{
  1309. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1310. line: 3,
  1311. column: 3
  1312. }]
  1313. },
  1314. //
  1315. // edge cases
  1316. {
  1317. code: [
  1318. 'let Greetings = {};',
  1319. 'Greetings.Hello = class extends React.Component {',
  1320. ' render () {',
  1321. ' return <div>Hello {this.props.foo}</div>;',
  1322. ' }',
  1323. '}',
  1324. 'Greetings.Hello.propTypes = {',
  1325. ' foo: PropTypes.string',
  1326. '};'
  1327. ].join('\n'),
  1328. errors: [{
  1329. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1330. line: 8,
  1331. column: 3
  1332. }]
  1333. },
  1334. {
  1335. code: [
  1336. 'var Greetings = ({ foo = "foo" }) => {',
  1337. ' return <div>Hello {this.props.foo}</div>;',
  1338. '}',
  1339. 'Greetings.propTypes = {',
  1340. ' foo: PropTypes.string',
  1341. '};'
  1342. ].join('\n'),
  1343. errors: [{
  1344. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1345. line: 5,
  1346. column: 3
  1347. }]
  1348. },
  1349. // component with no declared props followed by a failing component
  1350. {
  1351. code: [
  1352. 'var ComponentWithNoProps = ({ bar = "bar" }) => {',
  1353. ' return <div>Hello {this.props.foo}</div>;',
  1354. '}',
  1355. 'var Greetings = ({ foo = "foo" }) => {',
  1356. ' return <div>Hello {this.props.foo}</div>;',
  1357. '}',
  1358. 'Greetings.propTypes = {',
  1359. ' foo: PropTypes.string',
  1360. '};'
  1361. ].join('\n'),
  1362. errors: [{
  1363. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1364. line: 8,
  1365. column: 3
  1366. }]
  1367. },
  1368. //
  1369. // with Flow annotations
  1370. {
  1371. code: [
  1372. 'class Hello extends React.Component {',
  1373. ' props: {',
  1374. ' foo?: string,',
  1375. ' bar?: string',
  1376. ' };',
  1377. ' render() {',
  1378. ' return <div>Hello {this.props.foo}</div>;',
  1379. ' }',
  1380. '}',
  1381. 'Hello.defaultProps = {',
  1382. ' foo: "foo"',
  1383. '};'
  1384. ].join('\n'),
  1385. parser: 'babel-eslint',
  1386. errors: [{
  1387. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1388. line: 4,
  1389. column: 5
  1390. }]
  1391. },
  1392. {
  1393. code: [
  1394. 'type Props = {',
  1395. ' foo: string,',
  1396. ' bar?: string',
  1397. '};',
  1398. 'class Hello extends React.Component {',
  1399. ' props: Props;',
  1400. ' render() {',
  1401. ' return <div>Hello {this.props.foo}</div>;',
  1402. ' }',
  1403. '}'
  1404. ].join('\n'),
  1405. parser: 'babel-eslint',
  1406. errors: [{
  1407. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1408. line: 3,
  1409. column: 3
  1410. }]
  1411. },
  1412. {
  1413. code: [
  1414. 'type Props = {',
  1415. ' foo?: string',
  1416. '};',
  1417. 'class Hello extends React.Component {',
  1418. ' props: Props;',
  1419. ' static defaultProps: { foo: string };',
  1420. ' render() {',
  1421. ' return <div>Hello {this.props.foo}</div>;',
  1422. ' }',
  1423. '}'
  1424. ].join('\n'),
  1425. parser: 'babel-eslint',
  1426. errors: [{
  1427. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1428. line: 2,
  1429. column: 3
  1430. }]
  1431. },
  1432. {
  1433. code: [
  1434. 'class Hello extends React.Component {',
  1435. ' props: {',
  1436. ' foo: string,',
  1437. ' bar?: string',
  1438. ' };',
  1439. ' render() {',
  1440. ' return <div>Hello {this.props.foo}</div>;',
  1441. ' }',
  1442. '}'
  1443. ].join('\n'),
  1444. parser: 'babel-eslint',
  1445. errors: [{
  1446. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1447. line: 4,
  1448. column: 5
  1449. }]
  1450. },
  1451. {
  1452. code: [
  1453. 'class Hello extends React.Component {',
  1454. ' props: {',
  1455. ' foo?: string,',
  1456. ' bar?: string',
  1457. ' };',
  1458. ' render() {',
  1459. ' return <div>Hello {this.props.foo}</div>;',
  1460. ' }',
  1461. '}'
  1462. ].join('\n'),
  1463. parser: 'babel-eslint',
  1464. errors: [
  1465. {
  1466. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1467. line: 3,
  1468. column: 5
  1469. },
  1470. {
  1471. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1472. line: 4,
  1473. column: 5
  1474. }
  1475. ]
  1476. },
  1477. {
  1478. code: [
  1479. 'class Hello extends React.Component {',
  1480. ' props: {',
  1481. ' foo?: string',
  1482. ' };',
  1483. ' static defaultProps: { foo: string };',
  1484. ' render() {',
  1485. ' return <div>Hello {this.props.foo}</div>;',
  1486. ' }',
  1487. '}'
  1488. ].join('\n'),
  1489. parser: 'babel-eslint',
  1490. errors: [{
  1491. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1492. line: 3,
  1493. column: 5
  1494. }]
  1495. },
  1496. {
  1497. code: [
  1498. 'type Props = {',
  1499. ' foo?: string,',
  1500. ' bar?: string',
  1501. '};',
  1502. 'class Hello extends React.Component {',
  1503. ' props: Props;',
  1504. ' render() {',
  1505. ' return <div>Hello {this.props.foo}</div>;',
  1506. ' }',
  1507. '}',
  1508. 'Hello.defaultProps = {',
  1509. ' foo: "foo"',
  1510. '};'
  1511. ].join('\n'),
  1512. parser: 'babel-eslint',
  1513. errors: [{
  1514. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1515. line: 3,
  1516. column: 3
  1517. }]
  1518. },
  1519. {
  1520. code: [
  1521. 'type Props = {',
  1522. ' foo?: string,',
  1523. ' bar?: string',
  1524. '};',
  1525. 'class Hello extends React.Component {',
  1526. ' props: Props;',
  1527. ' static defaultProps: { foo: string, bar: string };',
  1528. ' render() {',
  1529. ' return <div>Hello {this.props.foo}</div>;',
  1530. ' }',
  1531. '}',
  1532. 'Hello.defaultProps = {',
  1533. ' foo: "foo"',
  1534. '};'
  1535. ].join('\n'),
  1536. parser: 'babel-eslint',
  1537. errors: [{
  1538. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1539. line: 3,
  1540. column: 3
  1541. }]
  1542. },
  1543. {
  1544. code: [
  1545. 'class Hello extends React.Component {',
  1546. ' props: {',
  1547. ' foo?: string,',
  1548. ' bar?: string',
  1549. ' };',
  1550. ' static defaultProps: { foo: string, bar: string };',
  1551. ' render() {',
  1552. ' return <div>Hello {this.props.foo}</div>;',
  1553. ' }',
  1554. '}',
  1555. 'Hello.defaultProps = {',
  1556. ' foo: "foo"',
  1557. '};'
  1558. ].join('\n'),
  1559. parser: 'babel-eslint',
  1560. errors: [{
  1561. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1562. line: 4,
  1563. column: 5
  1564. }]
  1565. },
  1566. {
  1567. code: [
  1568. 'function Hello(props: { foo?: string }) {',
  1569. ' return <div>Hello {props.foo}</div>;',
  1570. '}'
  1571. ].join('\n'),
  1572. parser: 'babel-eslint',
  1573. errors: [{
  1574. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1575. line: 1,
  1576. column: 25
  1577. }]
  1578. },
  1579. {
  1580. code: [
  1581. 'function Hello({ foo = "foo" }: { foo?: string }) {',
  1582. ' return <div>Hello {foo}</div>;',
  1583. '}'
  1584. ].join('\n'),
  1585. parser: 'babel-eslint',
  1586. errors: [{
  1587. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1588. line: 1,
  1589. column: 35
  1590. }]
  1591. },
  1592. {
  1593. code: [
  1594. 'function Hello(props: { foo?: string, bar?: string }) {',
  1595. ' return <div>Hello {props.foo}</div>;',
  1596. '}',
  1597. 'Hello.defaultProps = { foo: "foo" };'
  1598. ].join('\n'),
  1599. parser: 'babel-eslint',
  1600. errors: [{
  1601. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1602. line: 1,
  1603. column: 39
  1604. }]
  1605. },
  1606. {
  1607. code: [
  1608. 'function Hello(props: { foo?: string, bar?: string }) {',
  1609. ' return <div>Hello {props.foo}</div>;',
  1610. '}'
  1611. ].join('\n'),
  1612. parser: 'babel-eslint',
  1613. errors: [
  1614. {
  1615. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1616. line: 1,
  1617. column: 25
  1618. },
  1619. {
  1620. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1621. line: 1,
  1622. column: 39
  1623. }
  1624. ]
  1625. },
  1626. {
  1627. code: [
  1628. 'type Props = {',
  1629. ' foo?: string',
  1630. '};',
  1631. 'function Hello(props: Props) {',
  1632. ' return <div>Hello {props.foo}</div>;',
  1633. '}'
  1634. ].join('\n'),
  1635. parser: 'babel-eslint',
  1636. errors: [{
  1637. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1638. line: 2,
  1639. column: 3
  1640. }]
  1641. },
  1642. {
  1643. code: [
  1644. 'const Hello = (props: { foo?: string }) => {',
  1645. ' return <div>Hello {props.foo}</div>;',
  1646. '};'
  1647. ].join('\n'),
  1648. parser: 'babel-eslint',
  1649. errors: [{
  1650. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1651. line: 1,
  1652. column: 25
  1653. }]
  1654. },
  1655. {
  1656. code: [
  1657. 'const Hello = (props: { foo?: string, bar?: string }) => {',
  1658. ' return <div>Hello {props.foo}</div>;',
  1659. '};',
  1660. 'Hello.defaultProps = { foo: "foo" };'
  1661. ].join('\n'),
  1662. parser: 'babel-eslint',
  1663. errors: [{
  1664. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1665. line: 1,
  1666. column: 39
  1667. }]
  1668. },
  1669. {
  1670. code: [
  1671. 'const Hello = function(props: { foo?: string }) {',
  1672. ' return <div>Hello {props.foo}</div>;',
  1673. '};'
  1674. ].join('\n'),
  1675. parser: 'babel-eslint',
  1676. errors: [{
  1677. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1678. line: 1,
  1679. column: 33
  1680. }]
  1681. },
  1682. {
  1683. code: [
  1684. 'const Hello = function(props: { foo?: string, bar?: string }) {',
  1685. ' return <div>Hello {props.foo}</div>;',
  1686. '};',
  1687. 'Hello.defaultProps = { foo: "foo" };'
  1688. ].join('\n'),
  1689. parser: 'babel-eslint',
  1690. errors: [{
  1691. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1692. line: 1,
  1693. column: 47
  1694. }]
  1695. },
  1696. {
  1697. code: [
  1698. 'type Props = {',
  1699. ' foo?: string',
  1700. '};',
  1701. 'function Hello(props: Props) {',
  1702. ' return <div>Hello {props.foo}</div>;',
  1703. '}'
  1704. ].join('\n'),
  1705. parser: 'babel-eslint',
  1706. errors: [{
  1707. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1708. line: 2,
  1709. column: 3
  1710. }]
  1711. },
  1712. {
  1713. code: [
  1714. 'type Props = {',
  1715. ' foo?: string,',
  1716. ' bar?: string',
  1717. '};',
  1718. 'function Hello(props: Props) {',
  1719. ' return <div>Hello {props.foo}</div>;',
  1720. '}',
  1721. 'Hello.defaultProps = { foo: "foo" };'
  1722. ].join('\n'),
  1723. parser: 'babel-eslint',
  1724. errors: [{
  1725. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1726. line: 3,
  1727. column: 3
  1728. }]
  1729. },
  1730. // UnionType
  1731. {
  1732. code: [
  1733. 'function Hello(props: { one?: string } | { two?: string }) {',
  1734. ' return <div>Hello {props.foo}</div>;',
  1735. '}'
  1736. ].join('\n'),
  1737. parser: 'babel-eslint',
  1738. errors: [
  1739. {
  1740. message: 'propType "one" is not required, but has no corresponding defaultProp declaration.',
  1741. line: 1,
  1742. column: 25
  1743. },
  1744. {
  1745. message: 'propType "two" is not required, but has no corresponding defaultProp declaration.',
  1746. line: 1,
  1747. column: 44
  1748. }
  1749. ]
  1750. },
  1751. {
  1752. code: [
  1753. 'type Props = {',
  1754. ' foo: string,',
  1755. ' bar?: string',
  1756. '};',
  1757. 'type Props2 = {',
  1758. ' foo: string,',
  1759. ' baz?: string',
  1760. '}',
  1761. 'function Hello(props: Props | Props2) {',
  1762. ' return <div>Hello {props.foo}</div>;',
  1763. '}'
  1764. ].join('\n'),
  1765. parser: 'babel-eslint',
  1766. errors: [
  1767. {
  1768. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.',
  1769. line: 3,
  1770. column: 3
  1771. },
  1772. {
  1773. message: 'propType "baz" is not required, but has no corresponding defaultProp declaration.',
  1774. line: 7,
  1775. column: 3
  1776. }
  1777. ]
  1778. },
  1779. {
  1780. code: [
  1781. 'type Props = {',
  1782. ' foo: string,',
  1783. ' bar?: string',
  1784. '};',
  1785. 'type Props2 = {',
  1786. ' foo: string,',
  1787. ' baz?: string',
  1788. '}',
  1789. 'function Hello(props: Props | Props2) {',
  1790. ' return <div>Hello {props.foo}</div>;',
  1791. '}',
  1792. 'Hello.defaultProps = {',
  1793. ' bar: "bar"',
  1794. '};'
  1795. ].join('\n'),
  1796. parser: 'babel-eslint',
  1797. errors: [
  1798. {
  1799. message: 'propType "baz" is not required, but has no corresponding defaultProp declaration.',
  1800. line: 7,
  1801. column: 3
  1802. }
  1803. ]
  1804. },
  1805. {
  1806. code: [
  1807. 'type HelloProps = {',
  1808. ' two?: string,',
  1809. ' three: string',
  1810. '};',
  1811. 'function Hello(props: { one?: string } | HelloProps) {',
  1812. ' return <div>Hello {props.foo}</div>;',
  1813. '}'
  1814. ].join('\n'),
  1815. parser: 'babel-eslint',
  1816. errors: [
  1817. {
  1818. message: 'propType "two" is not required, but has no corresponding defaultProp declaration.',
  1819. line: 2,
  1820. column: 3
  1821. },
  1822. {
  1823. message: 'propType "one" is not required, but has no corresponding defaultProp declaration.',
  1824. line: 5,
  1825. column: 25
  1826. }
  1827. ]
  1828. },
  1829. {
  1830. code: [
  1831. 'type HelloProps = {',
  1832. ' two?: string,',
  1833. ' three: string',
  1834. '};',
  1835. 'function Hello(props: ExternalProps | HelloProps) {',
  1836. ' return <div>Hello {props.foo}</div>;',
  1837. '}'
  1838. ].join('\n'),
  1839. parser: 'babel-eslint',
  1840. errors: [
  1841. {
  1842. message: 'propType "two" is not required, but has no corresponding defaultProp declaration.',
  1843. line: 2,
  1844. column: 3
  1845. }
  1846. ]
  1847. },
  1848. {
  1849. code: [
  1850. 'class Hello extends React.Component {',
  1851. ' static propTypes = {',
  1852. ' foo: PropTypes.string',
  1853. ' };',
  1854. ' render() {',
  1855. ' return <div>Hello {this.props.foo}</div>;',
  1856. ' }',
  1857. '}'
  1858. ].join('\n'),
  1859. parser: 'babel-eslint',
  1860. errors: [
  1861. {
  1862. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.',
  1863. line: 3,
  1864. column: 5
  1865. }
  1866. ]
  1867. },
  1868. {
  1869. code: [
  1870. 'class Hello extends React.Component {',
  1871. ' static get propTypes() {',
  1872. ' return {',
  1873. ' name: PropTypes.string',
  1874. ' };',
  1875. ' }',
  1876. ' static defaultProps() {',
  1877. ' return {',
  1878. ' name: \'John\'',
  1879. ' };',
  1880. ' }',
  1881. ' render() {',
  1882. ' return <div>Hello {this.props.name}</div>;',
  1883. ' }',
  1884. '}'
  1885. ].join('\n'),
  1886. parser: 'babel-eslint',
  1887. errors: [{
  1888. message: 'propType "name" is not required, but has no corresponding defaultProp declaration.'
  1889. }]
  1890. },
  1891. {
  1892. code: [
  1893. 'class Hello extends React.Component {',
  1894. ' static get propTypes() {',
  1895. ' return {',
  1896. ' \'first-name\': PropTypes.string',
  1897. ' };',
  1898. ' }',
  1899. ' render() {',
  1900. ' return <div>Hello {this.props[\'first-name\']}</div>;',
  1901. ' }',
  1902. '}'
  1903. ].join('\n'),
  1904. parser: 'babel-eslint',
  1905. errors: [{
  1906. message: 'propType "first-name" is not required, but has no corresponding defaultProp declaration.'
  1907. }]
  1908. },
  1909. {
  1910. code: [
  1911. 'class Hello extends React.Component {',
  1912. ' render() {',
  1913. ' return <div>Hello {this.props.foo}</div>;',
  1914. ' }',
  1915. '}',
  1916. 'Hello.propTypes = {',
  1917. ' foo: PropTypes.string.isRequired',
  1918. '};',
  1919. 'Hello.defaultProps = {',
  1920. ' foo: \'bar\'',
  1921. '};'
  1922. ].join('\n'),
  1923. options: [{forbidDefaultForRequired: true}],
  1924. errors: [{
  1925. message: 'propType "foo" is required and should not have a defaultProp declaration.'
  1926. }]
  1927. },
  1928. {
  1929. code: [
  1930. 'function Hello(props) {',
  1931. ' return <div>Hello {props.foo}</div>;',
  1932. '}',
  1933. 'Hello.propTypes = {',
  1934. ' foo: PropTypes.string.isRequired',
  1935. '};',
  1936. 'Hello.defaultProps = {',
  1937. ' foo: \'bar\'',
  1938. '};'
  1939. ].join('\n'),
  1940. options: [{forbidDefaultForRequired: true}],
  1941. errors: [{
  1942. message: 'propType "foo" is required and should not have a defaultProp declaration.'
  1943. }]
  1944. },
  1945. {
  1946. code: [
  1947. 'const Hello = (props) => {',
  1948. ' return <div>Hello {props.foo}</div>;',
  1949. '};',
  1950. 'Hello.propTypes = {',
  1951. ' foo: PropTypes.string.isRequired',
  1952. '};',
  1953. 'Hello.defaultProps = {',
  1954. ' foo: \'bar\'',
  1955. '};'
  1956. ].join('\n'),
  1957. options: [{forbidDefaultForRequired: true}],
  1958. errors: [{
  1959. message: 'propType "foo" is required and should not have a defaultProp declaration.'
  1960. }]
  1961. },
  1962. {
  1963. code: [
  1964. 'class Hello extends React.Component {',
  1965. ' static propTypes = {',
  1966. ' foo: PropTypes.string.isRequired',
  1967. ' }',
  1968. ' static defaultProps = {',
  1969. ' foo: \'bar\'',
  1970. ' }',
  1971. ' render() {',
  1972. ' return <div>Hello {this.props.foo}</div>;',
  1973. ' }',
  1974. '}'
  1975. ].join('\n'),
  1976. parser: 'babel-eslint',
  1977. options: [{forbidDefaultForRequired: true}],
  1978. errors: [{
  1979. message: 'propType "foo" is required and should not have a defaultProp declaration.'
  1980. }]
  1981. },
  1982. {
  1983. code: [
  1984. 'class Hello extends React.Component {',
  1985. ' static get propTypes () {',
  1986. ' return {',
  1987. ' foo: PropTypes.string.isRequired',
  1988. ' };',
  1989. ' }',
  1990. ' static get defaultProps() {',
  1991. ' return {',
  1992. ' foo: \'bar\'',
  1993. ' };',
  1994. ' }',
  1995. ' render() {',
  1996. ' return <div>Hello {this.props.foo}</div>;',
  1997. ' }',
  1998. '}'
  1999. ].join('\n'),
  2000. options: [{forbidDefaultForRequired: true}],
  2001. errors: [{
  2002. message: 'propType "foo" is required and should not have a defaultProp declaration.'
  2003. }]
  2004. },
  2005. // test support for React PropTypes as Component's class generic
  2006. {
  2007. code: [
  2008. 'type HelloProps = {',
  2009. ' foo: string,',
  2010. ' bar?: string',
  2011. '};',
  2012. 'class Hello extends React.Component<HelloProps> {',
  2013. ' render() {',
  2014. ' return <div>Hello {this.props.foo}</div>;',
  2015. ' }',
  2016. '}'
  2017. ].join('\n'),
  2018. parser: 'babel-eslint',
  2019. errors: [{
  2020. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.'
  2021. }]
  2022. },
  2023. {
  2024. code: [
  2025. 'type HelloProps = {',
  2026. ' foo: string,',
  2027. ' bar?: string',
  2028. '};',
  2029. 'class Hello extends Component<HelloProps> {',
  2030. ' render() {',
  2031. ' return <div>Hello {this.props.foo}</div>;',
  2032. ' }',
  2033. '}'
  2034. ].join('\n'),
  2035. parser: 'babel-eslint',
  2036. errors: [{
  2037. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.'
  2038. }]
  2039. },
  2040. {
  2041. code: [
  2042. 'type HelloProps = {',
  2043. ' foo: string,',
  2044. ' bar?: string',
  2045. '};',
  2046. 'type HelloState = {',
  2047. ' dummyState: string',
  2048. '};',
  2049. 'class Hello extends Component<HelloProps, HelloState> {',
  2050. ' render() {',
  2051. ' return <div>Hello {this.props.foo}</div>;',
  2052. ' }',
  2053. '}'
  2054. ].join('\n'),
  2055. parser: 'babel-eslint',
  2056. errors: [{
  2057. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.'
  2058. }]
  2059. },
  2060. {
  2061. code: [
  2062. 'type HelloProps = {',
  2063. ' foo?: string,',
  2064. ' bar?: string',
  2065. '};',
  2066. 'class Hello extends Component<HelloProps> {',
  2067. ' render() {',
  2068. ' return <div>Hello {this.props.foo}</div>;',
  2069. ' }',
  2070. '}'
  2071. ].join('\n'),
  2072. parser: 'babel-eslint',
  2073. errors: [{
  2074. message: 'propType "foo" is not required, but has no corresponding defaultProp declaration.'
  2075. }, {
  2076. message: 'propType "bar" is not required, but has no corresponding defaultProp declaration.'
  2077. }]
  2078. }
  2079. ]
  2080. });