123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978 |
- /**
- * @fileoverview Validate JSX indentation
- * @author Yannick Croissant
- */
- 'use strict';
- // ------------------------------------------------------------------------------
- // Requirements
- // ------------------------------------------------------------------------------
- const rule = require('../../../lib/rules/jsx-indent');
- const RuleTester = require('eslint').RuleTester;
- const parserOptions = {
- ecmaVersion: 2018,
- sourceType: 'module',
- ecmaFeatures: {
- jsx: true
- }
- };
- // ------------------------------------------------------------------------------
- // Tests
- // ------------------------------------------------------------------------------
- const ruleTester = new RuleTester({parserOptions});
- ruleTester.run('jsx-indent', rule, {
- valid: [{
- code: [
- '<App></App>'
- ].join('\n')
- }, {
- code: [
- '<App>',
- '</App>'
- ].join('\n')
- }, {
- code: [
- '<App>',
- ' <Foo />',
- '</App>'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- '<App>',
- '<Foo />',
- '</App>'
- ].join('\n'),
- options: [0]
- }, {
- code: [
- ' <App>',
- '<Foo />',
- ' </App>'
- ].join('\n'),
- options: [-2]
- }, {
- code: [
- '<App>',
- '\t<Foo />',
- '</App>'
- ].join('\n'),
- options: ['tab']
- }, {
- code: [
- 'function App() {',
- ' return <App>',
- ' <Foo />',
- ' </App>;',
- '}'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- 'function App() {',
- ' return (<App>',
- ' <Foo />',
- ' </App>);',
- '}'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- 'function App() {',
- ' return (',
- ' <App>',
- ' <Foo />',
- ' </App>',
- ' );',
- '}'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- 'it(',
- ' (',
- ' <div>',
- ' <span />',
- ' </div>',
- ' )',
- ')'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- 'it(',
- ' (<div>',
- ' <span />',
- ' <span />',
- ' <span />',
- ' </div>)',
- ')'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- '(',
- ' <div>',
- ' <span />',
- ' </div>',
- ')'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- '{',
- ' head.title &&',
- ' <h1>',
- ' {head.title}',
- ' </h1>',
- '}'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- '{',
- ' head.title &&',
- ' <h1>',
- ' {head.title}',
- ' </h1>',
- '}'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- '{',
- ' head.title && (',
- ' <h1>',
- ' {head.title}',
- ' </h1>)',
- '}'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- '{',
- ' head.title && (',
- ' <h1>',
- ' {head.title}',
- ' </h1>',
- ' )',
- '}'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- '[',
- ' <div />,',
- ' <div />',
- ']'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- '<div>',
- ' {',
- ' [',
- ' <Foo />,',
- ' <Bar />',
- ' ]',
- ' }',
- '</div>'
- ].join('\n')
- }, {
- code: [
- '<div>',
- ' {foo &&',
- ' [',
- ' <Foo />,',
- ' <Bar />',
- ' ]',
- ' }',
- '</div>'
- ].join('\n')
- }, {
- // Literals indentation is not touched
- code: [
- '<div>',
- 'bar <div>',
- ' bar',
- ' bar {foo}',
- 'bar </div>',
- '</div>'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon at the end of the first expression)
- code: [
- 'foo ?',
- ' <Foo /> :',
- ' <Bar />'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon at the start of the second expression)
- code: [
- 'foo ?',
- ' <Foo />',
- ' : <Bar />'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon on its own line)
- code: [
- 'foo ?',
- ' <Foo />',
- ':',
- ' <Bar />'
- ].join('\n')
- }, {
- // Multiline ternary
- // (multiline JSX, colon on its own line)
- code: [
- '{!foo ?',
- ' <Foo',
- ' onClick={this.onClick}',
- ' />',
- ':',
- ' <Bar',
- ' onClick={this.onClick}',
- ' />',
- '}'
- ].join('\n')
- }, {
- // Multiline ternary
- // (first expression on test line, colon at the end of the first expression)
- code: [
- 'foo ? <Foo /> :',
- '<Bar />'
- ].join('\n')
- }, {
- // Multiline ternary
- // (first expression on test line, colon at the start of the second expression)
- code: [
- 'foo ? <Foo />',
- ': <Bar />'
- ].join('\n')
- }, {
- // Multiline ternary
- // (first expression on test line, colon on its own line)
- code: [
- 'foo ? <Foo />',
- ':',
- '<Bar />'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon at the end of the first expression, parenthesized first expression)
- code: [
- 'foo ? (',
- ' <Foo />',
- ') :',
- ' <Bar />'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon at the start of the second expression, parenthesized first expression)
- code: [
- 'foo ? (',
- ' <Foo />',
- ')',
- ' : <Bar />'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon on its own line, parenthesized first expression)
- code: [
- 'foo ? (',
- ' <Foo />',
- ')',
- ':',
- ' <Bar />'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon at the end of the first expression, parenthesized second expression)
- code: [
- 'foo ?',
- ' <Foo /> : (',
- ' <Bar />',
- ' )'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon on its own line, parenthesized second expression)
- code: [
- 'foo ?',
- ' <Foo />',
- ': (',
- ' <Bar />',
- ')'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon indented on its own line, parenthesized second expression)
- code: [
- 'foo ?',
- ' <Foo />',
- ' : (',
- ' <Bar />',
- ' )'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon at the end of the first expression, both expression parenthesized)
- code: [
- 'foo ? (',
- ' <Foo />',
- ') : (',
- ' <Bar />',
- ')'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon on its own line, both expression parenthesized)
- code: [
- 'foo ? (',
- ' <Foo />',
- ')',
- ': (',
- ' <Bar />',
- ')'
- ].join('\n')
- }, {
- // Multiline ternary
- // (colon on its own line, both expression parenthesized)
- code: [
- 'foo ? (',
- ' <Foo />',
- ')',
- ':',
- '(',
- ' <Bar />',
- ')'
- ].join('\n')
- }, {
- // Multiline ternary
- // (first expression on test line, colon at the end of the first expression, parenthesized second expression)
- code: [
- 'foo ? <Foo /> : (',
- ' <Bar />',
- ')'
- ].join('\n')
- }, {
- // Multiline ternary
- // (first expression on test line, colon at the start of the second expression, parenthesized second expression)
- code: [
- 'foo ? <Foo />',
- ': (<Bar />)'
- ].join('\n')
- }, {
- // Multiline ternary
- // (first expression on test line, colon on its own line, parenthesized second expression)
- code: [
- 'foo ? <Foo />',
- ': (',
- ' <Bar />',
- ')'
- ].join('\n')
- }, {
- code: [
- '<span>',
- ' {condition ?',
- ' <Thing',
- ' foo={`bar`}',
- ' /> :',
- ' <Thing/>',
- ' }',
- '</span>'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- '<span>',
- ' {condition ?',
- ' <Thing',
- ' foo={"bar"}',
- ' /> :',
- ' <Thing/>',
- ' }',
- '</span>'
- ].join('\n'),
- options: [2]
- }, {
- code: [
- 'function foo() {',
- ' <span>',
- ' {condition ?',
- ' <Thing',
- ' foo={superFoo}',
- ' /> :',
- ' <Thing/>',
- ' }',
- ' </span>',
- '}'
- ].join('\n'),
- options: [2]
- }],
- invalid: [{
- code: [
- '<App>',
- ' <Foo />',
- '</App>'
- ].join('\n'),
- output: [
- '<App>',
- ' <Foo />',
- '</App>'
- ].join('\n'),
- errors: [{message: 'Expected indentation of 4 space characters but found 2.'}]
- }, {
- code: [
- '<App>',
- ' <Foo />',
- '</App>'
- ].join('\n'),
- output: [
- '<App>',
- ' <Foo />',
- '</App>'
- ].join('\n'),
- options: [2],
- errors: [{message: 'Expected indentation of 2 space characters but found 4.'}]
- }, {
- code: [
- '<App>',
- ' <Foo />',
- '</App>'
- ].join('\n'),
- output: [
- '<App>',
- '\t<Foo />',
- '</App>'
- ].join('\n'),
- options: ['tab'],
- errors: [{message: 'Expected indentation of 1 tab character but found 0.'}]
- }, {
- code: [
- 'function App() {',
- ' return <App>',
- ' <Foo />',
- ' </App>;',
- '}'
- ].join('\n'),
- output: [
- 'function App() {',
- ' return <App>',
- ' <Foo />',
- ' </App>;',
- '}'
- ].join('\n'),
- options: [2],
- errors: [{message: 'Expected indentation of 2 space characters but found 9.'}]
- }, {
- code: [
- 'function App() {',
- ' return (<App>',
- ' <Foo />',
- ' </App>);',
- '}'
- ].join('\n'),
- output: [
- 'function App() {',
- ' return (<App>',
- ' <Foo />',
- ' </App>);',
- '}'
- ].join('\n'),
- options: [2],
- errors: [{message: 'Expected indentation of 2 space characters but found 4.'}]
- }, {
- code: [
- 'function App() {',
- ' return (',
- '<App>',
- ' <Foo />',
- '</App>',
- ' );',
- '}'
- ].join('\n'),
- // The detection logic only thinks <App> is indented wrong, not the other
- // two lines following. I *think* because it incorrectly uses <App>'s indention
- // as the baseline for the next two, instead of the realizing the entire three
- // lines are wrong together. See #608
- /* output: [
- 'function App() {',
- ' return (',
- ' <App>',
- ' <Foo />',
- ' </App>',
- ' );',
- '}'
- ].join('\n'), */
- options: [2],
- errors: [{message: 'Expected indentation of 4 space characters but found 0.'}]
- }, {
- code: [
- '<App>',
- ' {test}',
- '</App>'
- ].join('\n'),
- output: [
- '<App>',
- ' {test}',
- '</App>'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 3.'}
- ]
- }, {
- code: [
- '<App>',
- ' {options.map((option, index) => (',
- ' <option key={index} value={option.key}>',
- ' {option.name}',
- ' </option>',
- ' ))}',
- '</App>'
- ].join('\n'),
- output: [
- '<App>',
- ' {options.map((option, index) => (',
- ' <option key={index} value={option.key}>',
- ' {option.name}',
- ' </option>',
- ' ))}',
- '</App>'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 12 space characters but found 11.'}
- ]
- }, {
- code: [
- '<App>',
- '{test}',
- '</App>'
- ].join('\n'),
- output: [
- '<App>',
- '\t{test}',
- '</App>'
- ].join('\n'),
- options: ['tab'],
- errors: [
- {message: 'Expected indentation of 1 tab character but found 0.'}
- ]
- }, {
- code: [
- '<App>',
- '\t{options.map((option, index) => (',
- '\t\t<option key={index} value={option.key}>',
- '\t\t{option.name}',
- '\t\t</option>',
- '\t))}',
- '</App>'
- ].join('\n'),
- output: [
- '<App>',
- '\t{options.map((option, index) => (',
- '\t\t<option key={index} value={option.key}>',
- '\t\t\t{option.name}',
- '\t\t</option>',
- '\t))}',
- '</App>'
- ].join('\n'),
- options: ['tab'],
- errors: [
- {message: 'Expected indentation of 3 tab characters but found 2.'}
- ]
- }, {
- code: [
- '<App>\n',
- '<Foo />\n',
- '</App>'
- ].join('\n'),
- output: [
- '<App>\n',
- '\t<Foo />\n',
- '</App>'
- ].join('\n'),
- options: ['tab'],
- errors: [
- {message: 'Expected indentation of 1 tab character but found 0.'}
- ]
- }, {
- code: [
- '[',
- ' <div />,',
- ' <div />',
- ']'
- ].join('\n'),
- output: [
- '[',
- ' <div />,',
- ' <div />',
- ']'
- ].join('\n'),
- options: [2],
- errors: [
- {message: 'Expected indentation of 2 space characters but found 4.'}
- ]
- }, {
- code: [
- '<App>\n',
- ' <Foo />\n',
- '</App>'
- ].join('\n'),
- output: [
- '<App>\n',
- '\t<Foo />\n',
- '</App>'
- ].join('\n'),
- options: ['tab'],
- errors: [
- {message: 'Expected indentation of 1 tab character but found 0.'}
- ]
- }, {
- code: [
- '<App>\n',
- '\t<Foo />\n',
- '</App>'
- ].join('\n'),
- output: [
- '<App>\n',
- ' <Foo />\n',
- '</App>'
- ].join('\n'),
- options: [2],
- errors: [
- {message: 'Expected indentation of 2 space characters but found 0.'}
- ]
- }, {
- code: [
- '<div>',
- ' {',
- ' [',
- ' <Foo />,',
- ' <Bar />',
- ' ]',
- ' }',
- '</div>'
- ].join('\n'),
- output: [
- '<div>',
- ' {',
- ' [',
- ' <Foo />,',
- ' <Bar />',
- ' ]',
- ' }',
- '</div>'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 12 space characters but found 8.'}
- ]
- }, {
- code: [
- '<div>',
- ' {foo &&',
- ' [',
- ' <Foo />,',
- ' <Bar />',
- ' ]',
- ' }',
- '</div>'
- ].join('\n'),
- output: [
- '<div>',
- ' {foo &&',
- ' [',
- ' <Foo />,',
- ' <Bar />',
- ' ]',
- ' }',
- '</div>'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 12 space characters but found 8.'}
- ]
- }, {
- // Multiline ternary
- // (colon at the end of the first expression)
- code: [
- 'foo ?',
- ' <Foo /> :',
- '<Bar />'
- ].join('\n'),
- output: [
- 'foo ?',
- ' <Foo /> :',
- ' <Bar />'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 0.'}
- ]
- }, {
- // Multiline ternary
- // (colon on its own line)
- code: [
- 'foo ?',
- ' <Foo />',
- ':',
- '<Bar />'
- ].join('\n'),
- output: [
- 'foo ?',
- ' <Foo />',
- ':',
- ' <Bar />'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 0.'}
- ]
- }, {
- // Multiline ternary
- // (first expression on test line, colon at the end of the first expression)
- code: [
- 'foo ? <Foo /> :',
- ' <Bar />'
- ].join('\n'),
- output: [
- 'foo ? <Foo /> :',
- '<Bar />'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 0 space characters but found 4.'}
- ]
- }, {
- // Multiline ternary
- // (first expression on test line, colon on its own line)
- code: [
- 'foo ? <Foo />',
- ':',
- ' <Bar />'
- ].join('\n'),
- output: [
- 'foo ? <Foo />',
- ':',
- '<Bar />'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 0 space characters but found 6.'}
- ]
- }, {
- // Multiline ternary
- // (colon at the end of the first expression, parenthesized first expression)
- code: [
- 'foo ? (',
- ' <Foo />',
- ') :',
- '<Bar />'
- ].join('\n'),
- output: [
- 'foo ? (',
- ' <Foo />',
- ') :',
- ' <Bar />'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 0.'}
- ]
- }, {
- // Multiline ternary
- // (colon on its own line, parenthesized first expression)
- code: [
- 'foo ? (',
- ' <Foo />',
- ')',
- ':',
- '<Bar />'
- ].join('\n'),
- output: [
- 'foo ? (',
- ' <Foo />',
- ')',
- ':',
- ' <Bar />'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 0.'}
- ]
- }, {
- // Multiline ternary
- // (colon at the end of the first expression, parenthesized second expression)
- code: [
- 'foo ?',
- ' <Foo /> : (',
- ' <Bar />',
- ' )'
- ].join('\n'),
- output: [
- 'foo ?',
- ' <Foo /> : (',
- ' <Bar />',
- ' )'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 8 space characters but found 4.'}
- ]
- }, {
- // Multiline ternary
- // (colon on its own line, parenthesized second expression)
- code: [
- 'foo ?',
- ' <Foo />',
- ': (',
- '<Bar />',
- ')'
- ].join('\n'),
- output: [
- 'foo ?',
- ' <Foo />',
- ': (',
- ' <Bar />',
- ')'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 0.'}
- ]
- }, {
- // Multiline ternary
- // (colon indented on its own line, parenthesized second expression)
- code: [
- 'foo ?',
- ' <Foo />',
- ' : (',
- ' <Bar />',
- ' )'
- ].join('\n'),
- output: [
- 'foo ?',
- ' <Foo />',
- ' : (',
- ' <Bar />',
- ' )'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 8 space characters but found 4.'}
- ]
- }, {
- // Multiline ternary
- // (colon at the end of the first expression, both expression parenthesized)
- code: [
- 'foo ? (',
- '<Foo />',
- ') : (',
- '<Bar />',
- ')'
- ].join('\n'),
- output: [
- 'foo ? (',
- ' <Foo />',
- ') : (',
- ' <Bar />',
- ')'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 0.'},
- {message: 'Expected indentation of 4 space characters but found 0.'}
- ]
- }, {
- // Multiline ternary
- // (colon on its own line, both expression parenthesized)
- code: [
- 'foo ? (',
- '<Foo />',
- ')',
- ': (',
- '<Bar />',
- ')'
- ].join('\n'),
- output: [
- 'foo ? (',
- ' <Foo />',
- ')',
- ': (',
- ' <Bar />',
- ')'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 0.'},
- {message: 'Expected indentation of 4 space characters but found 0.'}
- ]
- }, {
- // Multiline ternary
- // (colon on its own line, both expression parenthesized)
- code: [
- 'foo ? (',
- '<Foo />',
- ')',
- ':',
- '(',
- '<Bar />',
- ')'
- ].join('\n'),
- output: [
- 'foo ? (',
- ' <Foo />',
- ')',
- ':',
- '(',
- ' <Bar />',
- ')'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 0.'},
- {message: 'Expected indentation of 4 space characters but found 0.'}
- ]
- }, {
- // Multiline ternary
- // (first expression on test line, colon at the end of the first expression, parenthesized second expression)
- code: [
- 'foo ? <Foo /> : (',
- '<Bar />',
- ')'
- ].join('\n'),
- output: [
- 'foo ? <Foo /> : (',
- ' <Bar />',
- ')'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 0.'}
- ]
- }, {
- // Multiline ternary
- // (first expression on test line, colon on its own line, parenthesized second expression)
- code: [
- 'foo ? <Foo />',
- ': (',
- '<Bar />',
- ')'
- ].join('\n'),
- output: [
- 'foo ? <Foo />',
- ': (',
- ' <Bar />',
- ')'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 0.'}
- ]
- }, {
- code: [
- '<p>',
- ' <div>',
- ' <SelfClosingTag />Text',
- ' </div>',
- '</p>'
- ].join('\n'),
- errors: [
- {message: 'Expected indentation of 4 space characters but found 2.'}
- ]
- }]
- });
|