Skip to content

feat(no-await-sync-queries): add auto-fix #919

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 10 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
@@ -299,7 +299,7 @@ module.exports = [
| [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][] | | |
| [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][] | | 🔧 |
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are some conflicts here, can you resolve that @neriyarde?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks.

Im getting some type errors in these files when im trying to solve the conflicts:

  • lib/create-testing-library-rule/index.ts
  • lib/rules/await-async-utils.ts
  • tools/generate-configs/utils.ts
  • lib/utils/types.ts
  • lib/utils/compat.ts

I don't remember doing any changes in these files but i still get type errors.

Since I don't know these changes and i don't want to break anythig, can I get some help solving these from someone who's familiar with these files and type?

| [no-container](docs/rules/no-container.md) | Disallow the use of `container` methods | ![badge-angular][] ![badge-marko][] ![badge-react][] ![badge-vue][] | | |
| [no-debugging-utils](docs/rules/no-debugging-utils.md) | Disallow the use of debugging utilities like `debug` | | ![badge-angular][] ![badge-marko][] ![badge-react][] ![badge-vue][] | |
| [no-dom-import](docs/rules/no-dom-import.md) | Disallow importing from DOM Testing Library | ![badge-angular][] ![badge-marko][] ![badge-react][] ![badge-vue][] | | 🔧 |
2 changes: 2 additions & 0 deletions docs/rules/no-await-sync-queries.md
Original file line number Diff line number Diff line change
@@ -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 sync queries are not awaited unnecessarily.
Original file line number Diff line number Diff line change
@@ -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;
@@ -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>,
@@ -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> = {}
2 changes: 1 addition & 1 deletion lib/create-testing-library-rule/index.ts
Original file line number Diff line number Diff line change
@@ -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 = {},
2 changes: 1 addition & 1 deletion lib/rules/await-async-events.ts
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ type EventModules = (typeof EVENTS_SIMULATORS)[number];
export type Options = [
{
eventModule: EventModules | EventModules[];
},
}
];

export default createTestingLibraryRule<Options, MessageIds>({
2 changes: 1 addition & 1 deletion lib/rules/consistent-data-testid.ts
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ export type Options = [
testIdAttribute?: string[] | string;
testIdPattern: string;
customMessage?: string;
},
}
];

const FILENAME_PLACEHOLDER = '{fileName}';
18 changes: 16 additions & 2 deletions lib/rules/no-await-sync-queries.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TSESTree } from '@typescript-eslint/utils';
import { ASTUtils, TSESTree } from '@typescript-eslint/utils';

import { createTestingLibraryRule } from '../create-testing-library-rule';
import { getDeepestIdentifierNode } from '../node-utils';
@@ -26,15 +26,20 @@ export default createTestingLibraryRule<Options, MessageIds>({
'`{{ name }}` query is sync so it does not need to be awaited',
},
schema: [],
fixable: 'code',
},
defaultOptions: [],

create(context, _, helpers) {
return {
'AwaitExpression > CallExpression'(node: TSESTree.CallExpression) {
const awaitExpression = node.parent;
const deepestIdentifierNode = getDeepestIdentifierNode(node);

if (!deepestIdentifierNode) {
if (
!ASTUtils.isAwaitExpression(awaitExpression) ||
!deepestIdentifierNode
) {
return;
}

@@ -45,6 +50,15 @@ export default createTestingLibraryRule<Options, MessageIds>({
data: {
name: deepestIdentifierNode.name,
},
fix: (fixer) => {
const awaitRangeStart = awaitExpression.range[0];
const awaitRangeEnd = awaitExpression.range[0] + 'await'.length;

return fixer.replaceTextRange(
[awaitRangeStart, awaitRangeEnd],
''
);
},
});
}
},
2 changes: 1 addition & 1 deletion lib/rules/no-render-in-lifecycle.ts
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ export type MessageIds = 'noRenderInSetup';
type Options = [
{
allowTestingFrameworkSetupHook?: string;
},
}
];

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

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

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

export default createTestingLibraryRule<Options, MessageIds>({
2 changes: 1 addition & 1 deletion lib/utils/compat.ts
Original file line number Diff line number Diff line change
@@ -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.
2 changes: 1 addition & 1 deletion lib/utils/types.ts
Original file line number Diff line number Diff line change
@@ -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>;
};
2 changes: 1 addition & 1 deletion tests/create-testing-library-rule.test.ts
Original file line number Diff line number Diff line change
@@ -459,7 +459,7 @@ ruleTester.run(RULE_NAME, rule, {
messageId: 'renderError',
},
],
}) as const
} as const)
),
{
code: `
4 changes: 2 additions & 2 deletions tests/lib/FlatCompatRuleTester.ts
Original file line number Diff line number Diff line change
@@ -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>,
@@ -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;
44 changes: 22 additions & 22 deletions tests/lib/rules/await-async-events.test.ts
Original file line number Diff line number Diff line change
@@ -427,7 +427,7 @@ ruleTester.run(RULE_NAME, rule, {
await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -448,7 +448,7 @@ ruleTester.run(RULE_NAME, rule, {
],
options: [{ eventModule: 'fireEvent' }],
output: null,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -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) =>
@@ -508,7 +508,7 @@ ruleTester.run(RULE_NAME, rule, {
await testingLibraryFireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -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) =>
@@ -569,7 +569,7 @@ ruleTester.run(RULE_NAME, rule, {
await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -598,7 +598,7 @@ ruleTester.run(RULE_NAME, rule, {
await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -631,7 +631,7 @@ ruleTester.run(RULE_NAME, rule, {
await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -664,7 +664,7 @@ ruleTester.run(RULE_NAME, rule, {
await fireEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),

...FIRE_EVENT_ASYNC_FUNCTIONS.map(
@@ -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) =>
@@ -731,7 +731,7 @@ ruleTester.run(RULE_NAME, rule, {
await triggerEvent()
})
`,
}) as const
} as const)
),
...FIRE_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -756,7 +756,7 @@ ruleTester.run(RULE_NAME, rule, {
],
options: [{ eventModule: 'fireEvent' }],
output: null,
}) as const
} as const)
),
]),
...USER_EVENT_ASYNC_FRAMEWORKS.flatMap((testingFramework) => [
@@ -785,7 +785,7 @@ ruleTester.run(RULE_NAME, rule, {
await userEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -806,7 +806,7 @@ ruleTester.run(RULE_NAME, rule, {
],
options: [{ eventModule: 'userEvent' }],
output: null,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -833,7 +833,7 @@ ruleTester.run(RULE_NAME, rule, {
await testingLibraryUserEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -867,7 +867,7 @@ ruleTester.run(RULE_NAME, rule, {
await userEvent.${eventMethod}(getByLabelText('username'))
})
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -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) =>
@@ -933,7 +933,7 @@ ruleTester.run(RULE_NAME, rule, {
await triggerEvent()
})
`,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -958,7 +958,7 @@ ruleTester.run(RULE_NAME, rule, {
],
options: [{ eventModule: 'userEvent' }],
output: null,
}) as const
} as const)
),
...USER_EVENT_ASYNC_FUNCTIONS.map(
(eventMethod) =>
@@ -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) =>
@@ -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) =>
@@ -1044,7 +1044,7 @@ ruleTester.run(RULE_NAME, rule, {
await (await userEvent.${eventMethod}(getByLabelText('username')), null);
});
`,
}) as const
} as const)
),
]),
{
Loading