Files
formipay/node_modules/eslint-plugin-playwright/lib/rules/prefer-web-first-assertions.js
dwindown e8fbfb14c1 fix: prevent asset conflicts between React and Grid.js versions
Add coexistence checks to all enqueue methods to prevent loading
both React and Grid.js assets simultaneously.

Changes:
- ReactAdmin.php: Only enqueue React assets when ?react=1
- Init.php: Skip Grid.js when React active on admin pages
- Form.php, Coupon.php, Access.php: Restore classic assets when ?react=0
- Customer.php, Product.php, License.php: Add coexistence checks

Now the toggle between Classic and React versions works correctly.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-18 17:02:14 +07:00

151 lines
6.5 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getMatcherCall = void 0;
const ast_1 = require("../utils/ast");
const parseExpectCall_1 = require("../utils/parseExpectCall");
const methods = {
getAttribute: {
matcher: 'toHaveAttribute',
type: 'string',
},
innerText: { matcher: 'toHaveText', type: 'string' },
inputValue: { matcher: 'toHaveValue', type: 'string' },
isChecked: { matcher: 'toBeChecked', type: 'boolean' },
isDisabled: {
inverse: 'toBeEnabled',
matcher: 'toBeDisabled',
type: 'boolean',
},
isEditable: { matcher: 'toBeEditable', type: 'boolean' },
isEnabled: {
inverse: 'toBeDisabled',
matcher: 'toBeEnabled',
type: 'boolean',
},
isHidden: {
inverse: 'toBeVisible',
matcher: 'toBeHidden',
type: 'boolean',
},
isVisible: {
inverse: 'toBeHidden',
matcher: 'toBeVisible',
type: 'boolean',
},
textContent: { matcher: 'toHaveText', type: 'string' },
};
const supportedMatchers = new Set([
'toBe',
'toEqual',
'toBeTruthy',
'toBeFalsy',
]);
function getMatcherCall(node) {
const grandparent = node.parent?.parent;
return grandparent.type === 'CallExpression' ? grandparent : undefined;
}
exports.getMatcherCall = getMatcherCall;
exports.default = {
create(context) {
return {
CallExpression(node) {
const expectCall = (0, parseExpectCall_1.parseExpectCall)(node);
if (!expectCall)
return;
const [arg] = node.arguments;
if (arg.type !== 'AwaitExpression' ||
arg.argument.type !== 'CallExpression' ||
arg.argument.callee.type !== 'MemberExpression') {
return;
}
// Matcher must be supported
if (!supportedMatchers.has(expectCall.matcherName))
return;
// Playwright method must be supported
const method = (0, ast_1.getStringValue)(arg.argument.callee.property);
const methodConfig = methods[method];
if (!methodConfig)
return;
// Change the matcher
const { args, matcher } = expectCall;
const notModifier = expectCall.modifiers.find((mod) => (0, ast_1.getStringValue)(mod) === 'not');
const isFalsy = methodConfig.type === 'boolean' &&
((!!args.length && (0, ast_1.isBooleanLiteral)(args[0], false)) ||
expectCall.matcherName === 'toBeFalsy');
const isInverse = methodConfig.inverse
? notModifier || isFalsy
: notModifier && isFalsy;
// Replace the old matcher with the new matcher. The inverse
// matcher should only be used if the old statement was not a
// double negation.
const newMatcher = (+!!notModifier ^ +isFalsy && methodConfig.inverse) ||
methodConfig.matcher;
const { callee } = arg.argument;
context.report({
data: {
matcher: newMatcher,
method,
},
fix: (fixer) => {
const methodArgs = arg.argument.type === 'CallExpression'
? arg.argument.arguments
: [];
const methodEnd = methodArgs.length
? methodArgs[methodArgs.length - 1].range[1] + 1
: callee.property.range[1] + 2;
const fixes = [
// Add await to the expect call
fixer.insertTextBefore(node, 'await '),
// Remove the await keyword
fixer.replaceTextRange([arg.range[0], arg.argument.range[0]], ''),
// Remove the old Playwright method and any arguments
fixer.replaceTextRange([callee.property.range[0] - 1, methodEnd], ''),
];
// Remove not from matcher chain if no longer needed
if (isInverse && notModifier) {
const notRange = notModifier.range;
fixes.push(fixer.removeRange([notRange[0], notRange[1] + 1]));
}
// Add not to the matcher chain if no inverse matcher exists
if (!methodConfig.inverse && !notModifier && isFalsy) {
fixes.push(fixer.insertTextBefore(matcher, 'not.'));
}
fixes.push(fixer.replaceText(matcher, newMatcher));
// Remove boolean argument if it exists
const [matcherArg] = args ?? [];
if (matcherArg && (0, ast_1.isBooleanLiteral)(matcherArg)) {
fixes.push(fixer.remove(matcherArg));
}
// Add the new matcher arguments if needed
const hasOtherArgs = !!methodArgs.filter((arg) => !(0, ast_1.isBooleanLiteral)(arg)).length;
if (methodArgs) {
const range = matcher.range;
const stringArgs = methodArgs
.map((arg) => (0, ast_1.getRawValue)(arg))
.concat(hasOtherArgs ? '' : [])
.join(', ');
fixes.push(fixer.insertTextAfterRange([range[0], range[1] + 1], stringArgs));
}
return fixes;
},
messageId: 'useWebFirstAssertion',
node,
});
},
};
},
meta: {
docs: {
category: 'Best Practices',
description: 'Prefer web first assertions',
recommended: true,
url: 'https://github.com/playwright-community/eslint-plugin-playwright/tree/main/docs/rules/prefer-web-first-assertions.md',
},
fixable: 'code',
messages: {
useWebFirstAssertion: 'Replace {{method}}() with {{matcher}}().',
},
type: 'suggestion',
},
};