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>
This commit is contained in:
dwindown
2026-04-18 17:02:14 +07:00
parent bd9cdac02e
commit e8fbfb14c1
74973 changed files with 6658406 additions and 71 deletions

View File

@@ -0,0 +1,41 @@
/**
* Internal dependencies
*/
import './matchers';
import supportedMatchers from './supported-matchers';
/**
* Sets spy on the console object's method to make it possible to fail test when method called without assertion.
*
* @param {Array} args
* @param {string} args."0" Name of console method.
* @param {string} args."1" Name of Jest matcher.
*/
const setConsoleMethodSpy = ([methodName, matcherName]) => {
const spy = jest.spyOn(console, methodName).mockName(`console.${methodName}`);
/**
* Resets the spy to its initial state.
*/
function resetSpy() {
spy.mockReset();
spy.assertionsNumber = 0;
}
/**
* Verifies that the spy has only been called if expected.
*/
function assertExpectedCalls() {
if (spy.assertionsNumber === 0 && spy.mock.calls.length > 0) {
expect(console).not[matcherName]();
}
}
beforeAll(resetSpy);
beforeEach(() => {
assertExpectedCalls();
resetSpy();
});
afterEach(assertExpectedCalls);
};
Object.entries(supportedMatchers).forEach(setConsoleMethodSpy);
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["supportedMatchers","setConsoleMethodSpy","methodName","matcherName","spy","jest","spyOn","console","mockName","resetSpy","mockReset","assertionsNumber","assertExpectedCalls","mock","calls","length","expect","not","beforeAll","beforeEach","afterEach","Object","entries","forEach"],"sources":["@wordpress/jest-console/src/index.js"],"sourcesContent":["/**\n * Internal dependencies\n */\nimport './matchers';\nimport supportedMatchers from './supported-matchers';\n\n/**\n * Sets spy on the console object's method to make it possible to fail test when method called without assertion.\n *\n * @param {Array} args\n * @param {string} args.\"0\" Name of console method.\n * @param {string} args.\"1\" Name of Jest matcher.\n */\nconst setConsoleMethodSpy = ( [ methodName, matcherName ] ) => {\n\tconst spy = jest\n\t\t.spyOn( console, methodName )\n\t\t.mockName( `console.${ methodName }` );\n\n\t/**\n\t * Resets the spy to its initial state.\n\t */\n\tfunction resetSpy() {\n\t\tspy.mockReset();\n\t\tspy.assertionsNumber = 0;\n\t}\n\n\t/**\n\t * Verifies that the spy has only been called if expected.\n\t */\n\tfunction assertExpectedCalls() {\n\t\tif ( spy.assertionsNumber === 0 && spy.mock.calls.length > 0 ) {\n\t\t\texpect( console ).not[ matcherName ]();\n\t\t}\n\t}\n\n\tbeforeAll( resetSpy );\n\n\tbeforeEach( () => {\n\t\tassertExpectedCalls();\n\t\tresetSpy();\n\t} );\n\n\tafterEach( assertExpectedCalls );\n};\n\nObject.entries( supportedMatchers ).forEach( setConsoleMethodSpy );\n"],"mappings":"AAAA;AACA;AACA;AACA,OAAO,YAAY;AACnB,OAAOA,iBAAiB,MAAM,sBAAsB;;AAEpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,mBAAmB,GAAGA,CAAE,CAAEC,UAAU,EAAEC,WAAW,CAAE,KAAM;EAC9D,MAAMC,GAAG,GAAGC,IAAI,CACdC,KAAK,CAAEC,OAAO,EAAEL,UAAW,CAAC,CAC5BM,QAAQ,CAAG,WAAWN,UAAY,EAAE,CAAC;;EAEvC;AACD;AACA;EACC,SAASO,QAAQA,CAAA,EAAG;IACnBL,GAAG,CAACM,SAAS,CAAC,CAAC;IACfN,GAAG,CAACO,gBAAgB,GAAG,CAAC;EACzB;;EAEA;AACD;AACA;EACC,SAASC,mBAAmBA,CAAA,EAAG;IAC9B,IAAKR,GAAG,CAACO,gBAAgB,KAAK,CAAC,IAAIP,GAAG,CAACS,IAAI,CAACC,KAAK,CAACC,MAAM,GAAG,CAAC,EAAG;MAC9DC,MAAM,CAAET,OAAQ,CAAC,CAACU,GAAG,CAAEd,WAAW,CAAE,CAAC,CAAC;IACvC;EACD;EAEAe,SAAS,CAAET,QAAS,CAAC;EAErBU,UAAU,CAAE,MAAM;IACjBP,mBAAmB,CAAC,CAAC;IACrBH,QAAQ,CAAC,CAAC;EACX,CAAE,CAAC;EAEHW,SAAS,CAAER,mBAAoB,CAAC;AACjC,CAAC;AAEDS,MAAM,CAACC,OAAO,CAAEtB,iBAAkB,CAAC,CAACuB,OAAO,CAAEtB,mBAAoB,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,59 @@
/**
* External dependencies
*/
import { matcherHint, printExpected, printReceived } from 'jest-matcher-utils';
/**
* Internal dependencies
*/
import supportedMatchers from './supported-matchers';
const createErrorMessage = spyInfo => {
const {
spy,
pass,
calls,
matcherName,
methodName,
expected
} = spyInfo;
const hint = pass ? `.not${matcherName}` : matcherName;
const message = pass ? `Expected mock function not to be called but it was called with:\n${calls.map(printReceived)}` : `Expected mock function to be called${expected ? ` with:\n${printExpected(expected)}\n` : '.'}\nbut it was called with:\n${calls.map(printReceived)}`;
return () => `${matcherHint(hint, spy.getMockName())}` + '\n\n' + message + '\n\n' + `console.${methodName}() should not be used unless explicitly expected\n` + 'See https://www.npmjs.com/package/@wordpress/jest-console for details.';
};
const createSpyInfo = (spy, matcherName, methodName, expected) => {
const calls = spy.mock.calls;
const pass = expected ? JSON.stringify(calls).includes(JSON.stringify(expected)) : calls.length > 0;
const message = createErrorMessage({
spy,
pass,
calls,
matcherName,
methodName,
expected
});
return {
pass,
message
};
};
const createToHaveBeenCalledMatcher = (matcherName, methodName) => received => {
const spy = received[methodName];
const spyInfo = createSpyInfo(spy, matcherName, methodName);
spy.assertionsNumber += 1;
return spyInfo;
};
const createToHaveBeenCalledWith = (matcherName, methodName) => function (received, ...expected) {
const spy = received[methodName];
const spyInfo = createSpyInfo(spy, matcherName, methodName, expected);
spy.assertionsNumber += 1;
return spyInfo;
};
expect.extend(Object.entries(supportedMatchers).reduce((result, [methodName, matcherName]) => {
const matcherNameWith = `${matcherName}With`;
return {
...result,
[matcherName]: createToHaveBeenCalledMatcher(`.${matcherName}`, methodName),
[matcherNameWith]: createToHaveBeenCalledWith(`.${matcherNameWith}`, methodName)
};
}, {}));
//# sourceMappingURL=matchers.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["matcherHint","printExpected","printReceived","supportedMatchers","createErrorMessage","spyInfo","spy","pass","calls","matcherName","methodName","expected","hint","message","map","getMockName","createSpyInfo","mock","JSON","stringify","includes","length","createToHaveBeenCalledMatcher","received","assertionsNumber","createToHaveBeenCalledWith","expect","extend","Object","entries","reduce","result","matcherNameWith"],"sources":["@wordpress/jest-console/src/matchers.js"],"sourcesContent":["/**\n * External dependencies\n */\nimport { matcherHint, printExpected, printReceived } from 'jest-matcher-utils';\n\n/**\n * Internal dependencies\n */\nimport supportedMatchers from './supported-matchers';\n\nconst createErrorMessage = ( spyInfo ) => {\n\tconst { spy, pass, calls, matcherName, methodName, expected } = spyInfo;\n\tconst hint = pass ? `.not${ matcherName }` : matcherName;\n\tconst message = pass\n\t\t? `Expected mock function not to be called but it was called with:\\n${ calls.map(\n\t\t\t\tprintReceived\n\t\t ) }`\n\t\t: `Expected mock function to be called${\n\t\t\t\texpected ? ` with:\\n${ printExpected( expected ) }\\n` : '.'\n\t\t }\\nbut it was called with:\\n${ calls.map( printReceived ) }`;\n\n\treturn () =>\n\t\t`${ matcherHint( hint, spy.getMockName() ) }` +\n\t\t'\\n\\n' +\n\t\tmessage +\n\t\t'\\n\\n' +\n\t\t`console.${ methodName }() should not be used unless explicitly expected\\n` +\n\t\t'See https://www.npmjs.com/package/@wordpress/jest-console for details.';\n};\n\nconst createSpyInfo = ( spy, matcherName, methodName, expected ) => {\n\tconst calls = spy.mock.calls;\n\n\tconst pass = expected\n\t\t? JSON.stringify( calls ).includes( JSON.stringify( expected ) )\n\t\t: calls.length > 0;\n\n\tconst message = createErrorMessage( {\n\t\tspy,\n\t\tpass,\n\t\tcalls,\n\t\tmatcherName,\n\t\tmethodName,\n\t\texpected,\n\t} );\n\n\treturn {\n\t\tpass,\n\t\tmessage,\n\t};\n};\n\nconst createToHaveBeenCalledMatcher =\n\t( matcherName, methodName ) => ( received ) => {\n\t\tconst spy = received[ methodName ];\n\t\tconst spyInfo = createSpyInfo( spy, matcherName, methodName );\n\n\t\tspy.assertionsNumber += 1;\n\n\t\treturn spyInfo;\n\t};\n\nconst createToHaveBeenCalledWith = ( matcherName, methodName ) =>\n\tfunction ( received, ...expected ) {\n\t\tconst spy = received[ methodName ];\n\t\tconst spyInfo = createSpyInfo( spy, matcherName, methodName, expected );\n\n\t\tspy.assertionsNumber += 1;\n\n\t\treturn spyInfo;\n\t};\n\nexpect.extend(\n\tObject.entries( supportedMatchers ).reduce(\n\t\t( result, [ methodName, matcherName ] ) => {\n\t\t\tconst matcherNameWith = `${ matcherName }With`;\n\n\t\t\treturn {\n\t\t\t\t...result,\n\t\t\t\t[ matcherName ]: createToHaveBeenCalledMatcher(\n\t\t\t\t\t`.${ matcherName }`,\n\t\t\t\t\tmethodName\n\t\t\t\t),\n\t\t\t\t[ matcherNameWith ]: createToHaveBeenCalledWith(\n\t\t\t\t\t`.${ matcherNameWith }`,\n\t\t\t\t\tmethodName\n\t\t\t\t),\n\t\t\t};\n\t\t},\n\t\t{}\n\t)\n);\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,WAAW,EAAEC,aAAa,EAAEC,aAAa,QAAQ,oBAAoB;;AAE9E;AACA;AACA;AACA,OAAOC,iBAAiB,MAAM,sBAAsB;AAEpD,MAAMC,kBAAkB,GAAKC,OAAO,IAAM;EACzC,MAAM;IAAEC,GAAG;IAAEC,IAAI;IAAEC,KAAK;IAAEC,WAAW;IAAEC,UAAU;IAAEC;EAAS,CAAC,GAAGN,OAAO;EACvE,MAAMO,IAAI,GAAGL,IAAI,GAAI,OAAOE,WAAa,EAAC,GAAGA,WAAW;EACxD,MAAMI,OAAO,GAAGN,IAAI,GAChB,oEAAoEC,KAAK,CAACM,GAAG,CAC9EZ,aACA,CAAG,EAAC,GACH,sCACDS,QAAQ,GAAI,WAAWV,aAAa,CAAEU,QAAS,CAAG,IAAG,GAAG,GACvD,8BAA8BH,KAAK,CAACM,GAAG,CAAEZ,aAAc,CAAG,EAAC;EAE/D,OAAO,MACL,GAAGF,WAAW,CAAEY,IAAI,EAAEN,GAAG,CAACS,WAAW,CAAC,CAAE,CAAG,EAAC,GAC7C,MAAM,GACNF,OAAO,GACP,MAAM,GACL,WAAWH,UAAY,oDAAmD,GAC3E,wEAAwE;AAC1E,CAAC;AAED,MAAMM,aAAa,GAAGA,CAAEV,GAAG,EAAEG,WAAW,EAAEC,UAAU,EAAEC,QAAQ,KAAM;EACnE,MAAMH,KAAK,GAAGF,GAAG,CAACW,IAAI,CAACT,KAAK;EAE5B,MAAMD,IAAI,GAAGI,QAAQ,GAClBO,IAAI,CAACC,SAAS,CAAEX,KAAM,CAAC,CAACY,QAAQ,CAAEF,IAAI,CAACC,SAAS,CAAER,QAAS,CAAE,CAAC,GAC9DH,KAAK,CAACa,MAAM,GAAG,CAAC;EAEnB,MAAMR,OAAO,GAAGT,kBAAkB,CAAE;IACnCE,GAAG;IACHC,IAAI;IACJC,KAAK;IACLC,WAAW;IACXC,UAAU;IACVC;EACD,CAAE,CAAC;EAEH,OAAO;IACNJ,IAAI;IACJM;EACD,CAAC;AACF,CAAC;AAED,MAAMS,6BAA6B,GAClCA,CAAEb,WAAW,EAAEC,UAAU,KAAQa,QAAQ,IAAM;EAC9C,MAAMjB,GAAG,GAAGiB,QAAQ,CAAEb,UAAU,CAAE;EAClC,MAAML,OAAO,GAAGW,aAAa,CAAEV,GAAG,EAAEG,WAAW,EAAEC,UAAW,CAAC;EAE7DJ,GAAG,CAACkB,gBAAgB,IAAI,CAAC;EAEzB,OAAOnB,OAAO;AACf,CAAC;AAEF,MAAMoB,0BAA0B,GAAGA,CAAEhB,WAAW,EAAEC,UAAU,KAC3D,UAAWa,QAAQ,EAAE,GAAGZ,QAAQ,EAAG;EAClC,MAAML,GAAG,GAAGiB,QAAQ,CAAEb,UAAU,CAAE;EAClC,MAAML,OAAO,GAAGW,aAAa,CAAEV,GAAG,EAAEG,WAAW,EAAEC,UAAU,EAAEC,QAAS,CAAC;EAEvEL,GAAG,CAACkB,gBAAgB,IAAI,CAAC;EAEzB,OAAOnB,OAAO;AACf,CAAC;AAEFqB,MAAM,CAACC,MAAM,CACZC,MAAM,CAACC,OAAO,CAAE1B,iBAAkB,CAAC,CAAC2B,MAAM,CACzC,CAAEC,MAAM,EAAE,CAAErB,UAAU,EAAED,WAAW,CAAE,KAAM;EAC1C,MAAMuB,eAAe,GAAI,GAAGvB,WAAa,MAAK;EAE9C,OAAO;IACN,GAAGsB,MAAM;IACT,CAAEtB,WAAW,GAAIa,6BAA6B,CAC5C,IAAIb,WAAa,EAAC,EACnBC,UACD,CAAC;IACD,CAAEsB,eAAe,GAAIP,0BAA0B,CAC7C,IAAIO,eAAiB,EAAC,EACvBtB,UACD;EACD,CAAC;AACF,CAAC,EACD,CAAC,CACF,CACD,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,8 @@
const supportedMatchers = {
error: 'toHaveErrored',
info: 'toHaveInformed',
log: 'toHaveLogged',
warn: 'toHaveWarned'
};
export default supportedMatchers;
//# sourceMappingURL=supported-matchers.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["supportedMatchers","error","info","log","warn"],"sources":["@wordpress/jest-console/src/supported-matchers.js"],"sourcesContent":["const supportedMatchers = {\n\terror: 'toHaveErrored',\n\tinfo: 'toHaveInformed',\n\tlog: 'toHaveLogged',\n\twarn: 'toHaveWarned',\n};\n\nexport default supportedMatchers;\n"],"mappings":"AAAA,MAAMA,iBAAiB,GAAG;EACzBC,KAAK,EAAE,eAAe;EACtBC,IAAI,EAAE,gBAAgB;EACtBC,GAAG,EAAE,cAAc;EACnBC,IAAI,EAAE;AACP,CAAC;AAED,eAAeJ,iBAAiB","ignoreList":[]}