react-docgen-typescript
Version:
[](https://github.com/styleguidist/react-docgen-typescript/actions/workflows/nodejs.yml)
1,132 lines • 65.1 kB
JavaScript
"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 () {
(0, 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 () {
(0, 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 () {
(0, testUtils_1.check)('ColumnWithDefaultExport', {
Column: {
prop1: { type: 'string', required: false },
prop2: { type: 'number' },
prop3: { type: '() => void' },
prop4: { type: '"option1" | "option2" | "option3"' }
}
});
});
describe('file path', function () {
it('should return the correct filepath for a parsed component', function () {
var results = (0, parser_1.parse)([(0, 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 = (0, parser_1.parse)([
(0, testUtils_1.fixturePath)('FilePathCheck'),
(0, testUtils_1.fixturePath)('Column'),
(0, 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 = (0, parser_1.parse)([
(0, testUtils_1.fixturePath)('Column'),
(0, testUtils_1.fixturePath)('ColumnWithDefaultExportOnly')
]);
(0, testUtils_1.checkComponent)(result, {
Column: {},
ColumnWithDefaultExportOnly: {}
}, false);
});
it('should parse simple react class component as default export only', function () {
(0, 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 () {
(0, 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 () {
(0, testUtils_1.check)('AppMenu', {
AppMenu: {
menu: { type: 'any' }
}
});
});
it('should parse simple react class component with picked properties', function () {
(0, 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 () {
(0, testUtils_1.check)('ColumnWithPropsWithExternalType', {
ColumnWithPropsWithExternalType: {
prop1: { type: 'string', required: false },
prop2: { type: 'number' },
prop3: { type: 'MyExternalType' }
}
});
});
it('should parse HOCs', function () {
(0, 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 () {
(0, 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 () {
(0, testUtils_1.check)('ColumnWithoutExportedProps', {
Column: {
prop1: { type: 'string', required: false },
prop2: { type: 'number' }
}
});
});
it('should parse functional component exported as const', function () {
(0, 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 () {
(0, testUtils_1.check)('ExternalPropsComponent', {
ExternalPropsComponent: {
prop1: { type: 'string' }
}
});
});
it('should parse static sub components', function () {
(0, testUtils_1.check)('StatelessStaticComponents', {
StatelessStaticComponents: {
myProp: { type: 'string' }
},
'StatelessStaticComponents.Label': {
title: { type: 'string' }
}
});
});
it('should parse static sub components on class components', function () {
(0, 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 () {
(0, 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 () {
(0, 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 () {
(0, testUtils_1.check)('InlineConst', {
MyComponent: {
foo: { type: 'any' }
}
});
});
it('should parse default interface export', function () {
(0, testUtils_1.check)('ExportsDefaultInterface', {
Component: {
foo: { type: 'any' }
}
});
});
it('should parse react component that exports a prop type const', function () {
(0, testUtils_1.check)('ExportsPropTypeShape', {
ExportsPropTypes: {
foo: { type: 'any' }
}
});
});
it('should parse react component that exports a prop type thats imported', function () {
(0, 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 () {
(0, 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 () {
(0, testUtils_1.check)('ComponentWithDefaultProps', expectation);
});
it('should parse referenced props', function () {
(0, 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 () {
(0, testUtils_1.check)('ComponentWithTypeJsDocTag', expectation);
});
});
it('should parse react PureComponent', function () {
(0, testUtils_1.check)('PureRow', {
Row: {
prop1: { type: 'string', required: false },
prop2: { type: 'number' }
}
});
});
it('should parse react PureComponent - regression test', function () {
(0, 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 () {
(0, testUtils_1.check)('Row', {
Row: {
prop1: { type: 'string', required: false },
prop2: { type: 'number' }
}
});
});
it('should parse react stateless component', function () {
(0, testUtils_1.check)('Stateless', {
Stateless: {
myProp: { type: 'string' }
}
});
});
it('should get name for default export', function () {
(0, testUtils_1.check)('ForwardRefDefaultExport', {
ForwardRefDefaultExport: {
myProp: { type: 'string' }
}
}, false);
});
it('should get name for default export 2', function () {
(0, testUtils_1.check)('ForwardRefDefaultExportAtExport', {
ForwardRefDefaultExport: {
myProp: { type: 'string' }
}
}, false);
});
it('should component where last line is a comment', function () {
(0, 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 () {
(0, 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 () {
(0, 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 () {
(0, 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 () {
(0, testUtils_1.check)('StatelessIntersectionExternalProps', {
StatelessIntersectionExternalProps: {
myProp: { type: 'string' },
prop1: { type: 'string', required: false }
}
});
});
it('should parse react stateless component with generic intersection props', function () {
(0, testUtils_1.check)('StatelessIntersectionGenericProps', {
StatelessIntersectionGenericProps: {
myProp: { type: 'string' }
}
});
});
it('should parse react stateless component with intersection + union props', function () {
(0, 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 () {
(0, 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 () {
(0, 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 () {
(0, 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 () {
(0, 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 () {
(0, testUtils_1.check)('StatefulIntersectionProps', {
StatefulIntersectionProps: {
moreProp: { type: 'number' },
myProp: { type: 'string' }
}
});
});
it('should parse react stateful component with external intersection props', function () {
(0, 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 () {
(0, 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'
}
}
};
it('should parse defined props', function () {
(0, testUtils_1.check)('StatelessWithDefaultProps', expectation);
});
it('should parse props with shorthands', function () {
(0, 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 () {
(0, testUtils_1.check)('StatelessWithDestructuredProps', expectation);
});
it('supports destructuring for arrow functions', function () {
(0, testUtils_1.check)('StatelessWithDestructuredPropsArrow', expectation);
});
it('supports typescript 3.0 style defaulted props', function () {
(0, testUtils_1.check)('StatelessWithDefaultPropsTypescript3', expectation);
});
});
it('should parse components with unioned types', function () {
(0, 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 () {
(0, 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 () {
(0, testUtils_1.check)('StatelessWithDefaultOnlyJsDoc', {
StatelessWithDefaultOnlyJsDoc: {
myProp: { defaultValue: 'hello', description: '', type: 'string' }
}
});
});
it('should parse functional component component defined as function', function () {
(0, testUtils_1.check)('FunctionDeclaration', {
Jumbotron: {
prop1: { type: 'string', required: true }
}
});
});
it('should parse functional component component defined as const', function () {
(0, testUtils_1.check)('FunctionalComponentAsConst', {
Jumbotron: {
prop1: { type: 'string', required: true }
}
});
});
it('should parse functional component defined as const with default value assignments in immediately destructured props', function () {
(0, 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 () {
(0, 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 () {
(0, testUtils_1.check)('FunctionDeclarationVisibleName', {
'Awesome Jumbotron': {
prop1: { type: 'string', required: true }
}
});
});
it('should parse React.SFC component defined as const', function () {
(0, testUtils_1.check)('ReactSFCAsConst', {
Jumbotron: {
prop1: { type: 'string', required: true }
}
});
});
it('should parse functional component component defined as function as default export', function () {
(0, testUtils_1.check)('FunctionDeclarationAsDefaultExport', {
Jumbotron: {
prop1: { type: 'string', required: true }
}
});
});
it('should parse functional component component thats been wrapped in React.memo', function () {
(0, testUtils_1.check)('FunctionDeclarationAsDefaultExportWithMemo', {
Jumbotron: {
prop1: { type: 'string', required: true }
}
});
});
it('should parse JSDoc correctly', function () {
(0, 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 () {
(0, 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 () {
(0, 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 () {
(0, 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 () {
(0, 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 = (0, parser_1.parse)((0, 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 = (0, parser_1.parse)((0, 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 = (0, parser_1.parse)((0, 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 = (0, parser_1.parse)((0, 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 = (0, parser_1.parse)((0, 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 = (0, parser_1.parse)((0, 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 = (0, parser_1.parse)((0, 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 = (0, parser_1.parse)((0, 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 = (0, parser_1.parse)((0, testUtils_1.fixturePath)('StatefulDisplayNameFolder/index'))[0];
chai_1.assert.equal(parsed.displayName, 'StatefulDisplayNameFolder');
});
});
describe('Parser options', function () {
describe('Property filtering', function () {
describe('children', function () {
it('should ignore property "children" if not explicitly documented', function () {
(0, 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 () {
(0, 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';
};
(0, 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;
};
(0, testUtils_1.check)('Column', {
Column: {
prop2: { type: 'number' },
prop3: { type: '() => void' },
prop4: { type: '"option1" | "option2" | "option3"' }
}
}, true, undefined, { propFilter: propFilter });
(0, 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');
};
(0, 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 () {
(0, 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((0, 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;
};
(0, 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' };
(0, 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'] };
(0, 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 };
(0, testUtils_1.check)('ColumnWithUndocumentedProps', {
Column: {
prop1: { type: 'string', required: false },
prop2: { type: 'number' }
}
}, true, undefined, { propFilter: propFilter });
});
});
});
it('should defaultProps in variable', function () {
(0, 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 () {
(0, 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 () {
(0, 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: true
});
});
it('Should infer types from constraint type (generic with extends)', function () {
(0, testUtils_1.check)('GenericWithExtends', {
GenericWithExtends: {
sampleUnionProp: {
raw: 'SampleUnion',
type: 'enum',
value: [
{
value: '"value 1"'
},
{
value: '"value 2"'
},
{
value: '"value 3"'
},
{
value: '"value 4"'
},
{
value: '"value n"'
}
]
},
sampleEnumProp: {
raw: 'SampleEnum',
type: 'enum',
value: [
{ value: '0', description: '', fullComment: '', tags: {} },
{ value: '1', description: '', fullComment: '', tags: {} },
{ value: '"c"', description: '', fullComment: '', tags: {} }
]
},
sampleUnionNonGeneric: {
type: 'SampleUnionNonGeneric'
},
sampleObjectProp: {
type: 'SampleObject'
},
sampleNumberProp: {
type: 'number'
},
sampleGenericArray: {
type: 'number[]'
},
sampleGenericObject: {
type: '{ prop1: number; }'
},
sampleInlineObject: {
type: '{ propA: string; }'
}
}
}, true, null, { shouldExtractLiteralValuesFromEnum: true });
});
});
describe('Extracting values from unions', function () {
it('extracts all values from union', function () {
(0, testUtils_1.check)('ExtractLiteralValuesFromUnion', {
ExtractLiteralValuesFromUnion: {
sampleComplexUnion: {
raw: 'number | "string1" | "string2"',
type: 'enum',
value: [
{ value: 'number' },
{ value: '"string1"' },
{ value: '"string2"' }
]
}
}
}, false, null, {
shouldExtractValuesFromUnion: true
});
});
it('extracts numbers from a union', function () {
(0, testUtils_1.check)('ExtractLiteralValuesFromUnion', {
ExtractLiteralValuesFromUnion: {
sampleNumberUnion: {
raw: '1 | 2 | 3',
type: 'enum',
value: [{ value: '1' }, { value: '2' }, { value: '3' }]
}
}
}, false, null, {
shouldExtractValuesFromUnion: true
});
});
it('extracts numbers and strings from a mixed union', function () {
(0, testUtils_1.check)('ExtractLiteralValuesFromUnion', {
ExtractLiteralValuesFromUnion: {
sampleMixedUnion: {
raw: '"string1" | "string2" | 1 | 2',
type: 'enum',
value: [
{ value: '"strin