From 7e237a5cdc27032676ca8fb1f359ca89f3b7f649 Mon Sep 17 00:00:00 2001 From: Alexey Romanov Date: Thu, 10 Apr 2025 16:01:47 +0000 Subject: [PATCH 1/3] Enable Jest ESLint plugin with recommended config --- eslint.config.ts | 15 ++- node_package/tests/Authenticity.test.js | 6 +- node_package/tests/ComponentRegistry.test.js | 6 +- node_package/tests/ReactOnRails.test.jsx | 3 +- node_package/tests/StoreRegistry.test.js | 11 +- node_package/tests/buildConsoleReplay.test.js | 11 +- node_package/tests/renderFunction.test.jsx | 1 - node_package/tests/scriptSanitizedVal.test.js | 1 - .../tests/serverRenderReactComponent.test.ts | 2 +- package.json | 3 +- yarn.lock | 121 +++++++++--------- 11 files changed, 93 insertions(+), 87 deletions(-) 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..b201ef1a6e 100644 --- a/node_package/tests/Authenticity.test.js +++ b/node_package/tests/Authenticity.test.js @@ -8,10 +8,9 @@ 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 ', () => { @@ -22,10 +21,9 @@ describe('authenticityToken', () => { }); 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', () => { diff --git a/node_package/tests/ComponentRegistry.test.js b/node_package/tests/ComponentRegistry.test.js index 44e460cdfe..c2db57d2de 100644 --- a/node_package/tests/ComponentRegistry.test.js +++ b/node_package/tests/ComponentRegistry.test.js @@ -176,10 +176,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..4f4e948336 100644 --- a/node_package/tests/ReactOnRails.test.jsx +++ b/node_package/tests/ReactOnRails.test.jsx @@ -7,7 +7,6 @@ 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({ @@ -25,7 +24,7 @@ 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', () => { diff --git a/node_package/tests/StoreRegistry.test.js b/node_package/tests/StoreRegistry.test.js index 2ebb98aedd..b4681464bd 100644 --- a/node_package/tests/StoreRegistry.test.js +++ b/node_package/tests/StoreRegistry.test.js @@ -14,11 +14,13 @@ function storeGenerator2(props) { return createStore(reducer, props); } -describe('', () => { - expect.assertions(11); +describe('StoreRegistry', () => { + beforeEach(() => { + StoreRegistry.stores().clear(); + }); + it('StoreRegistry throws error for registering null or undefined store', () => { expect.assertions(2); - StoreRegistry.stores().clear(); expect(() => StoreRegistry.register({ storeGenerator: null })).toThrow( /Called ReactOnRails.registerStoreGenerators with a null or undefined as a value/, ); @@ -29,7 +31,6 @@ 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/, ); @@ -46,7 +47,7 @@ describe('', () => { expect(actual2).toEqual(expected2); }); - it('StoreRegistry throws error for retrieving unregistered store', () => { + it('StoreRegistry throws error for retrieving unregistered store generator', () => { expect.assertions(1); expect(() => StoreRegistry.getStoreGenerator('foobar')).toThrow( /Could not find store generator registered with name foobar\. Registered store generator names include/, diff --git a/node_package/tests/buildConsoleReplay.test.js b/node_package/tests/buildConsoleReplay.test.js index 142941fbe6..b4b156263e 100644 --- a/node_package/tests/buildConsoleReplay.test.js +++ b/node_package/tests/buildConsoleReplay.test.js @@ -1,7 +1,6 @@ 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/); @@ -14,13 +13,7 @@ describe('consoleReplay', () => { 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', () => { + it('returns empty string if console.history is empty', () => { expect.assertions(1); console.history = []; const actual = consoleReplay(); @@ -52,7 +45,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 ', () => { + it('replays converts script tag inside of object string to be safe', () => { expect.assertions(1); console.history = [ { diff --git a/node_package/tests/renderFunction.test.jsx b/node_package/tests/renderFunction.test.jsx index 4cbc5c8c02..f76183c065 100644 --- a/node_package/tests/renderFunction.test.jsx +++ b/node_package/tests/renderFunction.test.jsx @@ -8,7 +8,6 @@ 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); diff --git a/node_package/tests/scriptSanitizedVal.test.js b/node_package/tests/scriptSanitizedVal.test.js index 13cd8700e3..19e7fdd491 100644 --- a/node_package/tests/scriptSanitizedVal.test.js +++ b/node_package/tests/scriptSanitizedVal.test.js @@ -1,7 +1,6 @@ import scriptSanitizedVal from '../src/scriptSanitizedVal.ts'; describe('scriptSanitizedVal', () => { - expect.assertions(5); it('returns no { expect.assertions(1); const input = '[SERVER] This is a script:"" { - 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:"" '; 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:"" '; const actual = scriptSanitizedVal(input); const expected = 'Script5:""(/script>