aboutsummaryrefslogtreecommitdiff
path: root/test/scripts
diff options
context:
space:
mode:
authorST-DDT <[email protected]>2022-05-04 14:58:25 +0200
committerGitHub <[email protected]>2022-05-04 12:58:25 +0000
commitf1dba1bb0b90dc5e1e3ee096f937a1d4df6acf03 (patch)
treeb2bdcb89baba518cc78a05d266839d0f114bb1dd /test/scripts
parent39b74c0326da2d96fa48837a9ad9b995b7158fbd (diff)
downloadfaker-f1dba1bb0b90dc5e1e3ee096f937a1d4df6acf03.tar.xz
faker-f1dba1bb0b90dc5e1e3ee096f937a1d4df6acf03.zip
test: ensure working examples and no console spam (#908)
Diffstat (limited to 'test/scripts')
-rw-r--r--test/scripts/apidoc/.gitignore1
-rw-r--r--test/scripts/apidoc/examplesAndDeprecations.spec.ts111
-rw-r--r--test/scripts/apidoc/utils.ts19
3 files changed, 130 insertions, 1 deletions
diff --git a/test/scripts/apidoc/.gitignore b/test/scripts/apidoc/.gitignore
index b0645e5b..4d07e30e 100644
--- a/test/scripts/apidoc/.gitignore
+++ b/test/scripts/apidoc/.gitignore
@@ -1 +1,2 @@
*.actuals.json
+temp/
diff --git a/test/scripts/apidoc/examplesAndDeprecations.spec.ts b/test/scripts/apidoc/examplesAndDeprecations.spec.ts
new file mode 100644
index 00000000..3bfca24f
--- /dev/null
+++ b/test/scripts/apidoc/examplesAndDeprecations.spec.ts
@@ -0,0 +1,111 @@
+import { mkdirSync, writeFileSync } from 'node:fs';
+import { resolve } from 'node:path';
+import type { DeclarationReflection, SignatureReflection } from 'typedoc';
+import { ReflectionKind } from 'typedoc';
+import type { SpyInstance } from 'vitest';
+import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest';
+import { faker } from '../../../src';
+import { loadProject } from './utils';
+
+/*
+ * This test ensures, that every method
+ * - has working examples
+ * - and running these does not log anything, unless the method is deprecated
+ */
+
+const locales: Record<string, string> = {
+ GH: 'en_GH',
+ US: 'en_US',
+};
+
+describe('examples and deprecations', () => {
+ const project = loadProject();
+
+ const directs: DeclarationReflection[] = project
+ .getChildrenByKind(ReflectionKind.Class)
+ .filter((ref) => ref.name === 'Faker')[0]
+ .getChildrenByKind(ReflectionKind.Property)
+ .filter((ref) => ['fake', 'unique'].includes(ref.name));
+
+ const modules: Record<string, DeclarationReflection[]> = project
+ .getChildrenByKind(ReflectionKind.Namespace)[0]
+ .getChildrenByKind(ReflectionKind.Class)
+ .filter((ref) => faker[ref.name.toLowerCase()] && ref.name !== 'Mersenne')
+ .reduce(
+ (a, v) => ({
+ ...a,
+ [v.name]: v.getChildrenByKind(ReflectionKind.Method),
+ }),
+ { directs }
+ );
+
+ const consoleSpies: Array<SpyInstance> = Object.keys(console)
+ .filter((key) => typeof console[key] === 'function')
+ .map((methodName) => vi.spyOn(console, methodName as keyof typeof console));
+
+ afterAll(() => {
+ faker.locale = 'en';
+ for (const spy of consoleSpies) {
+ spy.mockRestore();
+ }
+ });
+
+ describe.each(Object.entries(modules))('%s', (moduleName, methods) => {
+ const methodsByName: Record<string, DeclarationReflection> = methods.reduce(
+ (a, v) => ({ ...a, [v.name]: v }),
+ {}
+ );
+
+ beforeEach(() => {
+ faker.locale = 'en';
+ for (const spy of consoleSpies) {
+ spy.mockReset();
+ }
+ });
+
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
+ it.each(Object.entries(methodsByName))('%s', async (methodName, method) => {
+ const signatures: SignatureReflection[] =
+ method.signatures || method.type['declaration'].signatures;
+ const signature = signatures[signatures.length - 1];
+
+ // Extract examples and make them runnable
+ let examples =
+ signature?.comment?.tags
+ .filter((tag) => tag.tagName === 'example')
+ .map((tag) => tag.text.trimEnd())
+ .join('')
+ .trim() ?? '';
+ examples = examples.replace(
+ /faker([A-Z]{2})\./g,
+ (_, locale: string) => `faker.locale = '${locales[locale]}';\nfaker.`
+ );
+
+ expect(examples, `${moduleName}.${methodName} to have examples`).not.toBe(
+ ''
+ );
+
+ // Save examples to a file to run it
+ const dir = resolve(__dirname, 'temp', moduleName);
+ mkdirSync(dir, { recursive: true });
+ const path = resolve(dir, `${methodName}.ts`);
+ writeFileSync(
+ path,
+ `import { faker } from '../../../../../src';\n${examples}`
+ );
+
+ // Run the examples
+ await import(path);
+
+ // Verify logging
+ const deprecatedFlag = signature.comment?.hasTag('deprecated') ?? false;
+ if (deprecatedFlag) {
+ expect(consoleSpies[1]).toHaveBeenCalled();
+ } else {
+ for (const spy of consoleSpies) {
+ expect(spy).not.toHaveBeenCalled();
+ }
+ }
+ });
+ });
+});
diff --git a/test/scripts/apidoc/utils.ts b/test/scripts/apidoc/utils.ts
index d4d11e8c..19c4b4ea 100644
--- a/test/scripts/apidoc/utils.ts
+++ b/test/scripts/apidoc/utils.ts
@@ -1,4 +1,4 @@
-import type { DeclarationReflection } from 'typedoc';
+import type { DeclarationReflection, ProjectReflection } from 'typedoc';
import { ReflectionKind } from 'typedoc';
import { newTypeDocApp, patchProject } from '../../../scripts/apidoc/utils';
@@ -24,3 +24,20 @@ export function loadExampleMethods(): Record<string, DeclarationReflection> {
return methods;
}
+
+/**
+ * Loads the project using TypeDoc.
+ */
+export function loadProject(): ProjectReflection {
+ const app = newTypeDocApp();
+
+ app.bootstrap({
+ entryPoints: ['src/index.ts'],
+ });
+
+ const project = app.convert();
+
+ patchProject(project);
+
+ return project;
+}