aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorST-DDT <[email protected]>2023-04-20 20:22:26 +0200
committerGitHub <[email protected]>2023-04-20 20:22:26 +0200
commita001ac5cf284d3027b9726f1f1f5f3fa14bc7bf4 (patch)
tree16282634fd7ef8954e8d2f4557d7e72dea735423
parent2098b4d20e9604c95ab24f2f89452a11ae5f49d7 (diff)
downloadfaker-a001ac5cf284d3027b9726f1f1f5f3fa14bc7bf4.tar.xz
faker-a001ac5cf284d3027b9726f1f1f5f3fa14bc7bf4.zip
docs: check api references (#2024)
-rw-r--r--scripts/apidoc.ts2
-rw-r--r--scripts/apidoc/fakerClass.ts6
-rw-r--r--scripts/apidoc/markdown.ts68
-rw-r--r--scripts/apidoc/moduleMethods.ts5
-rw-r--r--scripts/apidoc/signature.ts87
-rw-r--r--scripts/apidoc/typedoc.ts11
-rw-r--r--src/modules/image/index.ts2
-rw-r--r--test/scripts/apidoc/signature.debug.ts6
-rw-r--r--test/scripts/apidoc/signature.spec.ts10
-rw-r--r--test/scripts/apidoc/utils.ts15
-rw-r--r--test/scripts/apidoc/verify-jsdoc-tags.spec.ts258
11 files changed, 272 insertions, 198 deletions
diff --git a/scripts/apidoc.ts b/scripts/apidoc.ts
index ecb1f8fe..31171b9d 100644
--- a/scripts/apidoc.ts
+++ b/scripts/apidoc.ts
@@ -1,5 +1,5 @@
import { generate } from './apidoc/generate';
-import { initMarkdownRenderer } from './apidoc/signature';
+import { initMarkdownRenderer } from './apidoc/markdown';
async function build(): Promise<void> {
await initMarkdownRenderer();
diff --git a/scripts/apidoc/fakerClass.ts b/scripts/apidoc/fakerClass.ts
index 9d11815f..c3a5287d 100644
--- a/scripts/apidoc/fakerClass.ts
+++ b/scripts/apidoc/fakerClass.ts
@@ -3,8 +3,8 @@ import { ReflectionKind } from 'typedoc';
import type { Method } from '../../docs/.vitepress/components/api-docs/method';
import { writeApiDocsModule } from './apiDocsWriter';
import { processModuleMethods } from './moduleMethods';
-import { analyzeSignature, toBlock } from './signature';
-import { selectApiSignature } from './typedoc';
+import { analyzeSignature } from './signature';
+import { extractDescription, selectApiSignature } from './typedoc';
import type { ModuleSummary } from './utils';
export function processFakerClass(project: ProjectReflection): ModuleSummary {
@@ -21,7 +21,7 @@ export function processFakerClass(project: ProjectReflection): ModuleSummary {
function processClass(fakerClass: DeclarationReflection): ModuleSummary {
console.log(`Processing Faker class`);
- const comment = toBlock(fakerClass.comment);
+ const comment = extractDescription(fakerClass);
const methods: Method[] = [];
console.debug(`- constructor`);
diff --git a/scripts/apidoc/markdown.ts b/scripts/apidoc/markdown.ts
new file mode 100644
index 00000000..8505b51d
--- /dev/null
+++ b/scripts/apidoc/markdown.ts
@@ -0,0 +1,68 @@
+import sanitizeHtml from 'sanitize-html';
+import type { MarkdownRenderer } from 'vitepress';
+import { createMarkdownRenderer } from 'vitepress';
+import vitepressConfig from '../../docs/.vitepress/config';
+import { pathOutputDir } from './utils';
+
+let markdown: MarkdownRenderer;
+
+export async function initMarkdownRenderer(): Promise<void> {
+ markdown = await createMarkdownRenderer(
+ pathOutputDir,
+ vitepressConfig.markdown,
+ '/'
+ );
+}
+
+const htmlSanitizeOptions: sanitizeHtml.IOptions = {
+ allowedTags: [
+ 'a',
+ 'button',
+ 'code',
+ 'div',
+ 'li',
+ 'p',
+ 'pre',
+ 'span',
+ 'strong',
+ 'ul',
+ ],
+ allowedAttributes: {
+ a: ['href', 'target', 'rel'],
+ button: ['class', 'title'],
+ div: ['class'],
+ pre: ['class', 'tabindex', 'v-pre'],
+ span: ['class', 'style'],
+ },
+ selfClosing: [],
+};
+
+function comparableSanitizedHtml(html: string): string {
+ return html
+ .replace(/&gt;/g, '>')
+ .replace(/ /g, '')
+ .replace(/&quot;/g, '"')
+ .replace(/&#39;/g, "'");
+}
+
+/**
+ * Converts Markdown to an HTML string and sanitizes it.
+ * @param md The markdown to convert.
+ * @param inline Whether to render the markdown as inline, without a wrapping `<p>` tag. Defaults to `false`.
+ * @returns The converted HTML string.
+ */
+export function mdToHtml(md: string, inline: boolean = false): string {
+ const rawHtml = inline ? markdown.renderInline(md) : markdown.render(md);
+
+ const safeHtml: string = sanitizeHtml(rawHtml, htmlSanitizeOptions);
+ // Revert some escaped characters for comparison.
+ if (comparableSanitizedHtml(rawHtml) === comparableSanitizedHtml(safeHtml)) {
+ return safeHtml.replace(/https:\/\/(next.)?fakerjs.dev\//g, '/');
+ }
+
+ console.debug('Rejected unsafe md:', md);
+ console.error('Rejected unsafe html:', rawHtml);
+ console.error('Rejected unsafe html:', comparableSanitizedHtml(rawHtml));
+ console.error('Expected safe html:', comparableSanitizedHtml(safeHtml));
+ throw new Error('Found unsafe html');
+}
diff --git a/scripts/apidoc/moduleMethods.ts b/scripts/apidoc/moduleMethods.ts
index 9c902dd7..55b1869f 100644
--- a/scripts/apidoc/moduleMethods.ts
+++ b/scripts/apidoc/moduleMethods.ts
@@ -5,9 +5,10 @@ import type {
} from 'typedoc';
import type { Method } from '../../docs/.vitepress/components/api-docs/method';
import { writeApiDocsModule } from './apiDocsWriter';
-import { analyzeSignature, stripAbsoluteFakerUrls, toBlock } from './signature';
+import { analyzeSignature } from './signature';
import {
extractDeprecated,
+ extractDescription,
extractModuleFieldName,
extractModuleName,
selectApiMethodSignatures,
@@ -35,7 +36,7 @@ function processModule(module: DeclarationReflection): ModuleSummary {
const moduleName = extractModuleName(module);
const moduleFieldName = extractModuleFieldName(module);
console.log(`Processing Module ${moduleName}`);
- const comment = stripAbsoluteFakerUrls(toBlock(module.comment));
+ const comment = extractDescription(module);
const deprecated = extractDeprecated(module);
const methods = processModuleMethods(module, `faker.${moduleFieldName}.`);
diff --git a/scripts/apidoc/signature.ts b/scripts/apidoc/signature.ts
index 8b5083ae..67101574 100644
--- a/scripts/apidoc/signature.ts
+++ b/scripts/apidoc/signature.ts
@@ -1,4 +1,3 @@
-import sanitizeHtml from 'sanitize-html';
import type {
Comment,
DeclarationReflection,
@@ -10,16 +9,15 @@ import type {
Type,
} from 'typedoc';
import { ReflectionFlag, ReflectionKind } from 'typedoc';
-import type { MarkdownRenderer } from 'vitepress';
-import { createMarkdownRenderer } from 'vitepress';
import type {
Method,
MethodParameter,
} from '../../docs/.vitepress/components/api-docs/method';
-import vitepressConfig from '../../docs/.vitepress/config';
import { formatTypescript } from './format';
+import { mdToHtml } from './markdown';
import {
extractDeprecated,
+ extractDescription,
extractRawDefault,
extractRawExamples,
extractSeeAlsos,
@@ -27,84 +25,11 @@ import {
extractSourcePath,
extractThrows,
joinTagParts,
+ toBlock,
} from './typedoc';
-import { pathOutputDir } from './utils';
const code = '```';
-export const MISSING_DESCRIPTION = 'Missing';
-
-export function toBlock(comment?: Comment): string {
- return joinTagParts(comment?.summary) || MISSING_DESCRIPTION;
-}
-
-export function stripAbsoluteFakerUrls(markdown: string): string {
- return markdown.replace(/https:\/\/(next.)?fakerjs.dev\//g, '/');
-}
-
-let markdown: MarkdownRenderer;
-
-export async function initMarkdownRenderer(): Promise<void> {
- markdown = await createMarkdownRenderer(
- pathOutputDir,
- vitepressConfig.markdown,
- '/'
- );
-}
-
-const htmlSanitizeOptions: sanitizeHtml.IOptions = {
- allowedTags: [
- 'a',
- 'button',
- 'code',
- 'div',
- 'li',
- 'p',
- 'pre',
- 'span',
- 'strong',
- 'ul',
- ],
- allowedAttributes: {
- a: ['href', 'target', 'rel'],
- button: ['class', 'title'],
- div: ['class'],
- pre: ['class', 'tabindex', 'v-pre'],
- span: ['class', 'style'],
- },
- selfClosing: [],
-};
-
-function comparableSanitizedHtml(html: string): string {
- return html
- .replace(/&gt;/g, '>')
- .replace(/ /g, '')
- .replace(/&quot;/g, '"')
- .replace(/&#39;/g, "'");
-}
-
-/**
- * Converts Markdown to an HTML string and sanitizes it.
- * @param md The markdown to convert.
- * @param inline Whether to render the markdown as inline, without a wrapping `<p>` tag. Defaults to `false`.
- * @returns The converted HTML string.
- */
-function mdToHtml(md: string, inline: boolean = false): string {
- const rawHtml = inline ? markdown.renderInline(md) : markdown.render(md);
-
- const safeHtml: string = sanitizeHtml(rawHtml, htmlSanitizeOptions);
- // Revert some escaped characters for comparison.
- if (comparableSanitizedHtml(rawHtml) === comparableSanitizedHtml(safeHtml)) {
- return safeHtml;
- }
-
- console.debug('Rejected unsafe md:', md);
- console.error('Rejected unsafe html:', rawHtml);
- console.error('Rejected unsafe html:', comparableSanitizedHtml(rawHtml));
- console.error('Expected safe html:', comparableSanitizedHtml(safeHtml));
- throw new Error('Found unsafe html');
-}
-
export function analyzeSignature(
signature: SignatureReflection,
accessor: string,
@@ -120,7 +45,7 @@ export function analyzeSignature(
parameters.push({
name: `<${parameter.name}>`,
type: parameter.type ? typeToText(parameter.type) : undefined,
- description: mdToHtml(toBlock(parameter.comment)),
+ description: mdToHtml(extractDescription(parameter)),
});
}
@@ -166,7 +91,7 @@ export function analyzeSignature(
return {
name: methodName,
- description: mdToHtml(toBlock(signature.comment)),
+ description: mdToHtml(extractDescription(signature)),
parameters: parameters,
since: extractSince(signature),
sourcePath: extractSourcePath(signature),
@@ -200,7 +125,7 @@ function analyzeParameter(parameter: ParameterReflection): {
name: declarationName,
type: typeToText(type, true),
default: defaultValue,
- description: mdToHtml(toBlock(parameter.comment)),
+ description: mdToHtml(extractDescription(parameter)),
},
];
parameters.push(...analyzeParameterOptions(name, type));
diff --git a/scripts/apidoc/typedoc.ts b/scripts/apidoc/typedoc.ts
index 858171ac..1a782aa9 100644
--- a/scripts/apidoc/typedoc.ts
+++ b/scripts/apidoc/typedoc.ts
@@ -1,4 +1,5 @@
import type {
+ Comment,
CommentDisplayPart,
CommentTag,
DeclarationReflection,
@@ -149,6 +150,16 @@ export function extractModuleFieldName(module: DeclarationReflection): string {
return moduleName.substring(0, 1).toLowerCase() + moduleName.substring(1);
}
+export const MISSING_DESCRIPTION = 'Missing';
+
+export function toBlock(comment?: Comment): string {
+ return joinTagParts(comment?.summary) || MISSING_DESCRIPTION;
+}
+
+export function extractDescription(reflection: Reflection): string {
+ return toBlock(reflection.comment);
+}
+
/**
* Extracts the source url from the jsdocs.
*
diff --git a/src/modules/image/index.ts b/src/modules/image/index.ts
index e7d26814..2e7806ff 100644
--- a/src/modules/image/index.ts
+++ b/src/modules/image/index.ts
@@ -10,7 +10,7 @@ import { Unsplash } from './providers/unsplash';
*
* ### Overview
*
- * For a random image, use [`url()`](https://next.fakerjs.dev/api/image.html#url). This will not return the image directly but a URL pointing to an image from one of two demo image providers "Picsum" and "LoremFlickr". You can request an image specifically from one of two providers using [`urlLoremFlickr()`](https://next.fakerjs.dev/api/image.html#urlloremflickr) or [`urlPicsum()`](https://next.fakerjs.dev/api/image.html#urlpicsum).
+ * For a random image, use [`url()`](https://next.fakerjs.dev/api/image.html#url). This will not return the image directly but a URL pointing to an image from one of two demo image providers "Picsum" and "LoremFlickr". You can request an image specifically from one of two providers using [`urlLoremFlickr()`](https://next.fakerjs.dev/api/image.html#urlloremflickr) or [`urlPicsumPhotos()`](https://next.fakerjs.dev/api/image.html#urlpicsumphotos).
*
* For a random placeholder image containing only solid color and text, use [`urlPlaceholder()`](https://next.fakerjs.dev/api/image.html#urlplaceholder) (uses a third-party service) or [`dataUri()`](https://next.fakerjs.dev/api/image.html#datauri) (returns a SVG string).
*
diff --git a/test/scripts/apidoc/signature.debug.ts b/test/scripts/apidoc/signature.debug.ts
index 0076dfa7..347b8235 100644
--- a/test/scripts/apidoc/signature.debug.ts
+++ b/test/scripts/apidoc/signature.debug.ts
@@ -2,10 +2,8 @@
* This file exists, because vitest doesn't allow me to debug code outside of src and test.
* And it's easier to test these features independently from the main project.
*/
-import {
- analyzeSignature,
- initMarkdownRenderer,
-} from '../../../scripts/apidoc/signature';
+import { initMarkdownRenderer } from '../../../scripts/apidoc/markdown';
+import { analyzeSignature } from '../../../scripts/apidoc/signature';
import { loadExampleMethods } from './utils';
/* Run with `pnpm tsx test/scripts/apidoc/signature.debug.ts` */
diff --git a/test/scripts/apidoc/signature.spec.ts b/test/scripts/apidoc/signature.spec.ts
index 3a48c29b..e80d78e6 100644
--- a/test/scripts/apidoc/signature.spec.ts
+++ b/test/scripts/apidoc/signature.spec.ts
@@ -1,8 +1,6 @@
import { beforeAll, describe, expect, it } from 'vitest';
-import {
- analyzeSignature,
- initMarkdownRenderer,
-} from '../../../scripts/apidoc/signature';
+import { initMarkdownRenderer } from '../../../scripts/apidoc/markdown';
+import { analyzeSignature } from '../../../scripts/apidoc/signature';
import { SignatureTest } from './signature.example';
import { loadExampleMethods } from './utils';
@@ -10,9 +8,7 @@ describe('signature', () => {
describe('analyzeSignature()', () => {
const methods = loadExampleMethods();
- beforeAll(async () => {
- await initMarkdownRenderer();
- });
+ beforeAll(initMarkdownRenderer);
it('dummy dependency to rerun the test if the example changes', () => {
expect(new SignatureTest()).toBeTruthy();
diff --git a/test/scripts/apidoc/utils.ts b/test/scripts/apidoc/utils.ts
index 809240c8..281fb2ef 100644
--- a/test/scripts/apidoc/utils.ts
+++ b/test/scripts/apidoc/utils.ts
@@ -1,4 +1,8 @@
-import type { SignatureReflection, TypeDocOptions } from 'typedoc';
+import type {
+ DeclarationReflection,
+ SignatureReflection,
+ TypeDocOptions,
+} from 'typedoc';
import {
loadProject,
selectApiMethodSignatures,
@@ -12,12 +16,15 @@ import { mapByName } from '../../../scripts/apidoc/utils';
export function loadProjectModules(
options?: Partial<TypeDocOptions>,
includeTestModules = false
-): Record<string, Record<string, SignatureReflection>> {
+): Record<
+ string,
+ [DeclarationReflection, Record<string, SignatureReflection>]
+> {
const [, project] = loadProject(options);
const modules = selectApiModules(project, includeTestModules);
- return mapByName(modules, selectApiMethodSignatures);
+ return mapByName(modules, (m) => [m, selectApiMethodSignatures(m)]);
}
/**
@@ -30,5 +37,5 @@ export function loadExampleMethods(): Record<string, SignatureReflection> {
tsconfig: 'test/scripts/apidoc/tsconfig.json',
},
true
- )['SignatureTest'];
+ )['SignatureTest'][1];
}
diff --git a/test/scripts/apidoc/verify-jsdoc-tags.spec.ts b/test/scripts/apidoc/verify-jsdoc-tags.spec.ts
index 68692fab..1e8fc55e 100644
--- a/test/scripts/apidoc/verify-jsdoc-tags.spec.ts
+++ b/test/scripts/apidoc/verify-jsdoc-tags.spec.ts
@@ -1,18 +1,18 @@
-import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
+import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';
import validator from 'validator';
import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';
-import {
- analyzeSignature,
- initMarkdownRenderer,
- MISSING_DESCRIPTION,
-} from '../../../scripts/apidoc/signature';
+import { initMarkdownRenderer } from '../../../scripts/apidoc/markdown';
+import { analyzeSignature } from '../../../scripts/apidoc/signature';
import {
extractDeprecated,
+ extractDescription,
+ extractModuleFieldName,
extractRawExamples,
extractSeeAlsos,
extractSince,
extractTagContent,
+ MISSING_DESCRIPTION,
} from '../../../scripts/apidoc/typedoc';
import { loadProjectModules } from './utils';
@@ -26,7 +26,9 @@ const tempDir = resolve(__dirname, 'temp');
afterAll(() => {
// Remove temp folder
- rmSync(tempDir, { recursive: true });
+ if (existsSync(tempDir)) {
+ rmSync(tempDir, { recursive: true });
+ }
});
describe('verify JSDoc tags', () => {
@@ -44,107 +46,173 @@ describe('verify JSDoc tags', () => {
return resolve(dir, `${methodName}.ts`);
}
- describe.each(Object.entries(modules))('%s', (moduleName, methodsByName) => {
- describe.each(Object.entries(methodsByName))(
- '%s',
- (methodName, signature) => {
- beforeAll(() => {
- // Write temp files to disk
-
- // Extract examples and make them runnable
- const examples = extractRawExamples(signature).join('').trim();
-
- // Save examples to a file to run them later in the specific tests
- const dir = resolveDirToModule(moduleName);
- mkdirSync(dir, { recursive: true });
-
- const path = resolvePathToMethodFile(moduleName, methodName);
- const imports = [...new Set(examples.match(/faker[^\.]*(?=\.)/g))];
- writeFileSync(
- path,
- `import { ${imports.join(
- ', '
- )} } from '../../../../../src';\n\n${examples}`
- );
+ const allowedReferences = new Set(
+ Object.values(modules).reduce((acc, [module, methods]) => {
+ const moduleFieldName = extractModuleFieldName(module);
+ return [
+ ...acc,
+ ...Object.keys(methods).map(
+ (methodName) => `faker.${moduleFieldName}.${methodName}`
+ ),
+ ];
+ }, [] as string[])
+ );
+ const allowedLinks = new Set(
+ Object.values(modules).reduce((acc, [module, methods]) => {
+ const moduleFieldName = extractModuleFieldName(module);
+ return [
+ ...acc,
+ `/api/${moduleFieldName}.html`,
+ ...Object.keys(methods).map(
+ (methodName) =>
+ `/api/${moduleFieldName}.html#${methodName.toLowerCase()}`
+ ),
+ ];
+ }, [] as string[])
+ );
+
+ function assertDescription(description: string, isHtml: boolean): void {
+ const linkRegexp = isHtml
+ ? /(href)="([^"]+)"/g
+ : /\[([^\]]+)\]\(([^)]+)\)/g;
+ const links = [...description.matchAll(linkRegexp)].map((m) => m[2]);
+
+ for (const link of links) {
+ if (!isHtml) {
+ expect(link).toMatch(/^https?:\/\//);
+ expect(link).toSatisfy(validator.isURL);
+ }
+
+ if (
+ isHtml ? link.startsWith('/api/') : link.includes('fakerjs.dev/api/')
+ ) {
+ expect(allowedLinks, `${link} to point to a valid target`).toContain(
+ link.replace(/.*fakerjs.dev\//, '/')
+ );
+ }
+ }
+ }
+
+ describe.each(Object.entries(modules))(
+ '%s',
+ (moduleName, [module, methodsByName]) => {
+ describe('verify module', () => {
+ it('verify description', () => {
+ const description = extractDescription(module);
+ assertDescription(description, false);
});
+ });
+
+ describe.each(Object.entries(methodsByName))(
+ '%s',
+ (methodName, signature) => {
+ beforeAll(() => {
+ // Write temp files to disk
+
+ // Extract examples and make them runnable
+ const examples = extractRawExamples(signature).join('').trim();
+
+ // Save examples to a file to run them later in the specific tests
+ const dir = resolveDirToModule(moduleName);
+ mkdirSync(dir, { recursive: true });
+
+ const path = resolvePathToMethodFile(moduleName, methodName);
+ const imports = [...new Set(examples.match(/faker[^\.]*(?=\.)/g))];
+ writeFileSync(
+ path,
+ `import { ${imports.join(
+ ', '
+ )} } from '../../../../../src';\n\n${examples}`
+ );
+ });
- it('verify @example tag', async () => {
- // Extract the examples
- const examples = extractRawExamples(signature).join('').trim();
+ it('verify description', () => {
+ const description = extractDescription(signature);
+ assertDescription(description, false);
+ });
- expect(
- examples,
- `${moduleName}.${methodName} to have examples`
- ).not.toBe('');
+ it('verify @example tag', async () => {
+ // Extract the examples
+ const examples = extractRawExamples(signature).join('').trim();
- // Grab path to example file
- const path = resolvePathToMethodFile(moduleName, methodName);
+ expect(
+ examples,
+ `${moduleName}.${methodName} to have examples`
+ ).not.toBe('');
- // Executing the examples should not throw
- await expect(import(`${path}?scope=example`)).resolves.toBeDefined();
- });
+ // Grab path to example file
+ const path = resolvePathToMethodFile(moduleName, methodName);
- // This only checks whether the whole method is deprecated or not
- // It does not check whether the method is deprecated for a specific set of arguments
- it('verify @deprecated tag', async () => {
- // Grab path to example file
- const path = resolvePathToMethodFile(moduleName, methodName);
+ // Executing the examples should not throw
+ await expect(
+ import(`${path}?scope=example`)
+ ).resolves.toBeDefined();
+ });
- const consoleWarnSpy = vi.spyOn(console, 'warn');
+ // This only checks whether the whole method is deprecated or not
+ // It does not check whether the method is deprecated for a specific set of arguments
+ it('verify @deprecated tag', async () => {
+ // Grab path to example file
+ const path = resolvePathToMethodFile(moduleName, methodName);
- // Run the examples
- await import(`${path}?scope=deprecated`);
+ const consoleWarnSpy = vi.spyOn(console, 'warn');
- // Verify that deprecated methods log a warning
- const deprecatedFlag = extractDeprecated(signature) !== undefined;
- if (deprecatedFlag) {
- expect(consoleWarnSpy).toHaveBeenCalled();
- expect(
- extractTagContent('@deprecated', signature).join(''),
- '@deprecated tag without message'
- ).not.toBe('');
- } else {
- expect(consoleWarnSpy).not.toHaveBeenCalled();
- }
- });
+ // Run the examples
+ await import(`${path}?scope=deprecated`);
- it('verify @param tags', () => {
- analyzeSignature(signature, '', methodName).parameters.forEach(
- (param) => {
- const { name, description } = param;
- const plainDescription = description
- .replace(/<[^>]+>/g, '')
- .trim();
+ // Verify that deprecated methods log a warning
+ const deprecatedFlag = extractDeprecated(signature) !== undefined;
+ if (deprecatedFlag) {
+ expect(consoleWarnSpy).toHaveBeenCalled();
expect(
- plainDescription,
- `Expect param ${name} to have a description`
- ).not.toBe(MISSING_DESCRIPTION);
+ extractTagContent('@deprecated', signature).join(''),
+ '@deprecated tag without message'
+ ).not.toBe('');
+ } else {
+ expect(consoleWarnSpy).not.toHaveBeenCalled();
}
- );
- });
+ });
- it('verify @see tags', () => {
- extractSeeAlsos(signature).forEach((link) => {
- if (link.startsWith('faker.')) {
- // Expected @see faker.xxx.yyy()
- expect(link, 'Expect method reference to contain ()').toContain(
- '('
- );
- expect(link, 'Expect method reference to contain ()').toContain(
- ')'
- );
- }
+ it('verify @param tags', () => {
+ analyzeSignature(signature, '', methodName).parameters.forEach(
+ (param) => {
+ const { name, description } = param;
+ const plainDescription = description
+ .replace(/<[^>]+>/g, '')
+ .trim();
+ expect(
+ plainDescription,
+ `Expect param ${name} to have a description`
+ ).not.toBe(MISSING_DESCRIPTION);
+ assertDescription(description, true);
+ }
+ );
});
- });
- it('verify @since tag', () => {
- const since = extractSince(signature);
- expect(since, '@since to be present').toBeTruthy();
- expect(since, '@since to be a valid semver').toSatisfy(
- validator.isSemVer
- );
- });
- }
- );
- });
+ it('verify @see tags', () => {
+ extractSeeAlsos(signature).forEach((link) => {
+ if (link.startsWith('faker.')) {
+ // Expected @see faker.xxx.yyy()
+ expect(link, 'Expect method reference to contain ()').toContain(
+ '('
+ );
+ expect(link, 'Expect method reference to contain ()').toContain(
+ ')'
+ );
+ expect(allowedReferences).toContain(link.replace(/\(.*/, ''));
+ }
+ });
+ });
+
+ it('verify @since tag', () => {
+ const since = extractSince(signature);
+ expect(since, '@since to be present').toBeTruthy();
+ expect(since, '@since to be a valid semver').toSatisfy(
+ validator.isSemVer
+ );
+ });
+ }
+ );
+ }
+ );
});