diff --git a/.eslintrc.json b/.eslintrc.json index 915ccda99..89284f2b0 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,7 +2,10 @@ "parser": "@typescript-eslint/parser", "parserOptions": { "sourceType": "module", - "ecmaVersion": 2015 + "ecmaVersion": 2015, + "ecmaFeatures": { + "jsx": true + } }, "settings": { "react": { @@ -12,17 +15,36 @@ "plugins": [ "react", "react-hooks", - "@typescript-eslint" + "@typescript-eslint", + "cypress", + "prettier" ], "extends": [ "eslint:recommended", "plugin:react/recommended", "plugin:react-hooks/recommended", - "plugin:@typescript-eslint/recommended" + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/stylistic", + "plugin:cypress/recommended", + "prettier" ], "rules": { "react/react-in-jsx-scope": "off", - "react/prop-types": "off" + "react/prop-types": "off", + // Emulate typescript style for unused variables, see + // https://typescript-eslint.io/rules/no-unused-vars/ + "@typescript-eslint/no-unused-vars": [ + "error", + { + "args": "all", + "argsIgnorePattern": "^_", + "caughtErrors": "all", + "caughtErrorsIgnorePattern": "^_", + "destructuredArrayIgnorePattern": "^_", + "varsIgnorePattern": "^_", + "ignoreRestSiblings": true + } + ] }, "overrides": [ { diff --git a/README.md b/README.md index 8bf0d3eb4..c2511acfa 100644 --- a/README.md +++ b/README.md @@ -57,12 +57,6 @@ Deploys a static version of the build from the `dist` directory to port 5001. Us For development purposes, use `yarn preview:build:dev` to build in watch mode so that changes are built automatically. -## Learn More - -You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). - -To learn React, check out the [React documentation](https://reactjs.org/). - ## How to run ### Docker Setup diff --git a/package.json b/package.json index 514c0b88d..20184c281 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "preview:build": "yarn build && yarn preview", "preview:build:dev": "yarn build --watch & yarn preview", "test": "vitest --coverage", - "lint:js": "eslint --max-warnings=0 --ext=tsx --ext=ts --ext=js --ext=jsx --fix ./src", + "lint": "eslint --max-warnings=0 --ext=tsx --ext=ts --ext=js --ext=jsx --fix ./src", "build:e2e": "cross-env VITE_APP_BUILD_STANDALONE=true VITE_APP_INCLUDE_MSW=true GENERATE_SOURCEMAP=false yarn build", "build:e2e:api": "cross-env VITE_APP_BUILD_STANDALONE=true VITE_APP_INCLUDE_MSW=false GENERATE_SOURCEMAP=false yarn build", "e2e:serve": "yarn build:e2e && node ./server/e2e-test-server.js", diff --git a/src/catalogue/category/catalogueCategoryDialog.component.tsx b/src/catalogue/category/catalogueCategoryDialog.component.tsx index f8931edf9..ce8d54916 100644 --- a/src/catalogue/category/catalogueCategoryDialog.component.tsx +++ b/src/catalogue/category/catalogueCategoryDialog.component.tsx @@ -272,11 +272,11 @@ const CatalogueCategoryDialog = React.memo( }); const uniqueDuplicateIndexes = Array.from(new Set(duplicateIndexes)); - for (let i = 0; i < uniqueDuplicateIndexes.length; i++) { + for (const uniqueDuplicateIndex of uniqueDuplicateIndexes) { setCatalogueItemPropertiesErrors((prev) => [ ...prev, { - index: uniqueDuplicateIndexes[i], + index: uniqueDuplicateIndex, errors: { fieldName: 'name', errorMessage: diff --git a/src/catalogue/items/catalogueItemsDialog.component.tsx b/src/catalogue/items/catalogueItemsDialog.component.tsx index eab1e4b56..f755b4e7a 100644 --- a/src/catalogue/items/catalogueItemsDialog.component.tsx +++ b/src/catalogue/items/catalogueItemsDialog.component.tsx @@ -60,7 +60,7 @@ function isValidUrl(url: string) { (parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:') && parsedUrl.hostname.includes('.') // Checks for the typical top-level domain ); - } catch (error) { + } catch (_error) { return false; } } diff --git a/src/catalogue/items/catalogueItemsLandingPage.component.test.tsx b/src/catalogue/items/catalogueItemsLandingPage.component.test.tsx index 69e7083a2..49e99193f 100644 --- a/src/catalogue/items/catalogueItemsLandingPage.component.test.tsx +++ b/src/catalogue/items/catalogueItemsLandingPage.component.test.tsx @@ -228,7 +228,7 @@ describe('Catalogue Items Landing Page', () => { }); it('prints when the button is clicked', async () => { - const spy = vi.spyOn(window, 'print').mockImplementation(() => {}); + const spy = vi.spyOn(window, 'print'); createView('/catalogue/item/89'); await waitFor(() => { diff --git a/src/catalogue/items/catalogueItemsTable.component.tsx b/src/catalogue/items/catalogueItemsTable.component.tsx index 46afc7d01..d7ba28204 100644 --- a/src/catalogue/items/catalogueItemsTable.component.tsx +++ b/src/catalogue/items/catalogueItemsTable.component.tsx @@ -135,18 +135,18 @@ export interface CatalogueItemsTableProps { onChangeObsoleteReplacementId?: ( obsoleteReplacementId: string | null ) => void; - selectedRowState?: { [x: string]: boolean }; + selectedRowState?: Record; // Only for dense tables with a select - should return if a given catalogue item is // selectable or not isItemSelectable?: (item: CatalogueItem) => boolean; requestOrigin?: 'move to' | 'obsolete'; } -export type PropertyFiltersType = { +export interface PropertyFiltersType { boolean: 'select' | 'text' | 'range'; string: 'select' | 'text' | 'range'; number: 'select' | 'text' | 'range'; null: 'select' | 'text' | 'range'; -}; +} const CatalogueItemsTable = (props: CatalogueItemsTableProps) => { const { diff --git a/src/items/itemsLandingPage.component.test.tsx b/src/items/itemsLandingPage.component.test.tsx index 50bd694a2..1f89be003 100644 --- a/src/items/itemsLandingPage.component.test.tsx +++ b/src/items/itemsLandingPage.component.test.tsx @@ -149,7 +149,7 @@ describe('Items Landing Page', () => { }); it('prints when the button is clicked', async () => { - const spy = vi.spyOn(window, 'print').mockImplementation(() => {}); + const spy = vi.spyOn(window, 'print'); createView('/catalogue/item/1/items/KvT2Ox7n'); await waitFor(() => { diff --git a/src/manufacturer/manufacturerDialog.component.tsx b/src/manufacturer/manufacturerDialog.component.tsx index d676e69a3..0e08cb996 100644 --- a/src/manufacturer/manufacturerDialog.component.tsx +++ b/src/manufacturer/manufacturerDialog.component.tsx @@ -38,7 +38,7 @@ function isValidUrl(url: string) { (parsedUrl.protocol === 'http:' || parsedUrl.protocol === 'https:') && parsedUrl.hostname.includes('.') // Checks for the typical top-level domain ); - } catch (error) { + } catch (_error) { return false; } } diff --git a/src/manufacturer/manufacturerLandingPage.component.test.tsx b/src/manufacturer/manufacturerLandingPage.component.test.tsx index 0058c7d08..c6db7ab4a 100644 --- a/src/manufacturer/manufacturerLandingPage.component.test.tsx +++ b/src/manufacturer/manufacturerLandingPage.component.test.tsx @@ -122,7 +122,7 @@ describe('Manufacturer Landing page', () => { }); it('prints when the button is clicked', async () => { - const spy = vi.spyOn(window, 'print').mockImplementation(() => {}); + const spy = vi.spyOn(window, 'print'); createView('/manufacturers/1'); await waitFor(() => { diff --git a/src/setupTests.tsx b/src/setupTests.ts similarity index 100% rename from src/setupTests.tsx rename to src/setupTests.ts diff --git a/tsconfig.build.json b/tsconfig.build.json index 2e180cfcf..30a804d55 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,5 +1,5 @@ { "extends": "./tsconfig.base.json", // Exclude test files from build - "exclude": ["**/?*test.*", "src/setupTests.tsx", "src/testUtils.tsx"], + "exclude": ["**/?*test.*", "src/setupTests.ts", "src/testUtils.tsx"], } \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 177c40ca3..be2fbbf68 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -122,7 +122,7 @@ export default defineConfig(({ mode }) => { globals: true, environment: 'jsdom', globalSetup: './globalSetup.js', - setupFiles: ['src/setupTests.tsx'], + setupFiles: ['src/setupTests.ts'], coverage: { exclude: [ 'public/*', @@ -132,7 +132,6 @@ export default defineConfig(({ mode }) => { 'src/mocks/server.ts', 'src/vite-env.d.ts', 'src/main.tsx', - 'src/testUtils.tsx', ], }, },