UNPKG

react-docgen-typescript

Version:

[![Build Status](https://github.com/styleguidist/react-docgen-typescript/actions/workflows/nodejs.yml/badge.svg)](https://github.com/styleguidist/react-docgen-typescript/actions/workflows/nodejs.yml)

1,133 lines 72.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var chai_1 = require("chai"); var fs = require("fs"); var path = require("path"); var ts = require("typescript"); var parser_1 = require("../parser"); var testUtils_1 = require("./testUtils"); describe('parser', function () { it('should parse simple react class component', function () { testUtils_1.check('Column', { Column: { prop1: { type: 'string', required: false }, prop2: { type: 'number' }, prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }); }); it('should parse simple react class component with console.log inside', function () { testUtils_1.check('ColumnWithLog', { Column: { prop1: { type: 'string', required: false }, prop2: { type: 'number' }, prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }); }); it('should parse simple react class component as default export', function () { testUtils_1.check('ColumnWithDefaultExport', { Column: { prop1: { type: 'string', required: false }, prop2: { type: 'number' }, prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }); }); it('should parse simple typescript definition file with default export', function () { testUtils_1.check('StatelessDisplayNameFolder/Stateless.d.ts', { Stateless: { foo: { description: '', type: 'string', required: false } } }, true, ''); }); describe('file path', function () { it('should return the correct filepath for a parsed component', function () { var results = parser_1.parse([testUtils_1.fixturePath('FilePathCheck')]); results.forEach(function (result) { chai_1.assert.equal(result.filePath, path.resolve('src/__tests__/data/FilePathCheck.tsx')); }); }); it('should return the correct filepath for multiple parsed components', function () { var results = parser_1.parse([ testUtils_1.fixturePath('FilePathCheck'), testUtils_1.fixturePath('Column'), testUtils_1.fixturePath('ColumnWithDefaultExportOnly') ]); var paths = [ path.resolve('src/__tests__/data/FilePathCheck.tsx'), path.resolve('src/__tests__/data/Column.tsx'), path.resolve('src/__tests__/data/ColumnWithDefaultExportOnly.tsx') ]; results.forEach(function (result, index) { chai_1.assert.equal(result.filePath, paths[index]); }); }); }); it('should parse mulitple files', function () { var result = parser_1.parse([ testUtils_1.fixturePath('Column'), testUtils_1.fixturePath('ColumnWithDefaultExportOnly') ]); testUtils_1.checkComponent(result, { Column: {}, ColumnWithDefaultExportOnly: {} }, false); }); it('should parse simple react class component as default export only', function () { testUtils_1.check('ColumnWithDefaultExportOnly', { ColumnWithDefaultExportOnly: { prop1: { type: 'string', required: false }, prop2: { type: 'number' }, prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }); }); it('should parse simple react class component as default anonymous export', function () { testUtils_1.check('ColumnWithDefaultAnonymousExportOnly', { ColumnWithDefaultAnonymousExportOnly: { prop1: { type: 'string', required: false }, prop2: { type: 'number' }, prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }); }); it('should parse simple react class component with state', function () { testUtils_1.check('AppMenu', { AppMenu: { menu: { type: 'any' } } }); }); it('should parse simple react class component with picked properties', function () { testUtils_1.check('ColumnWithPick', { Column: { prop1: { type: 'string', required: false }, prop2: { type: 'number' }, propx: { type: 'number' } } }); }); it('should parse component with props with external type', function () { testUtils_1.check('ColumnWithPropsWithExternalType', { ColumnWithPropsWithExternalType: { prop1: { type: 'string', required: false }, prop2: { type: 'number' }, prop3: { type: 'MyExternalType' } } }); }); it('should parse HOCs', function () { testUtils_1.check('ColumnHigherOrderComponent', { ColumnExternalHigherOrderComponent: { prop1: { type: 'string' } }, ColumnHigherOrderComponent1: { prop1: { type: 'string' } }, ColumnHigherOrderComponent2: { prop1: { type: 'string' } }, RowExternalHigherOrderComponent: { prop1: { type: 'string' } }, RowHigherOrderComponent1: { prop1: { type: 'string' } }, RowHigherOrderComponent2: { prop1: { type: 'string' } } }); }); it('should parse component with inherited properties HtmlAttributes<any>', function () { testUtils_1.check('ColumnWithHtmlAttributes', { Column: { // tslint:disable:object-literal-sort-keys prop1: { type: 'string', required: false }, prop2: { type: 'number' }, // HtmlAttributes defaultChecked: { type: 'boolean', required: false, description: '' } // ... // tslint:enable:object-literal-sort-keys } }, false); }); it('should parse component without exported props interface', function () { testUtils_1.check('ColumnWithoutExportedProps', { Column: { prop1: { type: 'string', required: false }, prop2: { type: 'number' } } }); }); it('should parse functional component exported as const', function () { testUtils_1.check('ConstExport', { Row: { prop1: { type: 'string', required: false }, prop2: { type: 'number' } }, // TODO: this wasn't there before, i would guess that that's correct test: {} }, false); }); it('should parse react component with properties defined in external file', function () { testUtils_1.check('ExternalPropsComponent', { ExternalPropsComponent: { prop1: { type: 'string' } } }); }); it('should parse static sub components', function () { testUtils_1.check('StatelessStaticComponents', { StatelessStaticComponents: { myProp: { type: 'string' } }, 'StatelessStaticComponents.Label': { title: { type: 'string' } } }); }); it('should parse static exported components variation1', function () { testUtils_1.check('StatelessStaticComponentsExportVariation1', { StatelessStaticComponents: { myProp: { type: 'string' } }, 'StatelessStaticComponents.Label': { title: { type: 'string' } } }); }); it('should parse static exported components variation2', function () { testUtils_1.check('StatelessStaticComponentsExportVariation2', { StatelessStaticComponents: { myProp: { type: 'string' } }, 'StatelessStaticComponents.Label': { title: { type: 'string' } } }); }); it('should parse static sub components exported from named object', function () { testUtils_1.check('StatelessStaticComponentsNamedObjectExport', { StatelessStaticComponents: { myProp: { type: 'string' } }, SubComponent: { title: { type: 'string' } } }, true, ''); }); it('should parse static sub components exported from named object with keys', function () { testUtils_1.check('StatelessStaticComponentsNamedObjectExportAsKeys', { StatelessStaticComponents: { myProp: { type: 'string' } }, SubComponent: { title: { type: 'string' } } }); }); it('should parse static sub components on class components', function () { testUtils_1.check('ColumnWithStaticComponents', { Column: { prop1: { type: 'string' } }, 'Column.Label': { title: { type: 'string' } }, 'Column.SubLabel': {} }); }); it('should parse react component with properties extended from an external .tsx file', function () { testUtils_1.check('ExtendsExternalPropsComponent', { ExtendsExternalPropsComponent: { prop1: { type: 'number', required: false, description: 'prop1' }, prop2: { type: 'string', required: false, description: 'prop2' } } }); }); it('should parse react component with properties defined as type', function () { testUtils_1.check('FlippableImage', { FlippableImage: { isFlippedX: { type: 'boolean', required: false }, isFlippedY: { type: 'boolean', required: false } } }, false); }); it('should parse react component with const definitions', function () { testUtils_1.check('InlineConst', { MyComponent: { foo: { type: 'any' } } }); }); it('should parse default interface export', function () { testUtils_1.check('ExportsDefaultInterface', { Component: { foo: { type: 'any' } } }); }); it('should parse react component that exports a prop type const', function () { testUtils_1.check('ExportsPropTypeShape', { ExportsPropTypes: { foo: { type: 'any' } } }); }); it('should parse react component that exports a prop type thats imported', function () { testUtils_1.check('ExportsPropTypeImport', { ExportsPropTypes: { foo: { type: 'any' } } }); }); // see issue #132 (https://github.com/styleguidist/react-docgen-typescript/issues/132) it('should determine the parent fileName relative to the project directory', function () { testUtils_1.check('ExportsPropTypeImport', { ExportsPropTypes: { foo: { parent: { fileName: 'react-docgen-typescript/src/__tests__/data/ExportsPropTypeImport.tsx', name: 'ExportsPropTypesProps' }, type: 'any' } } }, true); }); describe('component with default props', function () { var expectation = { ComponentWithDefaultProps: { sampleDefaultFromJSDoc: { defaultValue: 'hello', description: 'sample with default value', required: true, type: '"hello" | "goodbye"' }, sampleFalse: { defaultValue: false, required: false, type: 'boolean' }, sampleNull: { type: 'null', required: false, defaultValue: null }, sampleNumber: { type: 'number', required: false, defaultValue: -1 }, sampleObject: { defaultValue: "{ a: '1', b: 2, c: true, d: false, e: undefined, f: null, g: { a: '1' } }", required: false, type: '{ [key: string]: any; }' }, sampleString: { defaultValue: 'hello', required: false, type: 'string' }, sampleTrue: { type: 'boolean', required: false, defaultValue: true }, sampleUndefined: { defaultValue: 'undefined', required: false, type: 'any' } } }; it('should parse defined props', function () { testUtils_1.check('ComponentWithDefaultProps', expectation); }); it('should parse referenced props', function () { testUtils_1.check('ComponentWithReferencedDefaultProps', expectation); }); }); describe('component with @type jsdoc tag', function () { var expectation = { ComponentWithTypeJsDocTag: { sampleTypeFromJSDoc: { description: 'sample with custom type', required: true, type: 'string' } } }; it('should parse defined props', function () { testUtils_1.check('ComponentWithTypeJsDocTag', expectation); }); }); it('should parse react PureComponent', function () { testUtils_1.check('PureRow', { Row: { prop1: { type: 'string', required: false }, prop2: { type: 'number' } } }); }); it('should parse react PureComponent - regression test', function () { testUtils_1.check('Regression_v0_0_12', { Zoomable: { originX: { type: 'number' }, originY: { type: 'number' }, scaleFactor: { type: 'number' } } }, false); }); it('should parse react functional component', function () { testUtils_1.check('Row', { Row: { prop1: { type: 'string', required: false }, prop2: { type: 'number' } } }); }); it('should parse react stateless component', function () { testUtils_1.check('Stateless', { Stateless: { myProp: { type: 'string' } } }); }); it('should get name for default export', function () { testUtils_1.check('ForwardRefDefaultExport', { ForwardRefDefaultExport: { myProp: { type: 'string' } } }, false); }); it('should get name for default export 2', function () { testUtils_1.check('ForwardRefDefaultExportAtExport', { ForwardRefDefaultExport: { myProp: { type: 'string' } } }, false); }); it('should component where last line is a comment', function () { testUtils_1.check('ExportObject', { Baz: { baz: { description: '', type: 'string' } }, Bar: { foo: { description: '', type: 'string' } }, FooBar: { foobar: { description: '', type: 'string' } } }); }); it('should parse react stateless component with intersection props', function () { testUtils_1.check('StatelessIntersectionProps', { StatelessIntersectionProps: { moreProp: { type: 'number' }, myProp: { type: 'string' } } }); }); it('should parse react stateless component default props when declared as a normal function', function () { testUtils_1.check('FunctionDeclarationDefaultProps', { FunctionDeclarationDefaultProps: { id: { defaultValue: 1, description: '', required: false, type: 'number' } } }); }); it('should parse react stateless component default props when declared as a normal function inside forwardRef', function () { testUtils_1.check('ForwardRefDefaultValues', { ForwardRefDefaultValues: { myProp: { defaultValue: "I'm default", description: 'myProp description', type: 'string', required: false } } }, false, 'ForwardRefDefaultValues description'); }); it('should parse react stateless component with external intersection props', function () { testUtils_1.check('StatelessIntersectionExternalProps', { StatelessIntersectionExternalProps: { myProp: { type: 'string' }, prop1: { type: 'string', required: false } } }); }); it('should parse react stateless component with generic intersection props', function () { testUtils_1.check('StatelessIntersectionGenericProps', { StatelessIntersectionGenericProps: { myProp: { type: 'string' } } }); }); it('should parse react stateless component with intersection + union props', function () { testUtils_1.check('SimpleUnionIntersection', { SimpleUnionIntersection: { bar: { type: 'string', description: '' }, baz: { type: 'string', description: '' }, foo: { type: 'string', description: '' } } }); }); it('should parse react stateless component with intersection + union overlap props', function () { testUtils_1.check('SimpleDiscriminatedUnionIntersection', { SimpleDiscriminatedUnionIntersection: { bar: { type: '"one" | "other"', description: '' }, baz: { type: 'number', description: '' }, foo: { type: 'string', description: '' }, test: { type: 'number', description: '' } } }); }); it('should parse react stateless component with generic intersection + union overlap props - simple', function () { testUtils_1.check('SimpleGenericUnionIntersection', { SimpleGenericUnionIntersection: { as: { type: 'unknown', description: '' }, foo: { description: 'The foo prop should not repeat the description', required: false, type: '"red" | "blue"' }, gap: { description: 'The space between children\nYou cannot use gap when using a "space" justify property', required: false, type: 'number' }, hasWrap: { type: 'boolean', description: '', required: false } } }); }); it('should parse react stateless component with generic intersection + union overlap props', function () { testUtils_1.check('ComplexGenericUnionIntersection', { ComplexGenericUnionIntersection: { as: { type: 'ElementType<any>', required: false, description: 'Render the component as another component' }, align: { description: 'The flex "align" property', required: false, type: '"stretch" | "center" | "flex-start" | "flex-end"' }, justify: { description: "Use flex 'center' | 'flex-start' | 'flex-end' | 'stretch' with\na gap between each child.\nUse flex 'space-between' | 'space-around' | 'space-evenly' and\nflex will space the children.", required: false, type: '"stretch" | "center" | "flex-start" | "flex-end" | "space-between" | "space-around" | "space-evenly"' }, gap: { description: 'The space between children\nYou cannot use gap when using a "space" justify property', required: false, type: 'string | number' } } }); }); it('should parse react stateless component with generic intersection + union + omit overlap props', function () { testUtils_1.check('ComplexGenericUnionIntersectionWithOmit', { ComplexGenericUnionIntersectionWithOmit: { as: { type: 'ElementType<any>', required: false, description: 'Render the component as another component' }, align: { description: 'The flex "align" property', required: false, type: '"center" | "flex-start" | "flex-end" | "stretch"' }, justify: { description: "Use flex 'center' | 'flex-start' | 'flex-end' | 'stretch' with\na gap between each child.\nUse flex 'space-between' | 'space-around' | 'space-evenly' and\nflex will space the children.", required: false, type: '"center" | "flex-start" | "flex-end" | "stretch" | "space-between" | "space-around" | "space-evenly"' }, gap: { description: 'The space between children\nYou cannot use gap when using a "space" justify property', required: false, type: 'string | number' } } }); }); it('should parse react stateful component with intersection props', function () { testUtils_1.check('StatefulIntersectionProps', { StatefulIntersectionProps: { moreProp: { type: 'number' }, myProp: { type: 'string' } } }); }); it('should parse react stateful component with external intersection props', function () { testUtils_1.check('StatefulIntersectionExternalProps', { StatefulIntersectionExternalProps: { myProp: { type: 'string' }, prop1: { type: 'string', required: false } } }); }); it('should parse react stateful component (wrapped in HOC) with intersection props', function () { testUtils_1.check('HOCIntersectionProps', { HOCIntersectionProps: { injected: { type: 'boolean' }, myProp: { type: 'string' } } }); }); describe('stateless component with default props', function () { var expectation = { StatelessWithDefaultProps: { sampleDefaultFromJSDoc: { defaultValue: 'hello', description: 'sample with default value', required: true, type: '"hello" | "goodbye"' }, sampleEnum: { defaultValue: 'enumSample.HELLO', required: false, type: 'enumSample' }, sampleFalse: { defaultValue: false, required: false, type: 'boolean' }, sampleNull: { type: 'null', required: false, defaultValue: null }, sampleNumber: { type: 'number', required: false, defaultValue: -1 }, sampleObject: { defaultValue: "{ a: '1', b: 2, c: true, d: false, e: undefined, f: null, g: { a: '1' } }", required: false, type: '{ [key: string]: any; }' }, sampleString: { defaultValue: 'hello', required: false, type: 'string' }, sampleTrue: { type: 'boolean', required: false, defaultValue: true }, sampleUndefined: { defaultValue: undefined, required: false, type: 'any' }, sampleRenamed: { defaultValue: 'world', required: false, type: 'string' } } }; it('should parse defined props', function () { testUtils_1.check('StatelessWithDefaultProps', expectation); }); it('should parse props with shorthands', function () { testUtils_1.check('StatelessShorthandDefaultProps', { StatelessShorthandDefaultProps: { onCallback: { defaultValue: null, description: 'onCallback description', required: false, type: '() => void' }, regularProp: { defaultValue: 'foo', description: 'regularProp description', required: false, type: 'string' }, shorthandProp: { defaultValue: 123, description: 'shorthandProp description', required: false, type: 'number' } } }); }); it('supports destructuring', function () { testUtils_1.check('StatelessWithDestructuredProps', expectation); }); it('supports destructuring for arrow functions', function () { testUtils_1.check('StatelessWithDestructuredPropsArrow', expectation); }); it('supports typescript 3.0 style defaulted props', function () { testUtils_1.check('StatelessWithDefaultPropsTypescript3', expectation); }); }); it('should parse components with unioned types', function () { testUtils_1.check('OnlyDefaultExportUnion', { OnlyDefaultExportUnion: { content: { description: 'The content', type: 'string' } } }); }); it('should parse components with unioned types when re-exported as named export', function () { testUtils_1.check('OnlyDefaultExportUnionAsExport', { OnlyDefaultExportUnion: { content: { description: 'The content', type: 'string' } } }, true, 'OnlyDefaultExportUnion description'); }); it('should parse jsdocs with the @default tag and no description', function () { testUtils_1.check('StatelessWithDefaultOnlyJsDoc', { StatelessWithDefaultOnlyJsDoc: { myProp: { defaultValue: 'hello', description: '', type: 'string' } } }); }); it('should parse functional component component defined as function', function () { testUtils_1.check('FunctionDeclaration', { Jumbotron: { prop1: { type: 'string', required: true } } }); }); it('should parse functional component component defined as const', function () { testUtils_1.check('FunctionalComponentAsConst', { Jumbotron: { prop1: { type: 'string', required: true } } }); }); it('should parse functional component declared as React.FC with default import from react', function () { testUtils_1.check('FunctionalComponentWithDefaultImportReact', { Jumbotron: { prop1: { type: 'string', required: true } } }); }); it('should parse functional component defined as const with default value assignments in immediately destructured props', function () { testUtils_1.check('FunctionalComponentWithDesctructuredProps', { FunctionalComponentWithDesctructuredProps: { prop1: { type: 'Property1Type', required: false, defaultValue: 'hello' }, prop2: { type: '"goodbye" | "farewell"', required: false, defaultValue: 'goodbye' }, prop3: { type: 'number', required: false, defaultValue: 10 }, prop4: { type: 'string', required: false, defaultValue: 'this is a string' }, prop5: { type: 'boolean', required: false, defaultValue: true } } }); }); it('should parse functional component defined as const with default value (imported from a separate file) assignments in immediately destructured props', function () { testUtils_1.check('FunctionalComponentWithDesctructuredPropsAndImportedConstants', { FunctionalComponentWithDesctructuredPropsAndImportedConstants: { prop1: { type: 'Property1Type', required: false, defaultValue: 'hello' }, prop2: { type: '"goodbye" | "farewell"', required: false, defaultValue: 'goodbye' }, prop3: { type: 'number', required: false, defaultValue: 10 }, prop4: { type: 'string', required: false, defaultValue: 'this is a string' }, prop5: { type: 'boolean', required: false, defaultValue: true } } }); }); it('should parse functional component component defined as const', function () { testUtils_1.check('FunctionDeclarationVisibleName', { 'Awesome Jumbotron': { prop1: { type: 'string', required: true } } }); }); it('should parse React.SFC component defined as const', function () { testUtils_1.check('ReactSFCAsConst', { Jumbotron: { prop1: { type: 'string', required: true } } }); }); it('should parse functional component component defined as function as default export', function () { testUtils_1.check('FunctionDeclarationAsDefaultExport', { Jumbotron: { prop1: { type: 'string', required: true } } }); }); it('should parse functional component component thats been wrapped in React.memo', function () { testUtils_1.check('FunctionDeclarationAsDefaultExportWithMemo', { Jumbotron: { prop1: { type: 'string', required: true } } }); }); it('should parse functional component component defined as const thats been wrapped in React.memo', function () { testUtils_1.check('FunctionDeclarationAsConstAsDefaultExportWithMemo', { // in this case the component name is taken from the file name FunctionDeclarationAsConstAsDefaultExportWithMemo: { prop1: { type: 'string', required: true } } }, true, 'Jumbotron description'); }); it('should parse JSDoc correctly', function () { testUtils_1.check('JSDocWithParam', { JSDocWithParam: { prop1: { type: 'string', required: true } } }, true, 'JSDocWithParamProps description\n\nNOTE: If a parent element of this control is `overflow: hidden` then the\nballoon may not show up.'); }); it('should parse functional component component defined as const as default export', function () { testUtils_1.check('FunctionalComponentAsConstAsDefaultExport', { // in this case the component name is taken from the file name FunctionalComponentAsConstAsDefaultExport: { prop1: { type: 'string', required: true } } }, true, 'Jumbotron description'); }); it('should parse React.SFC component defined as const as default export', function () { testUtils_1.check('ReactSFCAsConstAsDefaultExport', { // in this case the component name is taken from the file name ReactSFCAsConstAsDefaultExport: { prop1: { type: 'string', required: true } } }, true, 'Jumbotron description'); }); it('should parse functional component component defined as const as named export', function () { testUtils_1.check('FunctionalComponentAsConstAsNamedExport', { // in this case the component name is taken from the file name Jumbotron: { prop1: { type: 'string', required: true } } }, true, 'Jumbotron description'); }); it('should parse React.SFC component defined as const as named export', function () { testUtils_1.check('ReactSFCAsConstAsNamedExport', { // in this case the component name is taken from the file name Jumbotron: { prop1: { type: 'string', required: true } } }, true, 'Jumbotron description'); }); describe('displayName', function () { it('should be taken from stateless component `displayName` property (using named export)', function () { var parsed = parser_1.parse(testUtils_1.fixturePath('StatelessDisplayName'))[0]; chai_1.assert.equal(parsed.displayName, 'StatelessDisplayName'); }); it('should be taken from stateful component `displayName` property (using named export)', function () { var parsed = parser_1.parse(testUtils_1.fixturePath('StatefulDisplayName'))[0]; chai_1.assert.equal(parsed.displayName, 'StatefulDisplayName'); }); it('should be taken from stateless component `displayName` property (using default export)', function () { var parsed = parser_1.parse(testUtils_1.fixturePath('StatelessDisplayNameDefaultExport'))[0]; chai_1.assert.equal(parsed.displayName, 'StatelessDisplayNameDefaultExport'); }); it("should be taken from stateless component `displayName` property (using default export) even if file name doesn't match", function () { var parsed = parser_1.parse(testUtils_1.fixturePath('StatelessDisplayNameDefaultExportDifferentFilename'))[0]; chai_1.assert.equal(parsed.displayName, 'ThisNameIsNotTheSameAsThisFilename'); }); it('should be taken from stateful component `displayName` property (using default export)', function () { var parsed = parser_1.parse(testUtils_1.fixturePath('StatefulDisplayNameDefaultExport'))[0]; chai_1.assert.equal(parsed.displayName, 'StatefulDisplayNameDefaultExport'); }); it('should be taken from named export when default export is an HOC', function () { var parsed = parser_1.parse(testUtils_1.fixturePath('StatelessDisplayNameHOC'))[0]; chai_1.assert.equal(parsed.displayName, 'StatelessDisplayName'); }); it('should be taken from named export when default export is an HOC', function () { var parsed = parser_1.parse(testUtils_1.fixturePath('StatefulDisplayNameHOC'))[0]; chai_1.assert.equal(parsed.displayName, 'StatefulDisplayName'); }); it('should be taken from stateless component folder name if file name is "index"', function () { var parsed = parser_1.parse(testUtils_1.fixturePath('StatelessDisplayNameFolder/index'))[0]; chai_1.assert.equal(parsed.displayName, 'StatelessDisplayNameFolder'); }); it('should be taken from stateful component folder name if file name is "index"', function () { var parsed = parser_1.parse(testUtils_1.fixturePath('StatefulDisplayNameFolder/index'))[0]; chai_1.assert.equal(parsed.displayName, 'StatefulDisplayNameFolder'); }); describe('multiple components in one', function () { it('should parse all `displayName` properties correctly when all are explicitly defined.', function () { var result = parser_1.parse(testUtils_1.fixturePath('MultipleAllWithDisplayName')); // Ensure we're not missing any exports. chai_1.assert.equal(result.length, 3); var parsed1 = result[0], parsed2 = result[1], parsed3 = result[2]; chai_1.assert.equal(parsed1.displayName, 'First'); chai_1.assert.equal(parsed2.displayName, 'Second'); chai_1.assert.equal(parsed3.displayName, 'Third'); }); it('should parse all `displayName` properties correctly when some are explicitly defined.', function () { var result = parser_1.parse(testUtils_1.fixturePath('MultipleSomeWithDisplayName')); // Ensure we're not missing any exports. chai_1.assert.equal(result.length, 4); var parsed1 = result[0], parsed2 = result[1], parsed3 = result[2], parsed4 = result[3]; chai_1.assert.equal(parsed1.displayName, 'First'); chai_1.assert.equal(parsed2.displayName, 'NoExplicitDisplayName1'); chai_1.assert.equal(parsed3.displayName, 'Second'); chai_1.assert.equal(parsed4.displayName, 'NoExplicitDisplayName2'); }); it('should parse all `displayName` properties correctly when none are explicitly defined.', function () { var result = parser_1.parse(testUtils_1.fixturePath('MultipleWithNoExplicitDisplayName')); // Ensure we're not missing any exports. chai_1.assert.equal(result.length, 3); var parsed1 = result[0], parsed2 = result[1], parsed3 = result[2]; chai_1.assert.equal(parsed1.displayName, 'Button'); chai_1.assert.equal(parsed2.displayName, 'SubmitButton'); chai_1.assert.equal(parsed3.displayName, 'ResetButton'); }); }); }); describe('Parser options', function () { describe('Property filtering', function () { describe('children', function () { it('should ignore property "children" if not explicitly documented', function () { testUtils_1.check('Column', { Column: { prop1: { type: 'string', required: false }, prop2: { type: 'number' }, prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }, true); }); it('should not ignore any property that is documented explicitly', function () { testUtils_1.check('ColumnWithAnnotatedChildren', { Column: { children: { description: 'children description', required: false, type: 'ReactNode' }, prop1: { type: 'string', required: false }, prop2: { type: 'number' }, prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }, true); }); }); describe('propsFilter method', function () { it('should apply filter function and filter components accordingly', function () { var propFilter = function (prop, component) { return prop.name !== 'prop1'; }; testUtils_1.check('Column', { Column: { prop2: { type: 'number' }, prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }, true, undefined, { propFilter: propFilter }); }); it('should apply filter function and filter components accordingly', function () { var propFilter = function (prop, component) { if (component.name === 'Column') { return prop.name !== 'prop1'; } return true; }; testUtils_1.check('Column', { Column: { prop2: { type: 'number' }, prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }, true, undefined, { propFilter: propFilter }); testUtils_1.check('AppMenu', { AppMenu: { menu: { type: 'any' } } }, true, undefined, { propFilter: propFilter }); }); it('should allow filtering by parent interface', function () { var propFilter = function (prop, component) { if (prop.parent == null) { return true; } return (prop.parent.fileName.indexOf('@types/react') < 0 && prop.parent.name !== 'HTMLAttributes'); }; testUtils_1.check('ColumnWithHtmlAttributes', { Column: { prop1: { type: 'string', required: false }, prop2: { type: 'number' } } }, true, undefined, { propFilter: propFilter }); }); }); it('should collect all `onClick prop` parent declarations', function (done) { chai_1.assert.doesNotThrow(function () { parser_1.withDefaultConfig({ propFilter: function (prop) { if (prop.name === 'onClick') { chai_1.assert.deepEqual(prop.declarations, [ { fileName: 'react-docgen-typescript/node_modules/@types/react/index.d.ts', name: 'DOMAttributes' }, { fileName: 'react-docgen-typescript/src/__tests__/data/ButtonWithOnClickComponent.tsx', name: 'TypeLiteral' } ]); done(); } return true; } }).parse(testUtils_1.fixturePath('ButtonWithOnClickComponent')); }); }); it('should allow filtering by parent declarations', function () { var propFilter = function (prop) { if (prop.declarations !== undefined && prop.declarations.length > 0) { var hasPropAdditionalDescription = prop.declarations.find(function (declaration) { return !declaration.fileName.includes('@types/react'); }); return Boolean(hasPropAdditionalDescription); } return true; }; testUtils_1.check('ButtonWithOnClickComponent', { ButtonWithOnClickComponent: { onClick: { type: 'MouseEventHandler<HTMLButtonElement>', required: false, description: 'onClick event handler' } } }, true, '', { propFilter: propFilter }); }); describe('skipPropsWithName', function () { it('should skip a single property in skipPropsWithName', function () { var propFilter = { skipPropsWithName: 'prop1' }; testUtils_1.check('Column', { Column: { prop2: { type: 'number' }, prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }, true, undefined, { propFilter: propFilter }); }); it('should skip multiple properties in skipPropsWithName', function () { var propFilter = { skipPropsWithName: ['prop1', 'prop2'] }; testUtils_1.check('Column', { Column: { prop3: { type: '() => void' }, prop4: { type: '"option1" | "option2" | "option3"' } } }, true, undefined, { propFilter: propFilter }); }); }); describe('skipPropsWithoutDoc', function () { it('should skip a properties without documentation', function () { var propFilter = { skipPropsWithoutDoc: false }; testUtils_1.check('ColumnWithUndocumentedProps', { Column: { prop1: { type: 'string', required: false }, prop2: { type: 'number' } } }, true, undefined, { propFilter: propFilter }); }); }); }); it('should defaultProps in variable', function () { testUtils_1.check('SeparateDefaultProps', { SeparateDefaultProps: { disabled: { description: '', required: false, defaultValue: false, type: 'boolean' }, id: { description: '', required: false, defaultValue: 123, type: 'number' } } }); }); it('should defaultProps accessed variable', function () { testUtils_1.check('SeparateDefaultPropsIndividual', { SeparateDefaultPropsIndividual: { disabled: { description: '', required: false, defaultValue: false, type: 'boolean' }, id: { description: '', required: false, defaultValue: 123, type: 'number' } } }); }); describe('Extracting literal values from enums', function () { it('extracts literal values from enum', function () { testUtils_1.check('ExtractLiteralValuesFromEnum', { ExtractLiteralValuesFromEnum: { sampleBoolean: { type: 'boolean' }, sampleEnum: { raw: 'sampleEnum', type: 'enum', value: [ { value: '"one"', description: '', fullComment: '', tags: {} }, { value: '"two"', description: '', fullComment: '', tags: {} }, { value: '"three"', description: '', fullComment: '', tags: {} } ] }, sampleString: { type: 'string' } } }, true, null, { shouldExtractLiteralValuesFromEnum: