eslint-plugin-playwright 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +68 -27
- package/dist/index.mjs +71 -28
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -238,7 +238,7 @@ function parse(context, node) {
|
|
|
238
238
|
return null;
|
|
239
239
|
}
|
|
240
240
|
let type = group;
|
|
241
|
-
if ((name === "test" || name === "describe") && (node.arguments.length
|
|
241
|
+
if ((name === "test" || name === "describe") && (node.arguments.length < 2 || !isFunction(node.arguments.at(-1)))) {
|
|
242
242
|
type = "config";
|
|
243
243
|
}
|
|
244
244
|
return {
|
|
@@ -1515,9 +1515,7 @@ var no_standalone_expect_default = {
|
|
|
1515
1515
|
CallExpression(node) {
|
|
1516
1516
|
const call = parseFnCall(context, node);
|
|
1517
1517
|
if (call?.type === "expect") {
|
|
1518
|
-
if (getParent(call.head.node)?.type === "MemberExpression" && call.members.length === 1
|
|
1519
|
-
getStringValue(call.members[0])
|
|
1520
|
-
)) {
|
|
1518
|
+
if (getParent(call.head.node)?.type === "MemberExpression" && call.members.length === 1) {
|
|
1521
1519
|
return;
|
|
1522
1520
|
}
|
|
1523
1521
|
const parent = callStack.at(-1);
|
|
@@ -1749,14 +1747,44 @@ function replaceAccessorFixer(fixer, node, text) {
|
|
|
1749
1747
|
text
|
|
1750
1748
|
);
|
|
1751
1749
|
}
|
|
1750
|
+
function removePropertyFixer(fixer, property) {
|
|
1751
|
+
const parent = getParent(property);
|
|
1752
|
+
if (parent?.type !== "ObjectExpression")
|
|
1753
|
+
return;
|
|
1754
|
+
if (parent.properties.length === 1) {
|
|
1755
|
+
return fixer.remove(parent);
|
|
1756
|
+
}
|
|
1757
|
+
const index2 = parent.properties.indexOf(property);
|
|
1758
|
+
const range = index2 ? [parent.properties[index2 - 1].range[1], property.range[1]] : [property.range[0], parent.properties[1].range[0]];
|
|
1759
|
+
return fixer.removeRange(range);
|
|
1760
|
+
}
|
|
1752
1761
|
|
|
1753
1762
|
// src/rules/no-useless-not.ts
|
|
1754
|
-
var
|
|
1755
|
-
toBeDisabled: "toBeEnabled",
|
|
1756
|
-
toBeEnabled:
|
|
1757
|
-
|
|
1758
|
-
|
|
1763
|
+
var matcherConfig = {
|
|
1764
|
+
toBeDisabled: { inverse: "toBeEnabled" },
|
|
1765
|
+
toBeEnabled: {
|
|
1766
|
+
argName: "enabled",
|
|
1767
|
+
inverse: "toBeDisabled"
|
|
1768
|
+
},
|
|
1769
|
+
toBeHidden: { inverse: "toBeVisible" },
|
|
1770
|
+
toBeVisible: {
|
|
1771
|
+
argName: "visible",
|
|
1772
|
+
inverse: "toBeHidden"
|
|
1773
|
+
}
|
|
1759
1774
|
};
|
|
1775
|
+
function getOptions(call, name) {
|
|
1776
|
+
const [arg] = call.matcherArgs;
|
|
1777
|
+
if (arg?.type !== "ObjectExpression")
|
|
1778
|
+
return;
|
|
1779
|
+
const property = arg.properties.find(
|
|
1780
|
+
(p) => p.type === "Property" && getStringValue(p.key) === name && isBooleanLiteral(p.value)
|
|
1781
|
+
);
|
|
1782
|
+
return {
|
|
1783
|
+
arg,
|
|
1784
|
+
property,
|
|
1785
|
+
value: property?.value?.value
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1760
1788
|
var no_useless_not_default = {
|
|
1761
1789
|
create(context) {
|
|
1762
1790
|
return {
|
|
@@ -1764,30 +1792,41 @@ var no_useless_not_default = {
|
|
|
1764
1792
|
const call = parseFnCall(context, node);
|
|
1765
1793
|
if (call?.type !== "expect")
|
|
1766
1794
|
return;
|
|
1795
|
+
const config = matcherConfig[call.matcherName];
|
|
1796
|
+
if (!config)
|
|
1797
|
+
return;
|
|
1798
|
+
const options = config.argName ? getOptions(call, config.argName) : void 0;
|
|
1799
|
+
if (options?.arg && options.value === void 0)
|
|
1800
|
+
return;
|
|
1767
1801
|
const notModifier = call.modifiers.find(
|
|
1768
1802
|
(mod) => getStringValue(mod) === "not"
|
|
1769
1803
|
);
|
|
1770
|
-
if (!notModifier)
|
|
1804
|
+
if (!notModifier && !options?.property)
|
|
1771
1805
|
return;
|
|
1772
|
-
const
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1806
|
+
const isInverted = !!notModifier !== (options?.value === false);
|
|
1807
|
+
const newMatcherName = isInverted ? config.inverse : call.matcherName;
|
|
1808
|
+
context.report({
|
|
1809
|
+
data: {
|
|
1810
|
+
new: newMatcherName,
|
|
1811
|
+
old: call.matcherName,
|
|
1812
|
+
property: config.argName ?? ""
|
|
1813
|
+
},
|
|
1814
|
+
fix: (fixer) => {
|
|
1815
|
+
return [
|
|
1816
|
+
// Remove the `not` modifier if it exists
|
|
1817
|
+
notModifier && fixer.removeRange([
|
|
1779
1818
|
notModifier.range[0] - getRangeOffset(notModifier),
|
|
1780
1819
|
notModifier.range[1] + 1
|
|
1781
1820
|
]),
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
}
|
|
1821
|
+
// Remove the `visible` or `enabled` property if it exists
|
|
1822
|
+
options?.property && removePropertyFixer(fixer, options.property),
|
|
1823
|
+
// Swap the matcher name if it's different
|
|
1824
|
+
call.matcherName !== newMatcherName && replaceAccessorFixer(fixer, call.matcher, newMatcherName)
|
|
1825
|
+
].filter(truthy);
|
|
1826
|
+
},
|
|
1827
|
+
loc: notModifier ? { end: call.matcher.loc.end, start: notModifier.loc.start } : options.property.loc,
|
|
1828
|
+
messageId: notModifier ? "noUselessNot" : isInverted ? "noUselessProperty" : "noUselessTruthy"
|
|
1829
|
+
});
|
|
1791
1830
|
}
|
|
1792
1831
|
};
|
|
1793
1832
|
},
|
|
@@ -1800,7 +1839,9 @@ var no_useless_not_default = {
|
|
|
1800
1839
|
},
|
|
1801
1840
|
fixable: "code",
|
|
1802
1841
|
messages: {
|
|
1803
|
-
noUselessNot: "Unexpected usage of not.{{old}}(). Use {{new}}() instead."
|
|
1842
|
+
noUselessNot: "Unexpected usage of not.{{old}}(). Use {{new}}() instead.",
|
|
1843
|
+
noUselessProperty: "Unexpected usage of '{{old}}({ {{property}}: false })'. Use '{{new}}()' instead.",
|
|
1844
|
+
noUselessTruthy: "Unexpected usage of '{{old}}({ {{property}}: true })'. Use '{{new}}()' instead."
|
|
1804
1845
|
},
|
|
1805
1846
|
type: "problem"
|
|
1806
1847
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -86,7 +86,7 @@ function parse(context, node) {
|
|
|
86
86
|
return null;
|
|
87
87
|
}
|
|
88
88
|
let type = group;
|
|
89
|
-
if ((name === "test" || name === "describe") && (node.arguments.length
|
|
89
|
+
if ((name === "test" || name === "describe") && (node.arguments.length < 2 || !isFunction(node.arguments.at(-1)))) {
|
|
90
90
|
type = "config";
|
|
91
91
|
}
|
|
92
92
|
return {
|
|
@@ -1671,9 +1671,7 @@ var init_no_standalone_expect = __esm({
|
|
|
1671
1671
|
CallExpression(node) {
|
|
1672
1672
|
const call = parseFnCall(context, node);
|
|
1673
1673
|
if (call?.type === "expect") {
|
|
1674
|
-
if (getParent(call.head.node)?.type === "MemberExpression" && call.members.length === 1
|
|
1675
|
-
getStringValue(call.members[0])
|
|
1676
|
-
)) {
|
|
1674
|
+
if (getParent(call.head.node)?.type === "MemberExpression" && call.members.length === 1) {
|
|
1677
1675
|
return;
|
|
1678
1676
|
}
|
|
1679
1677
|
const parent = callStack.at(-1);
|
|
@@ -1927,27 +1925,59 @@ function replaceAccessorFixer(fixer, node, text) {
|
|
|
1927
1925
|
text
|
|
1928
1926
|
);
|
|
1929
1927
|
}
|
|
1928
|
+
function removePropertyFixer(fixer, property) {
|
|
1929
|
+
const parent = getParent(property);
|
|
1930
|
+
if (parent?.type !== "ObjectExpression")
|
|
1931
|
+
return;
|
|
1932
|
+
if (parent.properties.length === 1) {
|
|
1933
|
+
return fixer.remove(parent);
|
|
1934
|
+
}
|
|
1935
|
+
const index = parent.properties.indexOf(property);
|
|
1936
|
+
const range = index ? [parent.properties[index - 1].range[1], property.range[1]] : [property.range[0], parent.properties[1].range[0]];
|
|
1937
|
+
return fixer.removeRange(range);
|
|
1938
|
+
}
|
|
1930
1939
|
var getRangeOffset;
|
|
1931
1940
|
var init_fixer = __esm({
|
|
1932
1941
|
"src/utils/fixer.ts"() {
|
|
1933
1942
|
"use strict";
|
|
1943
|
+
init_ast();
|
|
1934
1944
|
getRangeOffset = (node) => node.type === "Identifier" ? 0 : 1;
|
|
1935
1945
|
}
|
|
1936
1946
|
});
|
|
1937
1947
|
|
|
1938
1948
|
// src/rules/no-useless-not.ts
|
|
1939
|
-
|
|
1949
|
+
function getOptions(call, name) {
|
|
1950
|
+
const [arg] = call.matcherArgs;
|
|
1951
|
+
if (arg?.type !== "ObjectExpression")
|
|
1952
|
+
return;
|
|
1953
|
+
const property = arg.properties.find(
|
|
1954
|
+
(p) => p.type === "Property" && getStringValue(p.key) === name && isBooleanLiteral(p.value)
|
|
1955
|
+
);
|
|
1956
|
+
return {
|
|
1957
|
+
arg,
|
|
1958
|
+
property,
|
|
1959
|
+
value: property?.value?.value
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
var matcherConfig, no_useless_not_default;
|
|
1940
1963
|
var init_no_useless_not = __esm({
|
|
1941
1964
|
"src/rules/no-useless-not.ts"() {
|
|
1942
1965
|
"use strict";
|
|
1943
1966
|
init_ast();
|
|
1944
1967
|
init_fixer();
|
|
1968
|
+
init_misc();
|
|
1945
1969
|
init_parseFnCall();
|
|
1946
|
-
|
|
1947
|
-
toBeDisabled: "toBeEnabled",
|
|
1948
|
-
toBeEnabled:
|
|
1949
|
-
|
|
1950
|
-
|
|
1970
|
+
matcherConfig = {
|
|
1971
|
+
toBeDisabled: { inverse: "toBeEnabled" },
|
|
1972
|
+
toBeEnabled: {
|
|
1973
|
+
argName: "enabled",
|
|
1974
|
+
inverse: "toBeDisabled"
|
|
1975
|
+
},
|
|
1976
|
+
toBeHidden: { inverse: "toBeVisible" },
|
|
1977
|
+
toBeVisible: {
|
|
1978
|
+
argName: "visible",
|
|
1979
|
+
inverse: "toBeHidden"
|
|
1980
|
+
}
|
|
1951
1981
|
};
|
|
1952
1982
|
no_useless_not_default = {
|
|
1953
1983
|
create(context) {
|
|
@@ -1956,30 +1986,41 @@ var init_no_useless_not = __esm({
|
|
|
1956
1986
|
const call = parseFnCall(context, node);
|
|
1957
1987
|
if (call?.type !== "expect")
|
|
1958
1988
|
return;
|
|
1989
|
+
const config = matcherConfig[call.matcherName];
|
|
1990
|
+
if (!config)
|
|
1991
|
+
return;
|
|
1992
|
+
const options = config.argName ? getOptions(call, config.argName) : void 0;
|
|
1993
|
+
if (options?.arg && options.value === void 0)
|
|
1994
|
+
return;
|
|
1959
1995
|
const notModifier = call.modifiers.find(
|
|
1960
1996
|
(mod) => getStringValue(mod) === "not"
|
|
1961
1997
|
);
|
|
1962
|
-
if (!notModifier)
|
|
1998
|
+
if (!notModifier && !options?.property)
|
|
1963
1999
|
return;
|
|
1964
|
-
const
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2000
|
+
const isInverted = !!notModifier !== (options?.value === false);
|
|
2001
|
+
const newMatcherName = isInverted ? config.inverse : call.matcherName;
|
|
2002
|
+
context.report({
|
|
2003
|
+
data: {
|
|
2004
|
+
new: newMatcherName,
|
|
2005
|
+
old: call.matcherName,
|
|
2006
|
+
property: config.argName ?? ""
|
|
2007
|
+
},
|
|
2008
|
+
fix: (fixer) => {
|
|
2009
|
+
return [
|
|
2010
|
+
// Remove the `not` modifier if it exists
|
|
2011
|
+
notModifier && fixer.removeRange([
|
|
1971
2012
|
notModifier.range[0] - getRangeOffset(notModifier),
|
|
1972
2013
|
notModifier.range[1] + 1
|
|
1973
2014
|
]),
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
}
|
|
2015
|
+
// Remove the `visible` or `enabled` property if it exists
|
|
2016
|
+
options?.property && removePropertyFixer(fixer, options.property),
|
|
2017
|
+
// Swap the matcher name if it's different
|
|
2018
|
+
call.matcherName !== newMatcherName && replaceAccessorFixer(fixer, call.matcher, newMatcherName)
|
|
2019
|
+
].filter(truthy);
|
|
2020
|
+
},
|
|
2021
|
+
loc: notModifier ? { end: call.matcher.loc.end, start: notModifier.loc.start } : options.property.loc,
|
|
2022
|
+
messageId: notModifier ? "noUselessNot" : isInverted ? "noUselessProperty" : "noUselessTruthy"
|
|
2023
|
+
});
|
|
1983
2024
|
}
|
|
1984
2025
|
};
|
|
1985
2026
|
},
|
|
@@ -1992,7 +2033,9 @@ var init_no_useless_not = __esm({
|
|
|
1992
2033
|
},
|
|
1993
2034
|
fixable: "code",
|
|
1994
2035
|
messages: {
|
|
1995
|
-
noUselessNot: "Unexpected usage of not.{{old}}(). Use {{new}}() instead."
|
|
2036
|
+
noUselessNot: "Unexpected usage of not.{{old}}(). Use {{new}}() instead.",
|
|
2037
|
+
noUselessProperty: "Unexpected usage of '{{old}}({ {{property}}: false })'. Use '{{new}}()' instead.",
|
|
2038
|
+
noUselessTruthy: "Unexpected usage of '{{old}}({ {{property}}: true })'. Use '{{new}}()' instead."
|
|
1996
2039
|
},
|
|
1997
2040
|
type: "problem"
|
|
1998
2041
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-playwright",
|
|
3
3
|
"description": "ESLint plugin for Playwright testing.",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.0",
|
|
5
5
|
"repository": "https://github.com/playwright-community/eslint-plugin-playwright",
|
|
6
6
|
"author": "Mark Skelton <mark@mskelton.dev>",
|
|
7
7
|
"packageManager": "pnpm@8.12.0",
|