Skip to content

feat(await-async-utils): add auto-fix #918

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ module.exports = [
| :------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------- | :------------------------------------------------------------------ | :-- |
| [await-async-events](docs/rules/await-async-events.md) | Enforce promises from async event methods are handled | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-vue][] | | 🔧 |
| [await-async-queries](docs/rules/await-async-queries.md) | Enforce promises from async queries to be handled | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-vue][] | | |
| [await-async-utils](docs/rules/await-async-utils.md) | Enforce promises from async utils to be awaited properly | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-vue][] | | |
| [await-async-utils](docs/rules/await-async-utils.md) | Enforce promises from async utils to be awaited properly | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-vue][] | | 🔧 |
| [consistent-data-testid](docs/rules/consistent-data-testid.md) | Ensures consistent usage of `data-testid` | | | |
| [no-await-sync-events](docs/rules/no-await-sync-events.md) | Disallow unnecessary `await` for sync events | ![badge-angular][] ![badge-dom][] ![badge-react][] | | |
| [no-await-sync-queries](docs/rules/no-await-sync-queries.md) | Disallow unnecessary `await` for sync queries | ![badge-angular][] ![badge-dom][] ![badge-marko][] ![badge-react][] ![badge-vue][] | | |
Expand Down
2 changes: 2 additions & 0 deletions docs/rules/await-async-utils.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

💼 This rule is enabled in the following configs: `angular`, `dom`, `marko`, `react`, `vue`.

🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).

<!-- end auto-generated rule header -->

