test: strengthen internal types (#7488)

This commit is contained in:
Joshua Chen 2022-05-25 15:38:44 +08:00 committed by GitHub
parent d50fe3b670
commit cd21a31005
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 67 additions and 55 deletions

13
jest/deps.d.ts vendored
View file

@ -7,9 +7,18 @@
// modules only used in tests // modules only used in tests
declare module 'to-vfile'; declare module 'to-vfile' {
import type {VFile} from 'vfile';
declare module 'remark-mdx'; export function read(path: string, encoding?: string): Promise<VFile>;
}
declare module 'remark-mdx' {
import type {Plugin} from 'unified';
const mdx: Plugin;
export = mdx;
}
declare module '@testing-utils/git' { declare module '@testing-utils/git' {
const createTempRepo: typeof import('./utils/git').createTempRepo; const createTempRepo: typeof import('./utils/git').createTempRepo;

View file

@ -10,8 +10,8 @@ import vfile from 'to-vfile';
import postcss from 'postcss'; import postcss from 'postcss';
import postCssRemoveOverriddenCustomProperties from '../index'; import postCssRemoveOverriddenCustomProperties from '../index';
const processFixture = (name: string) => { const processFixture = async (name: string) => {
const input = vfile.readSync( const input = await vfile.read(
path.join(__dirname, '__fixtures__', `${name}.css`), path.join(__dirname, '__fixtures__', `${name}.css`),
'utf8', 'utf8',
); );
@ -23,11 +23,11 @@ const processFixture = (name: string) => {
}; };
describe('remove-overridden-custom-properties', () => { describe('remove-overridden-custom-properties', () => {
it('overridden custom properties should be removed', () => { it('overridden custom properties should be removed', async () => {
expect(processFixture('normal')).toMatchSnapshot(); await expect(processFixture('normal')).resolves.toMatchSnapshot();
}); });
it('overridden custom properties with `!important` rule should not be removed', () => { it('overridden custom properties with `!important` rule should not be removed', async () => {
expect(processFixture('important_rule')).toMatchSnapshot(); await expect(processFixture('important_rule')).resolves.toMatchSnapshot();
}); });
}); });

View file

@ -552,7 +552,7 @@ async function migrateVersionedSidebar(
(topLevel: SidebarEntries, value) => { (topLevel: SidebarEntries, value) => {
const key = value[0].replace(versionRegex, ''); const key = value[0].replace(versionRegex, '');
topLevel[key] = Object.entries(value[1]).reduce<{ topLevel[key] = Object.entries(value[1]).reduce<{
[key: string]: Array<string | {[key: string]: unknown}>; [key: string]: (string | {[key: string]: unknown})[];
}>((acc, val) => { }>((acc, val) => {
acc[val[0].replace(versionRegex, '')] = ( acc[val[0].replace(versionRegex, '')] = (
val[1] as SidebarEntry[] val[1] as SidebarEntry[]

View file

@ -34,7 +34,7 @@ export type SidebarEntry =
export type SidebarEntries = { export type SidebarEntries = {
[key: string]: [key: string]:
| {[key: string]: unknown} | {[key: string]: unknown}
| Array<{[key: string]: unknown} | string>; | ({[key: string]: unknown} | string)[];
}; };
export type VersionTwoConfig = { export type VersionTwoConfig = {
@ -49,7 +49,7 @@ export type VersionTwoConfig = {
githubHost?: string; githubHost?: string;
onBrokenLinks: string; onBrokenLinks: string;
onBrokenMarkdownLinks: string; onBrokenMarkdownLinks: string;
plugins: Array<[string, {[key: string]: unknown}]>; plugins: [string, {[key: string]: unknown}][];
themes?: []; themes?: [];
presets: [[string, ClassicPresetEntries]]; presets: [[string, ClassicPresetEntries]];
themeConfig: { themeConfig: {
@ -58,17 +58,14 @@ export type VersionTwoConfig = {
logo?: { logo?: {
src?: string; src?: string;
}; };
items: Array<{[key: string]: unknown} | null>; items: ({[key: string]: unknown} | null)[];
}; };
image?: string; image?: string;
footer: { footer: {
links: Array<{ links: {
title: string; title: string;
items: Array<{ items: {label: string; to: string}[];
label: string; }[];
to: string;
}>;
}>;
copyright?: string; copyright?: string;
logo: { logo: {
src?: string; src?: string;
@ -104,26 +101,26 @@ export type VersionOneConfig = {
organizationName?: string; organizationName?: string;
projectName?: string; projectName?: string;
noIndex?: boolean; noIndex?: boolean;
headerLinks?: Array<{doc: string; href: string; label: string; page: string}>; headerLinks?: {doc: string; href: string; label: string; page: string}[];
headerIcon?: string; headerIcon?: string;
favicon?: string; favicon?: string;
colors?: {primaryColor: string}; colors?: {primaryColor: string};
copyright?: string; copyright?: string;
editUrl?: string; editUrl?: string;
customDocsPath?: string; customDocsPath?: string;
users?: Array<{[key: string]: unknown}>; users?: {[key: string]: unknown}[];
disableHeaderTitle?: string; disableHeaderTitle?: string;
disableTitleTagline?: string; disableTitleTagline?: string;
separateCss?: Array<{[key: string]: unknown}>; separateCss?: {[key: string]: unknown}[];
footerIcon?: string; footerIcon?: string;
translationRecruitingLink?: string; translationRecruitingLink?: string;
algolia?: {[key: string]: unknown}; algolia?: {[key: string]: unknown};
gaTrackingId?: string; gaTrackingId?: string;
gaGtag?: boolean; gaGtag?: boolean;
highlight?: {[key: string]: unknown}; highlight?: {[key: string]: unknown};
markdownPlugins?: Array<() => void>; markdownPlugins?: (() => void)[];
scripts?: Array<{src: string; [key: string]: unknown} | string>; scripts?: ({src: string; [key: string]: unknown} | string)[];
stylesheets?: Array<{href: string; [key: string]: unknown} | string>; stylesheets?: ({href: string; [key: string]: unknown} | string)[];
facebookAppId?: string; facebookAppId?: string;
facebookComments?: true; facebookComments?: true;
facebookPixelId?: string; facebookPixelId?: string;

View file

@ -31,6 +31,7 @@ import type {
Options, Options,
PluginOptions, PluginOptions,
PropSidebarItemLink, PropSidebarItemLink,
PropSidebars,
} from '@docusaurus/plugin-content-docs'; } from '@docusaurus/plugin-content-docs';
import type { import type {
SidebarItemsGeneratorOption, SidebarItemsGeneratorOption,
@ -82,7 +83,7 @@ const createFakeActions = (contentDir: string) => {
// Query by prefix, because files have a hash at the end so it's not // Query by prefix, because files have a hash at the end so it's not
// convenient to query by full filename // convenient to query by full filename
const getCreatedDataByPrefix = (prefix: string) => { function getCreatedDataByPrefix(prefix: string) {
const entry = Object.entries(dataContainer).find(([key]) => const entry = Object.entries(dataContainer).find(([key]) =>
key.startsWith(prefix), key.startsWith(prefix),
); );
@ -92,8 +93,8 @@ Entries created:
- ${Object.keys(dataContainer).join('\n- ')} - ${Object.keys(dataContainer).join('\n- ')}
`); `);
} }
return JSON.parse(entry[1] as string); return JSON.parse(entry[1] as string) as PropSidebars;
}; }
// Extra fns useful for tests! // Extra fns useful for tests!
const utils = { const utils = {
@ -571,8 +572,8 @@ describe('versioned website (community)', () => {
allContent: {}, allContent: {},
}); });
utils.checkVersionMetadataPropCreated(currentVersion!); utils.checkVersionMetadataPropCreated(currentVersion);
utils.checkVersionMetadataPropCreated(version100!); utils.checkVersionMetadataPropCreated(version100);
utils.expectSnapshot(); utils.expectSnapshot();
}); });

View file

@ -71,6 +71,6 @@ export class ReactContextError extends Error {
this.message = `Hook ${ this.message = `Hook ${
this.stack?.split('\n')[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups! this.stack?.split('\n')[1]?.match(/at (?:\w+\.)?(?<name>\w+)/)?.groups!
.name ?? '' .name ?? ''
} is called outside the <${providerName}>. ${additionalInfo || ''}`; } is called outside the <${providerName}>. ${additionalInfo ?? ''}`;
} }
} }

View file

@ -120,7 +120,9 @@ function DocSearch({
} }
return Promise.all([ return Promise.all([
import('@docsearch/react/modal'), import('@docsearch/react/modal') as Promise<
typeof import('@docsearch/react')
>,
import('@docsearch/react/style'), import('@docsearch/react/style'),
import('./styles.css'), import('./styles.css'),
]).then(([{DocSearchModal: Modal}]) => { ]).then(([{DocSearchModal: Modal}]) => {

View file

@ -42,7 +42,7 @@ describe('normalizePluginOptions', () => {
it('throws for invalid options', () => { it('throws for invalid options', () => {
const options = {foo: 1}; const options = {foo: 1};
expect(() => expect(() =>
normalizePluginOptions(Joi.object({foo: Joi.string()}), options), normalizePluginOptions(Joi.object<object>({foo: Joi.string()}), options),
).toThrowErrorMatchingInlineSnapshot(`""foo" must be a string"`); ).toThrowErrorMatchingInlineSnapshot(`""foo" must be a string"`);
}); });
@ -90,7 +90,10 @@ describe('normalizeThemeConfig', () => {
it('throws for invalid options', () => { it('throws for invalid options', () => {
const themeConfig = {foo: 1, bar: 1}; const themeConfig = {foo: 1, bar: 1};
expect(() => expect(() =>
normalizeThemeConfig(Joi.object({foo: Joi.string()}), themeConfig), normalizeThemeConfig(
Joi.object<object>({foo: Joi.string()}),
themeConfig,
),
).toThrowErrorMatchingInlineSnapshot(`""foo" must be a string"`); ).toThrowErrorMatchingInlineSnapshot(`""foo" must be a string"`);
}); });

View file

@ -35,7 +35,7 @@ class PendingNavigation extends React.Component<Props, State> {
? dispatchLifecycleAction('onRouteUpdate', { ? dispatchLifecycleAction('onRouteUpdate', {
previousLocation: null, previousLocation: null,
location: this.props.location, location: this.props.location,
})! })
: () => {}; : () => {};
this.state = { this.state = {
nextRouteHasLoaded: true, nextRouteHasLoaded: true,
@ -60,14 +60,14 @@ class PendingNavigation extends React.Component<Props, State> {
this.routeUpdateCleanupCb = dispatchLifecycleAction('onRouteUpdate', { this.routeUpdateCleanupCb = dispatchLifecycleAction('onRouteUpdate', {
previousLocation: this.previousLocation, previousLocation: this.previousLocation,
location: nextLocation, location: nextLocation,
})!; });
// Load data while the old screen remains. Force preload instead of using // Load data while the old screen remains. Force preload instead of using
// `window.docusaurus`, because we want to avoid loading screen even when // `window.docusaurus`, because we want to avoid loading screen even when
// user is on saveData // user is on saveData
preload(nextLocation.pathname) preload(nextLocation.pathname)
.then(() => { .then(() => {
this.routeUpdateCleanupCb?.(); this.routeUpdateCleanupCb();
this.setState({nextRouteHasLoaded: true}); this.setState({nextRouteHasLoaded: true});
}) })
.catch((e: unknown) => console.warn(e)); .catch((e: unknown) => console.warn(e));

View file

@ -69,7 +69,7 @@ This behavior can have SEO impacts and create relative link issues.
// The source branch; defaults to the currently checked out branch // The source branch; defaults to the currently checked out branch
const sourceBranch = const sourceBranch =
process.env.CURRENT_BRANCH || process.env.CURRENT_BRANCH ??
shell.exec('git rev-parse --abbrev-ref HEAD', {silent: true}).stdout.trim(); shell.exec('git rev-parse --abbrev-ref HEAD', {silent: true}).stdout.trim();
const gitUser = process.env.GIT_USER; const gitUser = process.env.GIT_USER;
@ -90,8 +90,8 @@ This behavior can have SEO impacts and create relative link issues.
} }
const organizationName = const organizationName =
process.env.ORGANIZATION_NAME || process.env.ORGANIZATION_NAME ??
process.env.CIRCLE_PROJECT_USERNAME || process.env.CIRCLE_PROJECT_USERNAME ??
siteConfig.organizationName; siteConfig.organizationName;
if (!organizationName) { if (!organizationName) {
throw new Error( throw new Error(
@ -101,8 +101,8 @@ This behavior can have SEO impacts and create relative link issues.
logger.info`organizationName: name=${organizationName}`; logger.info`organizationName: name=${organizationName}`;
const projectName = const projectName =
process.env.PROJECT_NAME || process.env.PROJECT_NAME ??
process.env.CIRCLE_PROJECT_REPONAME || process.env.CIRCLE_PROJECT_REPONAME ??
siteConfig.projectName; siteConfig.projectName;
if (!projectName) { if (!projectName) {
throw new Error( throw new Error(
@ -113,7 +113,7 @@ This behavior can have SEO impacts and create relative link issues.
// We never deploy on pull request. // We never deploy on pull request.
const isPullRequest = const isPullRequest =
process.env.CI_PULL_REQUEST || process.env.CIRCLE_PULL_REQUEST; process.env.CI_PULL_REQUEST ?? process.env.CIRCLE_PULL_REQUEST;
if (isPullRequest) { if (isPullRequest) {
shell.echo('Skipping deploy on a pull request.'); shell.echo('Skipping deploy on a pull request.');
shell.exit(0); shell.exit(0);
@ -136,12 +136,12 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
} }
const deploymentBranch = const deploymentBranch =
process.env.DEPLOYMENT_BRANCH || siteConfig.deploymentBranch || 'gh-pages'; process.env.DEPLOYMENT_BRANCH ?? siteConfig.deploymentBranch ?? 'gh-pages';
logger.info`deploymentBranch: name=${deploymentBranch}`; logger.info`deploymentBranch: name=${deploymentBranch}`;
const githubHost = const githubHost =
process.env.GITHUB_HOST || siteConfig.githubHost || 'github.com'; process.env.GITHUB_HOST ?? siteConfig.githubHost ?? 'github.com';
const githubPort = process.env.GITHUB_PORT || siteConfig.githubPort; const githubPort = process.env.GITHUB_PORT ?? siteConfig.githubPort;
let deploymentRepoURL: string; let deploymentRepoURL: string;
if (useSSH) { if (useSSH) {
@ -214,7 +214,7 @@ You can also set the deploymentBranch property in docusaurus.config.js .`);
shellExecLog('git add --all'); shellExecLog('git add --all');
const commitMessage = const commitMessage =
process.env.CUSTOM_COMMIT_MESSAGE || process.env.CUSTOM_COMMIT_MESSAGE ??
`Deploy website - based on ${currentCommit}`; `Deploy website - based on ${currentCommit}`;
const commitResults = shellExecLog(`git commit -m "${commitMessage}"`); const commitResults = shellExecLog(`git commit -m "${commitMessage}"`);
if ( if (

View file

@ -65,7 +65,7 @@ function createExitMock() {
}); });
// eslint-disable-next-line jest/require-top-level-describe // eslint-disable-next-line jest/require-top-level-describe
afterEach(async () => { afterEach(async () => {
mock?.mockRestore(); mock.mockRestore();
}); });
return { return {

View file

@ -28,7 +28,7 @@ describe('loadPlugins', () => {
name: 'test1', name: 'test1',
prop: 'a', prop: 'a',
async loadContent() { async loadContent() {
// Testing that plugin lifecycle is bound to the plugin instance // Testing that plugin lifecycle is bound to the instance
return this.prop; return this.prop;
}, },
async contentLoaded({content, actions}) { async contentLoaded({content, actions}) {

View file

@ -96,14 +96,14 @@ type SidebarGenerator = (generatorArgs: {
/** Useful metadata for the version this sidebar belongs to. */ /** Useful metadata for the version this sidebar belongs to. */
version: {contentPath: string; versionName: string}; version: {contentPath: string; versionName: string};
/** All the docs of that version (unfiltered). */ /** All the docs of that version (unfiltered). */
docs: Array<{ docs: {
id: string; id: string;
title: string; title: string;
frontMatter: DocFrontMatter & Record<string, unknown>; frontMatter: DocFrontMatter & Record<string, unknown>;
source: string; source: string;
sourceDirName: string; sourceDirName: string;
sidebarPosition?: number | undefined; sidebarPosition?: number | undefined;
}>; }[];
/** Number prefix parser configured for this plugin. */ /** Number prefix parser configured for this plugin. */
numberPrefixParser: PrefixParser; numberPrefixParser: PrefixParser;
/** The default category index matcher which you can override. */ /** The default category index matcher which you can override. */

View file

@ -112,8 +112,8 @@ Turn debug mode on:
### `offlineModeActivationStrategies` {#offlinemodeactivationstrategies} ### `offlineModeActivationStrategies` {#offlinemodeactivationstrategies}
- Type: `Array<'appInstalled' | 'mobile' | 'saveData'| 'queryString' | 'always'>` - Type: `('appInstalled' | 'mobile' | 'saveData'| 'queryString' | 'always')[]`
- Default: `['appInstalled','queryString','standalone']` - Default: `['appInstalled', 'queryString', 'standalone']`
Strategies used to turn the offline mode on: Strategies used to turn the offline mode on:
@ -194,7 +194,7 @@ The default theme includes an implementation for the reload popup and uses [Infi
### `pwaHead` {#pwahead} ### `pwaHead` {#pwahead}
- Type: `Array<{ tagName: string } & Record<string,string>>` - Type: `({ tagName: string; [attributeName: string]: string })[]`
- Default: `[]` - Default: `[]`
Array of objects containing `tagName` and key-value pairs for attributes to inject into the `<head>` tag. Technically you can inject any head tag through this, but it's ideally used for tags to make your site PWA compliant. Here's a list of tag to make your app fully compliant: Array of objects containing `tagName` and key-value pairs for attributes to inject into the `<head>` tag. Technically you can inject any head tag through this, but it's ideally used for tags to make your site PWA compliant. Here's a list of tag to make your app fully compliant:

View file

@ -83,11 +83,11 @@ import TOCInline from '@theme/TOCInline';
The `toc` global is just a list of heading items: The `toc` global is just a list of heading items:
```ts ```ts
declare const toc: Array<{ declare const toc: {
value: string; value: string;
id: string; id: string;
level: number; level: number;
}>; }[];
``` ```
Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree. Note that the `toc` global is a flat array, so you can easily cut out unwanted nodes or insert extra nodes, and create a new TOC tree.