如何用ESLint的no-restricted-syntax禁止在it/test外使用screen?
ESLint
no-restricted-syntax规则配置问题:禁止it()/test()块外使用screen 问题描述
我正尝试配置ESLint的no-restricted-syntax规则,此前未成功实现禁止screen.findByX不配合await使用的需求,现在有另一个场景:需要禁止在it()/test()块外使用screen——因为JSDOM环境是全局共享的,在外部渲染会导致DOM清理问题。
示例代码(希望其中的screen调用触发ESLint报错):
beforeEach(async() => { render(<MyLovelyComponent />); await waitForElementToBeRemoved(() => screen.getAllByText('dddd')); });
我编写的规则配置如下,但并未生效:
'no-restricted-syntax':[ 'error', { message: 'No screen outside of it', selector: `FunctionCall[name!="it"] MemberExpression[object.name="screen"]` }, ],
问题原因与解决方案
原配置的问题
原选择器FunctionCall[name!="it"] MemberExpression[object.name="screen"]存在两个核心缺陷:
- 匹配范围过窄:仅能匹配直接作为非
it函数调用的直接子节点的screen调用,无法处理多层嵌套的情况(比如示例中screen嵌套在waitForElementToBeRemoved的回调函数里)。 - 覆盖场景不全:未考虑
test函数(多数测试框架中test与it等价),也未处理箭头函数、普通函数作为it/test回调的嵌套结构。
正确的规则配置
可以通过AST选择器的否定逻辑,匹配所有screen的成员表达式调用,同时排除位于it()/test()回调内部的情况:
写法一(紧凑版)
'no-restricted-syntax': [ 'error', { message: '禁止在it()/test()块外使用screen', selector: 'MemberExpression[object.name="screen"]:not(:matches(FunctionExpression[parent.type="CallExpression"][parent.callee.name=/^(it|test)$/]), ArrowFunctionExpression[parent.type="CallExpression"][parent.callee.name=/^(it|test)$/])' } ]
写法二(易读版)
'no-restricted-syntax': [ 'error', { message: '禁止在it()/test()块外使用screen', selector: ` MemberExpression[object.name="screen"] :not( :has( ancestor CallExpression[callee.name=/^(it|test)$/] ) ) ` } ]
配置说明
- 选择器
MemberExpression[object.name="screen"]匹配所有screen.xxx()形式的调用。 :not(:has(ancestor CallExpression[callee.name=/^(it|test)$/]))用于排除那些上层作用域属于it()或test()函数回调的调用,无论嵌套多少层函数,只要归属于it/test的作用域,就不会触发报错。
内容的提问来源于stack exchange,提问作者AncientSwordRage
相关产品推荐
相关产品推荐

