diff --git a/eslint.config.ts b/eslint.config.ts
index 44d1caea8e..d70f0dd793 100644
--- a/eslint.config.ts
+++ b/eslint.config.ts
@@ -1,5 +1,6 @@
import path from 'node:path';
import { globalIgnores } from 'eslint/config';
+import jest from 'eslint-plugin-jest';
import prettierRecommended from 'eslint-plugin-prettier/recommended';
import globals from 'globals';
import tsEslint from 'typescript-eslint';
@@ -52,10 +53,6 @@ const config = tsEslint.config([
globals: {
...globals.browser,
...globals.node,
- ...globals.mocha,
- ...globals.jest,
- __DEBUG_SERVER_ERRORS__: true,
- __SERVER_ERRORS__: true,
},
parserOptions: {
@@ -190,6 +187,16 @@ const config = tsEslint.config([
'react/no-deprecated': 'off',
},
},
+ {
+ files: ['node_package/tests/**', '**/*.test.{js,jsx,ts,tsx}'],
+
+ extends: [jest.configs['flat/recommended'], jest.configs['flat/style']],
+
+ rules: {
+ // Allows Jest mocks before import
+ 'import/first': 'off',
+ },
+ },
// must be the last config in the array
// https://github.com/prettier/eslint-plugin-prettier?tab=readme-ov-file#configuration-new-eslintconfigjs
prettierRecommended,
diff --git a/node_package/tests/Authenticity.test.js b/node_package/tests/Authenticity.test.js
index 68d97edaac..743b18c512 100644
--- a/node_package/tests/Authenticity.test.js
+++ b/node_package/tests/Authenticity.test.js
@@ -8,28 +8,22 @@ meta.content = testToken;
document.head.appendChild(meta);
describe('authenticityToken', () => {
- expect.assertions(2);
it('exists in ReactOnRails API', () => {
- expect.assertions(1);
- expect(typeof ReactOnRails.authenticityToken).toEqual('function');
+ expect(typeof ReactOnRails.authenticityToken).toBe('function');
});
it('can read Rails CSRF token from ', () => {
- expect.assertions(1);
const realToken = ReactOnRails.authenticityToken();
expect(realToken).toEqual(testToken);
});
});
describe('authenticityHeaders', () => {
- expect.assertions(2);
it('exists in ReactOnRails API', () => {
- expect.assertions(1);
- expect(typeof ReactOnRails.authenticityHeaders).toEqual('function');
+ expect(typeof ReactOnRails.authenticityHeaders).toBe('function');
});
it('returns valid header with CSRF token', () => {
- expect.assertions(1);
const realHeader = ReactOnRails.authenticityHeaders();
expect(realHeader).toEqual({ 'X-CSRF-Token': testToken, 'X-Requested-With': 'XMLHttpRequest' });
});
diff --git a/node_package/tests/ComponentRegistry.test.js b/node_package/tests/ComponentRegistry.test.js
index 44e460cdfe..1b5fe51773 100644
--- a/node_package/tests/ComponentRegistry.test.js
+++ b/node_package/tests/ComponentRegistry.test.js
@@ -37,7 +37,6 @@ describe('ComponentRegistry', () => {
});
it('registers and retrieves React function components', () => {
- expect.assertions(1);
const C1 = () =>
HELLO
;
ComponentRegistry.register({ C1 });
const actual = ComponentRegistry.get('C1');
@@ -46,7 +45,6 @@ describe('ComponentRegistry', () => {
});
it('registers and retrieves Render-Function components where property renderFunction is set and zero params', () => {
- expect.assertions(1);
const C1 = () => HELLO
;
C1.renderFunction = true;
ComponentRegistry.register({ C1 });
@@ -56,7 +54,6 @@ describe('ComponentRegistry', () => {
});
it('registers and retrieves ES5 class components', () => {
- expect.assertions(1);
const C2 = createReactClass({
render() {
return WORLD
;
@@ -69,7 +66,6 @@ describe('ComponentRegistry', () => {
});
it('registers and retrieves ES6 class components', () => {
- expect.assertions(1);
class C3 extends React.Component {
render() {
return Wow!
;
@@ -82,7 +78,6 @@ describe('ComponentRegistry', () => {
});
it('registers and retrieves renderers if 3 params', () => {
- expect.assertions(1);
const C4 = (a1, a2, a3) => null;
ComponentRegistry.register({ C4 });
const actual = ComponentRegistry.get('C4');
@@ -95,7 +90,6 @@ describe('ComponentRegistry', () => {
* Thus, tests are cumulative.
*/
it('registers and retrieves multiple components', () => {
- expect.assertions(4);
// Plain react stateless functional components
const C5 = () => WHY
;
const C6 = () => NOW
;
@@ -127,7 +121,6 @@ describe('ComponentRegistry', () => {
});
it('only detects a renderer function if it has three arguments', () => {
- expect.assertions(2);
const C7 = (a1, a2) => null;
const C8 = (a1) => null;
ComponentRegistry.register({ C7 });
@@ -148,20 +141,17 @@ describe('ComponentRegistry', () => {
});
it('throws error for retrieving unregistered component', () => {
- expect.assertions(1);
expect(() => ComponentRegistry.get('foobar')).toThrow(
/Could not find component registered with name foobar/,
);
});
it('throws error for setting null component', () => {
- expect.assertions(1);
const C9 = null;
expect(() => ComponentRegistry.register({ C9 })).toThrow(/Called register with null component named C9/);
});
it('retrieves component asynchronously when registered later', async () => {
- expect.assertions(1);
const C1 = () => HELLO
;
const componentPromise = ComponentRegistry.getOrWaitForComponent('C1');
ComponentRegistry.register({ C1 });
@@ -175,11 +165,12 @@ describe('ComponentRegistry', () => {
});
it('handles timeout for unregistered components', async () => {
- expect.assertions(1);
+ let error;
try {
await ComponentRegistry.getOrWaitForComponent('NonExistent');
- } catch (error) {
- expect(error.message).toMatch(/Could not find component/);
+ } catch (e) {
+ error = e;
}
+ expect(error.message).toMatch(/Could not find component/);
});
});
diff --git a/node_package/tests/ReactOnRails.test.jsx b/node_package/tests/ReactOnRails.test.jsx
index 3e7f757adf..a39b67040d 100644
--- a/node_package/tests/ReactOnRails.test.jsx
+++ b/node_package/tests/ReactOnRails.test.jsx
@@ -7,9 +7,7 @@ import * as createReactClass from 'create-react-class';
import ReactOnRails from '../src/ReactOnRails.client.ts';
describe('ReactOnRails', () => {
- expect.assertions(14);
it('render returns a virtual DOM element for component', () => {
- expect.assertions(1);
const R1 = createReactClass({
render() {
return WORLD
;
@@ -25,12 +23,11 @@ describe('ReactOnRails', () => {
document.body.appendChild(root);
ReactOnRails.render('R1', {}, 'root');
- expect(document.getElementById('root').textContent).toEqual(' WORLD ');
+ expect(document.getElementById('root').textContent).toBe(' WORLD ');
});
it('accepts traceTurbolinks as an option true', () => {
ReactOnRails.resetOptions();
- expect.assertions(1);
ReactOnRails.setOptions({ traceTurbolinks: true });
const actual = ReactOnRails.option('traceTurbolinks');
expect(actual).toBe(true);
@@ -38,7 +35,6 @@ describe('ReactOnRails', () => {
it('accepts traceTurbolinks as an option false', () => {
ReactOnRails.resetOptions();
- expect.assertions(1);
ReactOnRails.setOptions({ traceTurbolinks: false });
const actual = ReactOnRails.option('traceTurbolinks');
expect(actual).toBe(false);
@@ -46,7 +42,6 @@ describe('ReactOnRails', () => {
it('not specified has traceTurbolinks as false', () => {
ReactOnRails.resetOptions();
- expect.assertions(1);
ReactOnRails.setOptions({});
const actual = ReactOnRails.option('traceTurbolinks');
expect(actual).toBe(false);
@@ -54,13 +49,10 @@ describe('ReactOnRails', () => {
it('setOptions method throws error for invalid options', () => {
ReactOnRails.resetOptions();
- expect.assertions(1);
expect(() => ReactOnRails.setOptions({ foobar: true })).toThrow(/Invalid option/);
});
it('registerStore throws if passed a falsey object (null, undefined, etc)', () => {
- expect.assertions(3);
-
expect(() => ReactOnRails.registerStore(null)).toThrow(/null or undefined/);
expect(() => ReactOnRails.registerStore(undefined)).toThrow(/null or undefined/);
@@ -69,7 +61,6 @@ describe('ReactOnRails', () => {
});
it('register store and getStoreGenerator allow registration', () => {
- expect.assertions(2);
function reducer() {
return {};
}
@@ -87,7 +78,6 @@ describe('ReactOnRails', () => {
});
it('setStore and getStore', () => {
- expect.assertions(2);
function reducer() {
return {};
}
@@ -109,7 +99,6 @@ describe('ReactOnRails', () => {
});
it('clearHydratedStores', () => {
- expect.assertions(2);
function reducer() {
return {};
}
diff --git a/node_package/tests/StoreRegistry.test.js b/node_package/tests/StoreRegistry.test.js
index 2ebb98aedd..3a498fb345 100644
--- a/node_package/tests/StoreRegistry.test.js
+++ b/node_package/tests/StoreRegistry.test.js
@@ -14,11 +14,12 @@ function storeGenerator2(props) {
return createStore(reducer, props);
}
-describe('', () => {
- expect.assertions(11);
- it('StoreRegistry throws error for registering null or undefined store', () => {
- expect.assertions(2);
+describe('StoreRegistry', () => {
+ beforeEach(() => {
StoreRegistry.stores().clear();
+ });
+
+ it('StoreRegistry throws error for registering null or undefined store', () => {
expect(() => StoreRegistry.register({ storeGenerator: null })).toThrow(
/Called ReactOnRails.registerStoreGenerators with a null or undefined as a value/,
);
@@ -28,15 +29,12 @@ describe('', () => {
});
it('StoreRegistry throws error for retrieving unregistered store', () => {
- expect.assertions(1);
- StoreRegistry.stores().clear();
expect(() => StoreRegistry.getStore('foobar')).toThrow(
/There are no stores hydrated and you are requesting the store/,
);
});
it('StoreRegistry registers and retrieves Render-Function stores', () => {
- expect.assertions(2);
StoreRegistry.register({ storeGenerator, storeGenerator2 });
const actual = StoreRegistry.getStoreGenerator('storeGenerator');
const expected = storeGenerator;
@@ -46,15 +44,13 @@ describe('', () => {
expect(actual2).toEqual(expected2);
});
- it('StoreRegistry throws error for retrieving unregistered store', () => {
- expect.assertions(1);
+ it('StoreRegistry throws error for retrieving unregistered store generator', () => {
expect(() => StoreRegistry.getStoreGenerator('foobar')).toThrow(
/Could not find store generator registered with name foobar\. Registered store generator names include/,
);
});
it('StoreRegistry returns undefined for retrieving unregistered store, passing throwIfMissing = false', () => {
- expect.assertions(1);
StoreRegistry.setStore('foobarX', {});
const actual = StoreRegistry.getStore('foobar', false);
const expected = undefined;
@@ -62,7 +58,6 @@ describe('', () => {
});
it('StoreRegistry getStore, setStore', () => {
- expect.assertions(1);
const store = storeGenerator({});
StoreRegistry.setStore('storeGenerator', store);
const actual = StoreRegistry.getStore('storeGenerator');
@@ -71,14 +66,12 @@ describe('', () => {
});
it('StoreRegistry throws error for retrieving unregistered hydrated store', () => {
- expect.assertions(1);
expect(() => StoreRegistry.getStore('foobar')).toThrow(
/Could not find hydrated store registered with name foobar\. Registered hydrated store names include/,
);
});
it('StoreRegistry clearHydratedStores', () => {
- expect.assertions(2);
StoreRegistry.clearHydratedStores();
const result = storeGenerator({});
diff --git a/node_package/tests/buildConsoleReplay.test.js b/node_package/tests/buildConsoleReplay.test.js
index 142941fbe6..80bb01aae2 100644
--- a/node_package/tests/buildConsoleReplay.test.js
+++ b/node_package/tests/buildConsoleReplay.test.js
@@ -1,27 +1,17 @@
import buildConsoleReplay, { consoleReplay } from '../src/buildConsoleReplay.ts';
describe('consoleReplay', () => {
- expect.assertions(8);
it('does not throw an exception if no console.history object', () => {
- expect.assertions(1);
expect(() => consoleReplay()).not.toThrow(/Error/);
});
it('returns empty string if no console.history object', () => {
- expect.assertions(1);
const actual = consoleReplay();
const expected = '';
expect(actual).toEqual(expected);
});
- it('does not throw an exception if console.history.length is zero', () => {
- expect.assertions(1);
- console.history = [];
- expect(() => consoleReplay()).not.toThrow(/Error/);
- });
-
- it('returns empty string if no console.history object', () => {
- expect.assertions(1);
+ it('returns empty string if console.history is empty', () => {
console.history = [];
const actual = consoleReplay();
const expected = '';
@@ -29,7 +19,6 @@ describe('consoleReplay', () => {
});
it('replays multiple history messages', () => {
- expect.assertions(1);
console.history = [
{ arguments: ['a', 'b'], level: 'log' },
{ arguments: ['c', 'd'], level: 'warn' },
@@ -40,7 +29,6 @@ describe('consoleReplay', () => {
});
it('replays converts console param objects to JSON', () => {
- expect.assertions(1);
console.history = [
{ arguments: ['some message', { a: 1, b: 2 }], level: 'log' },
{ arguments: ['other message', { c: 3, d: 4 }], level: 'warn' },
@@ -52,8 +40,7 @@ console.warn.apply(console, ["other message","{\\"c\\":3,\\"d\\":4}"]);`;
expect(actual).toEqual(expected);
});
- it('replays converts script tag inside of object string to be safe ', () => {
- expect.assertions(1);
+ it('replays converts script tag inside of object string to be safe', () => {
console.history = [
{
arguments: [
@@ -74,7 +61,6 @@ console.warn.apply(console, ["other message","{\\"c\\":3,\\"d\\":4}"]);`;
});
it('buildConsoleReplay wraps console replay in a script tag', () => {
- expect.assertions(1);
console.history = [
{ arguments: ['some message', { a: 1, b: 2 }], level: 'log' },
{ arguments: ['other message', { c: 3, d: 4 }], level: 'warn' },
diff --git a/node_package/tests/renderFunction.test.jsx b/node_package/tests/renderFunction.test.jsx
index 4cbc5c8c02..7372216656 100644
--- a/node_package/tests/renderFunction.test.jsx
+++ b/node_package/tests/renderFunction.test.jsx
@@ -8,10 +8,7 @@ import * as createReactClass from 'create-react-class';
import isRenderFunction from '../src/isRenderFunction.ts';
describe('isRenderFunction', () => {
- expect.assertions(6);
it('returns false for a ES5 React Component', () => {
- expect.assertions(1);
-
const es5Component = createReactClass({
render() {
return ES5 React Component
;
@@ -22,8 +19,6 @@ describe('isRenderFunction', () => {
});
it('returns false for a ES6 React class', () => {
- expect.assertions(1);
-
class ES6Component extends React.Component {
render() {
return ES6 Component
;
@@ -34,8 +29,6 @@ describe('isRenderFunction', () => {
});
it('returns false for a ES6 React subclass', () => {
- expect.assertions(1);
-
class ES6Component extends React.Component {
render() {
return ES6 Component
;
@@ -52,24 +45,18 @@ describe('isRenderFunction', () => {
});
it('returns false for a stateless functional component with zero params', () => {
- expect.assertions(1);
-
const pureComponent = () => Hello
;
expect(isRenderFunction(pureComponent)).toBe(false);
});
it('returns false for a stateless functional component with one param', () => {
- expect.assertions(1);
-
const pureComponent = (props) => {props.title}
;
expect(isRenderFunction(pureComponent)).toBe(false);
});
it('returns true for a Render-Function (containing two params)', () => {
- expect.assertions(1);
-
const foobarComponent = () => Component for Render-Function
;
const foobarrenderFunction = (_props, _railsContext) => foobarComponent;
@@ -77,8 +64,6 @@ describe('isRenderFunction', () => {
});
it('returns false for simple object', () => {
- expect.assertions(1);
-
const foobarComponent = {
hello() {
return 'world';
diff --git a/node_package/tests/scriptSanitizedVal.test.js b/node_package/tests/scriptSanitizedVal.test.js
index 13cd8700e3..3dba559eac 100644
--- a/node_package/tests/scriptSanitizedVal.test.js
+++ b/node_package/tests/scriptSanitizedVal.test.js
@@ -1,9 +1,7 @@
import scriptSanitizedVal from '../src/scriptSanitizedVal.ts';
describe('scriptSanitizedVal', () => {
- expect.assertions(5);
it('returns no {
- expect.assertions(1);
const input = '[SERVER] This is a script:"" 2', () => {
- expect.assertions(1);
const input = 'Script2:"" ';
const actual = scriptSanitizedVal(input);
const expected = 'Script2:""(/script xx> 3', () => {
- expect.assertions(1);
const input = 'Script3:"" SCRIPT xx> ';
const actual = scriptSanitizedVal(input);
const expected = 'Script3:""(/script xx> 4', () => {
- expect.assertions(1);
const input = 'Script4""alert(\'WTF4\')';
const actual = scriptSanitizedVal(input);
const expected = 'Script4""(/script 5', () => {
- expect.assertions(1);
const input = 'Script5:"" script> ';
const actual = scriptSanitizedVal(input);
const expected = 'Script5:""(/script>