diff --git a/src/csf/__snapshots__/transformCsf.test.ts.snap b/src/csf/__snapshots__/transformCsf.test.ts.snap index fb35c604..13170c98 100644 --- a/src/csf/__snapshots__/transformCsf.test.ts.snap +++ b/src/csf/__snapshots__/transformCsf.test.ts.snap @@ -1314,3 +1314,12 @@ if (!require.main) { }); }" `; + +exports[`transformCsf returns empty result if there are no stories 1`] = ` +" + export default { + title: 'Button', + }; + +" +`; diff --git a/src/csf/transformCsf.test.ts b/src/csf/transformCsf.test.ts index 0326ed30..61c11d0c 100644 --- a/src/csf/transformCsf.test.ts +++ b/src/csf/transformCsf.test.ts @@ -17,6 +17,18 @@ describe('transformCsf', () => { expect(result).toEqual(expectedCode); }); + it('returns empty result if there are no stories', () => { + const csfCode = ` + export default { + title: 'Button', + }; + `; + + const result = transformCsf(csfCode, {}); + + expect(result).toMatchSnapshot(); + }); + it('calls the testPrefixer function for each test', () => { const csfCode = ` export default { diff --git a/src/csf/transformCsf.ts b/src/csf/transformCsf.ts index 113b8a08..bbb37a86 100644 --- a/src/csf/transformCsf.ts +++ b/src/csf/transformCsf.ts @@ -62,7 +62,7 @@ const makePlayTest = ( return [ t.expressionStatement( t.callExpression(t.identifier('it'), [ - t.stringLiteral(!!metaOrStoryPlay ? 'play-test' : 'smoke-test'), + t.stringLiteral(metaOrStoryPlay ? 'play-test' : 'smoke-test'), prefixFunction(key, title, metaOrStoryPlay as t.Expression, testPrefix), ]) ), @@ -100,9 +100,9 @@ export const transformCsf = ( beforeEachPrefixer, insertTestIfEmpty, makeTitle, - }: TransformOptions = {} + }: TransformOptions ) => { - const csf = loadCsf(code, { makeTitle: makeTitle || ((userTitle: string) => userTitle) }); + const csf = loadCsf(code, { makeTitle: makeTitle ?? ((userTitle: string) => userTitle) }); csf.parse(); const storyExports = Object.keys(csf._stories); @@ -125,7 +125,6 @@ export const transformCsf = ( if (tests.length) { return makeDescribe(key, tests); } - return null; }) .filter(Boolean) as babel.types.Statement[]; diff --git a/src/playwright/hooks.ts b/src/playwright/hooks.ts index c082aa28..c4404e8a 100644 --- a/src/playwright/hooks.ts +++ b/src/playwright/hooks.ts @@ -14,7 +14,7 @@ export type PrepareContext = { }; export type TestHook = (page: Page, context: TestContext) => Promise; -export type HttpHeaderSetter = (url: string) => Promise>; +export type HttpHeaderSetter = (url: string) => Promise>; export type PrepareSetter = (context: PrepareContext) => Promise; export interface TestRunnerConfig { diff --git a/src/playwright/index.ts b/src/playwright/index.ts index 8abfbf42..e24e8811 100644 --- a/src/playwright/index.ts +++ b/src/playwright/index.ts @@ -1,7 +1,7 @@ import { transformSync as swcTransform } from '@swc/core'; import { transformPlaywright } from './transformPlaywright'; -export const process = (src: string, filename: string, config: any) => { +export const process = (src: string, filename: string) => { const csfTest = transformPlaywright(src, filename); const result = swcTransform(csfTest, { diff --git a/src/playwright/transformPlaywright.test.ts b/src/playwright/transformPlaywright.test.ts index 8181cb15..0a36cb8f 100644 --- a/src/playwright/transformPlaywright.test.ts +++ b/src/playwright/transformPlaywright.test.ts @@ -19,8 +19,8 @@ jest.mock('@storybook/core-common', () => ({ })); expect.addSnapshotSerializer({ - print: (val: any) => val.trim(), - test: (val: any) => true, + print: (val: unknown) => (typeof val === 'string' ? val.trim() : String(val)), + test: () => true, }); describe('Playwright', () => { diff --git a/src/playwright/transformPlaywright.ts b/src/playwright/transformPlaywright.ts index 7f5bcd9b..87a0e308 100644 --- a/src/playwright/transformPlaywright.ts +++ b/src/playwright/transformPlaywright.ts @@ -13,8 +13,9 @@ const coverageErrorMessage = dedent` More info: https://github.com/storybookjs/test-runner#setting-up-code-coverage `; -export const testPrefixer = template( - ` +export const testPrefixer: TestPrefixer = (context) => { + return template( + ` console.log({ id: %%id%%, title: %%title%%, name: %%name%%, storyExport: %%storyExport%% }); async () => { const testFn = async() => { @@ -62,14 +63,20 @@ export const testPrefixer = template( } } `, - { - plugins: ['jsx'], - } -) as any as TestPrefixer; + { + plugins: ['jsx'], + } + )({ + id: context.id, + title: context.title, + name: context.name, + storyExport: context.storyExport, + }); +}; const makeTitleFactory = (filename: string) => { const { workingDir, normalizedStoriesEntries } = getStorybookMetadata(); - const filePath = './' + relative(workingDir, filename); + const filePath = `./${relative(workingDir, filename)}`; return (userTitle: string) => userOrAutoTitle(filePath, normalizedStoriesEntries, userTitle) as string; diff --git a/src/playwright/transformPlaywrightJson.test.ts b/src/playwright/transformPlaywrightJson.test.ts index beb0b5f2..d1ffbd29 100644 --- a/src/playwright/transformPlaywrightJson.test.ts +++ b/src/playwright/transformPlaywrightJson.test.ts @@ -1,4 +1,9 @@ -import { transformPlaywrightJson } from './transformPlaywrightJson'; +import { + UnsupportedVersion, + V3StoriesIndex, + V4Index, + transformPlaywrightJson, +} from './transformPlaywrightJson'; describe('Playwright Json', () => { describe('v4 indexes', () => { @@ -10,22 +15,19 @@ describe('Playwright Json', () => { id: 'example-header--logged-in', title: 'Example/Header', name: 'Logged In', - importPath: './stories/basic/Header.stories.js', }, 'example-header--logged-out': { id: 'example-header--logged-out', title: 'Example/Header', name: 'Logged Out', - importPath: './stories/basic/Header.stories.js', }, 'example-page--logged-in': { id: 'example-page--logged-in', title: 'Example/Page', name: 'Logged In', - importPath: './stories/basic/Page.stories.js', }, }, - }; + } satisfies V4Index; expect(transformPlaywrightJson(input)).toMatchInlineSnapshot(` { "example-header": "describe("Example/Header", () => { @@ -207,16 +209,14 @@ describe('Playwright Json', () => { id: 'example-introduction--page', title: 'Example/Introduction', name: 'Page', - importPath: './stories/basic/Introduction.stories.mdx', }, 'example-page--logged-in': { id: 'example-page--logged-in', title: 'Example/Page', name: 'Logged In', - importPath: './stories/basic/Page.stories.js', }, }, - }; + } satisfies V4Index; expect(transformPlaywrightJson(input)).toMatchInlineSnapshot(` { "example-page": "describe("Example/Page", () => { @@ -289,9 +289,6 @@ describe('Playwright Json', () => { id: 'example-header--logged-in', title: 'Example/Header', name: 'Logged In', - importPath: './stories/basic/Header.stories.js', - kind: 'Example/Header', - story: 'Logged In', parameters: { __id: 'example-header--logged-in', docsOnly: false, @@ -302,9 +299,6 @@ describe('Playwright Json', () => { id: 'example-header--logged-out', title: 'Example/Header', name: 'Logged Out', - importPath: './stories/basic/Header.stories.js', - kind: 'Example/Header', - story: 'Logged Out', parameters: { __id: 'example-header--logged-out', docsOnly: false, @@ -315,9 +309,6 @@ describe('Playwright Json', () => { id: 'example-page--logged-in', title: 'Example/Page', name: 'Logged In', - importPath: './stories/basic/Page.stories.js', - kind: 'Example/Page', - story: 'Logged In', parameters: { __id: 'example-page--logged-in', docsOnly: false, @@ -325,7 +316,7 @@ describe('Playwright Json', () => { }, }, }, - }; + } satisfies V3StoriesIndex; expect(transformPlaywrightJson(input)).toMatchInlineSnapshot(` { "example-header": "describe("Example/Header", () => { @@ -506,9 +497,6 @@ describe('Playwright Json', () => { id: 'example-introduction--page', title: 'Example/Introduction', name: 'Page', - importPath: './stories/basic/Introduction.stories.mdx', - kind: 'Example/Introduction', - story: 'Page', parameters: { __id: 'example-introduction--page', docsOnly: true, @@ -519,9 +507,6 @@ describe('Playwright Json', () => { id: 'example-page--logged-in', title: 'Example/Page', name: 'Logged In', - importPath: './stories/basic/Page.stories.js', - kind: 'Example/Page', - story: 'Logged In', parameters: { __id: 'example-page--logged-in', docsOnly: false, @@ -529,7 +514,7 @@ describe('Playwright Json', () => { }, }, }, - }; + } satisfies V3StoriesIndex; expect(transformPlaywrightJson(input)).toMatchInlineSnapshot(` { "example-page": "describe("Example/Page", () => { @@ -593,3 +578,12 @@ describe('Playwright Json', () => { }); }); }); + +describe('unsupported index', () => { + it('throws an error for unsupported versions', () => { + const unsupportedVersion = { v: 1 } satisfies UnsupportedVersion; + expect(() => transformPlaywrightJson(unsupportedVersion)).toThrowError( + `Unsupported version ${unsupportedVersion.v}` + ); + }); +}); diff --git a/src/playwright/transformPlaywrightJson.ts b/src/playwright/transformPlaywrightJson.ts index 0a6df337..45486ce6 100644 --- a/src/playwright/transformPlaywrightJson.ts +++ b/src/playwright/transformPlaywrightJson.ts @@ -5,14 +5,14 @@ import { ComponentTitle, StoryId, StoryName, toId } from '@storybook/csf'; import { testPrefixer } from './transformPlaywright'; const makeTest = (entry: V4Entry): t.Statement => { - const result: any = testPrefixer({ + const result = testPrefixer({ name: t.stringLiteral(entry.name), title: t.stringLiteral(entry.title), id: t.stringLiteral(entry.id), // FIXME storyExport: t.identifier(entry.id), }); - const stmt = result[1] as t.ExpressionStatement; + const stmt = (result as Array)[1]; return t.expressionStatement( t.callExpression(t.identifier('it'), [t.stringLiteral('test'), stmt.expression]) ); @@ -28,16 +28,23 @@ const makeDescribe = (title: string, stmts: t.Statement[]) => { }; type V4Entry = { type?: 'story' | 'docs'; id: StoryId; name: StoryName; title: ComponentTitle }; -type V4Index = { +export type V4Index = { v: 4; entries: Record; }; -type V3Story = Omit & { parameters?: Record }; -type V3StoriesIndex = { +type StoryParameters = { + __id: StoryId; + docsOnly?: boolean; + fileName?: string; +}; + +type V3Story = Omit & { parameters?: StoryParameters }; +export type V3StoriesIndex = { v: 3; stories: Record; }; +export type UnsupportedVersion = { v: number }; const isV3DocsOnly = (stories: V3Story[]) => stories.length === 1 && stories[0].name === 'Page'; function v3TitleMapToV4TitleMap(titleIdToStories: Record) { @@ -49,7 +56,7 @@ function v3TitleMapToV4TitleMap(titleIdToStories: Record) { ({ type: isV3DocsOnly(stories) ? 'docs' : 'story', ...story, - } as V4Entry) + } satisfies V4Entry) ), ]) ); @@ -68,7 +75,7 @@ function groupByTitleId(entries: T[]) { * Generate one test file per component so that Jest can * run them in parallel. */ -export const transformPlaywrightJson = (index: Record) => { +export const transformPlaywrightJson = (index: V3StoriesIndex | V4Index | UnsupportedVersion) => { let titleIdToEntries: Record; if (index.v === 3) { const titleIdToStories = groupByTitleId( diff --git a/src/setup-page.ts b/src/setup-page.ts index 6ed56703..6cc35de4 100644 --- a/src/setup-page.ts +++ b/src/setup-page.ts @@ -32,7 +32,7 @@ const sanitizeURL = (url: string) => { let finalURL = url; // prepend URL protocol if not there if (finalURL.indexOf('http://') === -1 && finalURL.indexOf('https://') === -1) { - finalURL = 'http://' + finalURL; + finalURL = `http://${finalURL}`; } // remove iframe.html if present @@ -42,8 +42,8 @@ const sanitizeURL = (url: string) => { finalURL = finalURL.replace(/index.html\s*$/, ''); // add forward slash at the end if not there - if (finalURL.slice(-1) !== '/') { - finalURL = finalURL + '/'; + if (!finalURL.endsWith('/')) { + finalURL = `${finalURL}/`; } return finalURL; @@ -53,7 +53,7 @@ export const setupPage = async (page: Page, browserContext: BrowserContext) => { const targetURL = process.env.TARGET_URL; const failOnConsole = process.env.TEST_CHECK_CONSOLE; - const viewMode = process.env.VIEW_MODE || 'story'; + const viewMode = process.env.VIEW_MODE ?? 'story'; const renderedEvent = viewMode === 'docs' ? 'docsRendered' : 'storyRendered'; const { packageJson } = (await readPackageUp()) as NormalizedReadResult; const { version: testRunnerVersion } = packageJson; @@ -72,9 +72,7 @@ export const setupPage = async (page: Page, browserContext: BrowserContext) => { const testRunnerConfig = getTestRunnerConfig(); if (testRunnerConfig?.prepare) { await testRunnerConfig.prepare({ page, browserContext, testRunnerConfig }); - } else { - if (testRunnerConfig) await defaultPrepare({ page, browserContext, testRunnerConfig }); - } + } else if (testRunnerConfig) await defaultPrepare({ page, browserContext, testRunnerConfig }); // if we ever want to log something from the browser to node await page.exposeBinding('logToPage', (_, message) => console.log(message)); @@ -247,7 +245,7 @@ export const setupPage = async (page: Page, browserContext: BrowserContext) => { constructor(storyId, errorMessage, logs = []) { super(errorMessage); this.name = 'StorybookTestRunnerError'; - const storyUrl = \`${referenceURL || targetURL}?path=/story/\${storyId}\`; + const storyUrl = \`${referenceURL ?? targetURL}?path=/story/\${storyId}\`; const finalStoryUrl = \`\${storyUrl}&addonPanel=storybook/interactions/panel\`; const separator = '\\n\\n--------------------------------------------------'; const extraLogs = logs.length > 0 ? separator + "\\n\\nBrowser logs:\\n\\n"+ logs.join('\\n\\n') : ''; diff --git a/src/test-storybook.ts b/src/test-storybook.ts index 665683b7..7a722e6b 100644 --- a/src/test-storybook.ts +++ b/src/test-storybook.ts @@ -1,5 +1,4 @@ #!/usr/bin/env node -'use strict'; import fs from 'fs'; import { execSync } from 'child_process'; @@ -9,10 +8,9 @@ import dedent from 'ts-dedent'; import path from 'path'; import tempy from 'tempy'; import semver from 'semver'; -import { detect as detectPackageManager, PM } from 'detect-package-manager'; +import { detect as detectPackageManager } from 'detect-package-manager'; -import { JestOptions } from './util/getCliOptions'; -import { getCliOptions } from './util/getCliOptions'; +import { JestOptions, getCliOptions } from './util/getCliOptions'; import { getStorybookMetadata } from './util/getStorybookMetadata'; import { getTestRunnerConfig } from './util/getTestRunnerConfig'; import { transformPlaywrightJson } from './playwright/transformPlaywrightJson'; @@ -135,7 +133,7 @@ function sanitizeURL(url: string) { let finalURL = url; // prepend URL protocol if not there if (finalURL.indexOf('http://') === -1 && finalURL.indexOf('https://') === -1) { - finalURL = 'http://' + finalURL; + finalURL = `http://${finalURL}`; } // remove iframe.html if present @@ -145,8 +143,8 @@ function sanitizeURL(url: string) { finalURL = finalURL.replace(/index.html\s*$/, ''); // add forward slash at the end if not there - if (finalURL.slice(-1) !== '/') { - finalURL = finalURL + '/'; + if (!finalURL.endsWith('/')) { + finalURL = `${finalURL}/`; } return finalURL; @@ -160,10 +158,10 @@ async function executeJestPlaywright(args: JestOptions) { }) ); const jest = require(jestPath); - let argv = args.slice(2); + const argv = args.slice(2); // jest configs could either come in the root dir, or inside of the Storybook config dir - const configDir = process.env.STORYBOOK_CONFIG_DIR || ''; + const configDir = process.env.STORYBOOK_CONFIG_DIR ?? ''; const [userDefinedJestConfig] = ( await Promise.all([ glob(path.join(configDir, 'test-runner-jest*'), { windowsPathsNoEscape: true }), @@ -180,7 +178,7 @@ async function executeJestPlaywright(args: JestOptions) { await jest.run(argv); } -async function checkStorybook(url: any) { +async function checkStorybook(url: string) { try { const headers = await getHttpHeaders(url); const res = await fetch(url, { method: 'HEAD', headers }); @@ -245,10 +243,10 @@ async function getIndexTempDir(url: string) { const titleIdToTest = transformPlaywrightJson(indexJson); tmpDir = tempy.directory(); - Object.entries(titleIdToTest).forEach(([titleId, test]) => { + for (const [titleId, test] of Object.entries(titleIdToTest)) { const tmpFile = path.join(tmpDir, `${titleId}.test.js`); - fs.writeFileSync(tmpFile, test as string); - }); + fs.writeFileSync(tmpFile, test); + } } catch (err) { const errorMessage = err instanceof Error ? err.message : String(err); const errorObject = new Error(errorMessage); @@ -287,7 +285,7 @@ const main = async () => { process.env.STORYBOOK_CONFIG_DIR = runnerOptions.configDir; - const testRunnerConfig = getTestRunnerConfig(runnerOptions.configDir) || {}; + const testRunnerConfig = getTestRunnerConfig(runnerOptions.configDir) ?? {}; if (testRunnerConfig.getHttpHeaders) { getHttpHeaders = testRunnerConfig.getHttpHeaders; } @@ -295,7 +293,7 @@ const main = async () => { // set this flag to skip reporting coverage in watch mode const isWatchMode = jestOptions.includes('--watch') || jestOptions.includes('--watchAll'); - const rawTargetURL = process.env.TARGET_URL || runnerOptions.url || 'http://127.0.0.1:6006'; + const rawTargetURL = process.env.TARGET_URL ?? runnerOptions.url ?? 'http://127.0.0.1:6006'; await checkStorybook(rawTargetURL); const targetURL = sanitizeURL(rawTargetURL); diff --git a/src/util/getCliOptions.test.ts b/src/util/getCliOptions.test.ts index df52cb7e..f0a5f99a 100644 --- a/src/util/getCliOptions.test.ts +++ b/src/util/getCliOptions.test.ts @@ -2,7 +2,7 @@ import { getCliOptions } from './getCliOptions'; import * as cliHelper from './getParsedCliOptions'; describe('getCliOptions', () => { - let originalArgv: string[] = process.argv; + const originalArgv: string[] = process.argv; afterEach(() => { process.argv = originalArgv; diff --git a/src/util/getCliOptions.ts b/src/util/getCliOptions.ts index 816e3018..2cfcca76 100644 --- a/src/util/getCliOptions.ts +++ b/src/util/getCliOptions.ts @@ -14,7 +14,7 @@ export type CliOptions = { junit?: boolean; browsers?: BrowserType | BrowserType[]; failOnConsole?: boolean; - }; + } & Record; jestOptions: JestOptions; }; @@ -49,20 +49,14 @@ export const getCliOptions = (): CliOptions => { }; const finalOptions = Object.keys(allOptions).reduce((acc: CliOptions, key: string) => { - if (STORYBOOK_RUNNER_COMMANDS.includes(key as StorybookRunnerCommand)) { - copyOption( - acc.runnerOptions, - key as StorybookRunnerCommand, - allOptions[key as StorybookRunnerCommand] - ); + if (STORYBOOK_RUNNER_COMMANDS.includes(key)) { + copyOption(acc.runnerOptions, key, allOptions[key]); + } else if (allOptions[key] === true) { + acc.jestOptions.push(`--${key}`); + } else if (allOptions[key] === false) { + acc.jestOptions.push(`--no-${key}`); } else { - if (allOptions[key as StorybookRunnerCommand] === true) { - acc.jestOptions.push(`--${key}`); - } else if (allOptions[key as StorybookRunnerCommand] === false) { - acc.jestOptions.push(`--no-${key}`); - } else { - acc.jestOptions.push(`--${key}="${allOptions[key as StorybookRunnerCommand]}"`); - } + acc.jestOptions.push(`--${key}="${allOptions[key]}"`); } return acc; diff --git a/src/util/getParsedCliOptions.test.ts b/src/util/getParsedCliOptions.test.ts index 3ee51258..6f34bd6a 100644 --- a/src/util/getParsedCliOptions.test.ts +++ b/src/util/getParsedCliOptions.test.ts @@ -44,7 +44,7 @@ describe('getParsedCliOptions', () => { console.warn = jest.fn(); const originalExit = process.exit; - process.exit = jest.fn() as any; + process.exit = jest.fn() as unknown as typeof process.exit; const argv = process.argv.slice(); process.argv.push('--unknown-option'); diff --git a/src/util/getStorybookMain.ts b/src/util/getStorybookMain.ts index 288bec0d..9726204d 100644 --- a/src/util/getStorybookMain.ts +++ b/src/util/getStorybookMain.ts @@ -3,7 +3,7 @@ import { serverRequire } from '@storybook/core-common'; import type { StorybookConfig } from '@storybook/types'; import dedent from 'ts-dedent'; -let storybookMainConfig = new Map(); +const storybookMainConfig = new Map(); export const getStorybookMain = (configDir: string) => { if (storybookMainConfig.has(configDir)) { diff --git a/src/util/getStorybookMetadata.ts b/src/util/getStorybookMetadata.ts index fd45b660..8e17857a 100644 --- a/src/util/getStorybookMetadata.ts +++ b/src/util/getStorybookMetadata.ts @@ -5,7 +5,7 @@ import { StoriesEntry } from '@storybook/types'; export const getStorybookMetadata = () => { const workingDir = getProjectRoot(); - const configDir = process.env.STORYBOOK_CONFIG_DIR || ''; + const configDir = process.env.STORYBOOK_CONFIG_DIR ?? ''; const main = getStorybookMain(configDir); const normalizedStoriesEntries = normalizeStories(main?.stories as StoriesEntry[], { @@ -17,7 +17,7 @@ export const getStorybookMetadata = () => { })); const storiesPaths = normalizedStoriesEntries - .map((entry) => entry.directory + '/' + entry.files) + .map((entry) => `${entry.directory}/${entry.files}`) .map((dir) => join(workingDir, dir)) .join(';'); diff --git a/src/util/getTestRunnerConfig.test.ts b/src/util/getTestRunnerConfig.test.ts index a59b9447..9934acd2 100644 --- a/src/util/getTestRunnerConfig.test.ts +++ b/src/util/getTestRunnerConfig.test.ts @@ -1,6 +1,5 @@ -import { serverRequire } from '@storybook/core-common'; import { TestRunnerConfig } from '../playwright/hooks'; -import { getTestRunnerConfig, loaded } from './getTestRunnerConfig'; +import { getTestRunnerConfig } from './getTestRunnerConfig'; import { join, resolve } from 'path'; const testRunnerConfig: TestRunnerConfig = { @@ -71,6 +70,6 @@ describe('getTestRunnerConfig', () => { }); afterEach(() => { - delete process.env.STORYBOOK_CONFIG_DIR; + process.env.STORYBOOK_CONFIG_DIR = undefined; }); }); diff --git a/src/util/getTestRunnerConfig.ts b/src/util/getTestRunnerConfig.ts index 78a28c18..64e3d0fe 100644 --- a/src/util/getTestRunnerConfig.ts +++ b/src/util/getTestRunnerConfig.ts @@ -6,7 +6,7 @@ let testRunnerConfig: TestRunnerConfig; let loaded = false; export const getTestRunnerConfig = ( - configDir = process.env.STORYBOOK_CONFIG_DIR || '' + configDir = process.env.STORYBOOK_CONFIG_DIR ?? '' ): TestRunnerConfig | undefined => { // testRunnerConfig can be undefined if (loaded) { diff --git a/tsconfig.json b/tsconfig.json index ddc1f0da..ba12020e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,7 +18,8 @@ "moduleResolution": "node", "strict": true, "noEmit": true, + "noUnusedLocals": true, + "noUnusedParameters": true, }, - "include": ["src/**/*.ts"], - "exclude": ["src/**/*.test.ts"] + "include": ["src/**/*.ts"] }