Ensure that promises returned by async utils are handled properly.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export type TestingLibrarySettings = {

export type TestingLibraryContext<
TOptions extends readonly unknown[],
TMessageIds extends string,
TMessageIds extends string
> = Readonly<
TSESLint.RuleContext<TMessageIds, TOptions> & {
settings: TestingLibrarySettings;
Expand All @@ -45,7 +45,7 @@ export type TestingLibraryContext<
export type EnhancedRuleCreate<
TOptions extends readonly unknown[],
TMessageIds extends string,
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener,
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener
> = (
context: TestingLibraryContext<TOptions, TMessageIds>,
optionsWithDefault: Readonly<TOptions>,
Expand Down Expand Up @@ -156,7 +156,7 @@ export type DetectionOptions = {
export function detectTestingLibraryUtils<
TOptions extends readonly unknown[],
TMessageIds extends string,
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener,
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener
>(
ruleCreate: EnhancedRuleCreate<TOptions, TMessageIds, TRuleListener>,
{ skipRuleReportingCheck = false }: Partial<DetectionOptions> = {}
Expand Down
2 changes: 1 addition & 1 deletion lib/create-testing-library-rule/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
export function createTestingLibraryRule<
TOptions extends readonly unknown[],
TMessageIds extends string,
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener,
TRuleListener extends TSESLint.RuleListener = TSESLint.RuleListener
>({
create,
detectionOptions = {},
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/await-async-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type EventModules = (typeof EVENTS_SIMULATORS)[number];
export type Options = [
{
eventModule: EventModules | EventModules[];
},
}
];

export default createTestingLibraryRule<Options, MessageIds>({
Expand Down
11 changes: 11 additions & 0 deletions lib/rules/await-async-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getFunctionName,
getInnermostReturningFunction,
getVariableReferences,
isMemberExpression,
isObjectPattern,
isPromiseHandled,
isProperty,
Expand Down Expand Up @@ -36,6 +37,7 @@ export default createTestingLibraryRule<Options, MessageIds>({
'Promise returned from {{ name }} wrapper over async util must be handled',
},
schema: [],
fixable: 'code',
},
defaultOptions: [],

Expand Down Expand Up @@ -149,6 +151,12 @@ export default createTestingLibraryRule<Options, MessageIds>({
data: {
name: node.name,
},
fix: (fixer) => {
if (isMemberExpression(node.parent)) {
return fixer.insertTextBefore(node.parent, 'await ');
}
return fixer.insertTextBefore(node, 'await ');
},
});
}
} else {
Expand All @@ -161,6 +169,9 @@ export default createTestingLibraryRule<Options, MessageIds>({
data: {
name: node.name,
},
fix: (fixer) => {
return fixer.insertTextBefore(referenceNode, 'await ');
},
});
return;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/consistent-data-testid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type Options = [
testIdAttribute?: string[] | string;
testIdPattern: string;
customMessage?: string;
},
}
];

const FILENAME_PLACEHOLDER = '{fileName}';
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-render-in-lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type MessageIds = 'noRenderInSetup';
type Options = [
{
allowTestingFrameworkSetupHook?: string;
},
}
];

export function findClosestBeforeHook(
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/prefer-explicit-assert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type Options = [
{
assertion?: string;
includeFindQueries?: boolean;
},
}
];

const isAtTopLevel = (node: TSESTree.Node) =>
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/prefer-presence-queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type Options = [
{
presence?: boolean;
absence?: boolean;
},
}
];

export default createTestingLibraryRule<Options, MessageIds>({
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/prefer-query-matchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type Options = [
query: 'get' | 'query';
matcher: string;
}[];
},
}
];

export default createTestingLibraryRule<Options, MessageIds>({
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/compat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ declare module '@typescript-eslint/utils/dist/ts-eslint/Rule' {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
TMessageIds extends string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
TOptions extends readonly unknown[],
TOptions extends readonly unknown[]
> {
/**
* The filename associated with the source.
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export type TestingLibraryRuleMetaDocs<TOptions extends readonly unknown[]> =
};
export type TestingLibraryRuleMeta<
TMessageIds extends string,
TOptions extends readonly unknown[],
TOptions extends readonly unknown[]
> = Omit<TSESLint.RuleMetaData<TMessageIds>, 'docs'> & {
docs: TestingLibraryRuleMetaDocs<TOptions>;
};
Expand Down
2 changes: 1 addition & 1 deletion tests/create-testing-library-rule.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ ruleTester.run(RULE_NAME, rule, {
messageId: 'renderError',
},
],
}) as const
} as const)
),
{
code: `
Expand Down
4 changes: 2 additions & 2 deletions tests/lib/FlatCompatRuleTester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export class FlatCompatRuleTester extends TSESLint.RuleTester {

public override run<
TMessageIds extends string,
TOptions extends readonly unknown[],
TOptions extends readonly unknown[]
>(
ruleName: string,
rule: TSESLint.RuleModule<TMessageIds, TOptions>,
Expand All @@ -141,7 +141,7 @@ export class FlatCompatRuleTester extends TSESLint.RuleTester {
| TSESLint.RuleTesterConfig
| string
| TSESLint.ValidTestCase<unknown[]>
| TSESLint.InvalidTestCase<string, unknown[]>,
| TSESLint.InvalidTestCase<string, unknown[]>
>(config: T): T {
if (!config || !usingFlatConfig || typeof config === 'string') {
return config;
Expand Down
44 changes: 22 additions & 22 deletions tests/lib/rules/await-async-events.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ ruleTester.run(RULE_NAME, rule, {
await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand All @@ -448,7 +448,7 @@ ruleTester.run(RULE_NAME, rule, {
],
options: [{ eventModule: 'fireEvent' }],
output: null,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand Down Expand Up @@ -481,7 +481,7 @@ ruleTester.run(RULE_NAME, rule, {

test('should handle external function', run)
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand All @@ -508,7 +508,7 @@ ruleTester.run(RULE_NAME, rule, {
await testingLibraryFireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand All @@ -535,7 +535,7 @@ ruleTester.run(RULE_NAME, rule, {
await testingLibrary.fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand Down Expand Up @@ -569,7 +569,7 @@ ruleTester.run(RULE_NAME, rule, {
await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand Down Expand Up @@ -598,7 +598,7 @@ ruleTester.run(RULE_NAME, rule, {
await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand Down Expand Up @@ -631,7 +631,7 @@ ruleTester.run(RULE_NAME, rule, {
await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand Down Expand Up @@ -664,7 +664,7 @@ ruleTester.run(RULE_NAME, rule, {
await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),

...FIRE_EVENT_ASYNC_FUNCTIONS.map(
Expand Down Expand Up @@ -695,7 +695,7 @@ ruleTester.run(RULE_NAME, rule, {
const promise = await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand Down Expand Up @@ -731,7 +731,7 @@ ruleTester.run(RULE_NAME, rule, {
await triggerEvent()
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand All @@ -756,7 +756,7 @@ ruleTester.run(RULE_NAME, rule, {
],
options: [{ eventModule: 'fireEvent' }],
output: null,
}) as const
} as const)
),
]),
...USER_EVENT_ASYNC_FRAMEWORKS.flatMap((testingFramework) => [
Expand Down Expand Up @@ -785,7 +785,7 @@ ruleTester.run(RULE_NAME, rule, {
await userEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand All @@ -806,7 +806,7 @@ ruleTester.run(RULE_NAME, rule, {
],
options: [{ eventModule: 'userEvent' }],
output: null,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand All @@ -833,7 +833,7 @@ ruleTester.run(RULE_NAME, rule, {
await testingLibraryUserEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand Down Expand Up @@ -867,7 +867,7 @@ ruleTester.run(RULE_NAME, rule, {
await userEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand Down Expand Up @@ -897,7 +897,7 @@ ruleTester.run(RULE_NAME, rule, {
const promise = await userEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand Down Expand Up @@ -933,7 +933,7 @@ ruleTester.run(RULE_NAME, rule, {
await triggerEvent()
})
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand All @@ -958,7 +958,7 @@ ruleTester.run(RULE_NAME, rule, {
],
options: [{ eventModule: 'userEvent' }],
output: null,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand All @@ -984,7 +984,7 @@ ruleTester.run(RULE_NAME, rule, {
condition ? null : (null, true && await userEvent.${eventMethod}(getByLabelText('username')));
});
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand All @@ -1010,7 +1010,7 @@ ruleTester.run(RULE_NAME, rule, {
await (await userEvent.${eventMethod}(getByLabelText('username')) && userEvent.${eventMethod}(getByLabelText('username')));
});
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
Expand Down Expand Up @@ -1044,7 +1044,7 @@ ruleTester.run(RULE_NAME, rule, {
await (await userEvent.${eventMethod}(getByLabelText('username')), null);
});
`,
}) as const
} as const)
),
]),
{
Expand Down
Loading