Skip to content

Commit

Permalink
test: separate jsdoc tag tests (#1969)
Browse files Browse the repository at this point in the history
  • Loading branch information
Shinigami92 authored Mar 30, 2023
1 parent 3562e87 commit 063ba6e
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 125 deletions.
4 changes: 3 additions & 1 deletion scripts/apidoc/signature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ function prettifyMethodName(method: string): string {
);
}

export const MISSING_DESCRIPTION = 'Missing';

export function toBlock(comment?: Comment): string {
return joinTagParts(comment?.summary) || 'Missing';
return joinTagParts(comment?.summary) || MISSING_DESCRIPTION;
}

export function stripAbsoluteFakerUrls(markdown: string): string {
Expand Down
124 changes: 0 additions & 124 deletions test/scripts/apidoc/examplesAndDeprecations.spec.ts

This file was deleted.

150 changes: 150 additions & 0 deletions test/scripts/apidoc/verify-jsdoc-tags.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { mkdirSync, rmdirSync, 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 {
extractDeprecated,
extractRawExamples,
extractSeeAlsos,
extractSince,
extractTagContent,
} from '../../../scripts/apidoc/typedoc';
import { loadProjectModules } from './utils';

// This test ensures, that every method
// - has working examples
// - running these do not log anything, unless the method is deprecated

beforeAll(initMarkdownRenderer);

const tempDir = resolve(__dirname, 'temp');

afterAll(() => {
// Remove temp folder
rmdirSync(tempDir, { recursive: true });
});

describe('verify JSDoc tags', () => {
const modules = loadProjectModules();

function resolveDirToModule(moduleName: string): string {
return resolve(tempDir, moduleName);
}

function resolvePathToMethodFile(
moduleName: string,
methodName: string
): string {
const dir = resolveDirToModule(moduleName);
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}`
);
});

it('verify @example tag', async () => {
// Extract the examples
const examples = extractRawExamples(signature).join('').trim();

expect(
examples,
`${moduleName}.${methodName} to have examples`
).not.toBe('');

// Grab path to example file
const path = resolvePathToMethodFile(moduleName, methodName);

// Executing the examples should not throw
await expect(import(`${path}?scope=example`)).resolves.toBeDefined();
});

// 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);

const consoleWarnSpy = vi.spyOn(console, 'warn');

// Run the examples
await import(`${path}?scope=deprecated`);

// 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();
}
});

it('verify @param tags', () => {
analyzeSignature(
signature,
moduleName,
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);
});
});

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 @since tag', () => {
const since = extractSince(signature);
expect(since, '@since to be present').toBeTruthy();
expect(since, '@since to be a valid semver').toSatisfy(
validator.isSemVer
);
});
}
);
});
});

0 comments on commit 063ba6e

Please sign in to comment.