diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index dac522abc..5201aed9f 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -9,6 +9,6 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - uses: actions/labeler@v6 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index b52109895..556120872 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -12,6 +12,6 @@ jobs: name: Validate PR title runs-on: ubuntu-24.04 steps: - - uses: amannn/action-semantic-pull-request@v5 + - uses: amannn/action-semantic-pull-request@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index 68418789c..656d925d9 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -11,12 +11,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Pages id: pages uses: actions/configure-pages@v5 - name: Use Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: "lts/*" - name: Install dependencies @@ -24,7 +24,7 @@ jobs: - name: Build Storybook run: yarn build-docs - name: Upload artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@v4 with: path: "./docs" publish-docs: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 854d85261..21c8a273d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,11 +15,11 @@ jobs: id-token: write # to enable use of OIDC for npm provenance steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: "lts/*" - name: Install dependencies diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 7e6f74c47..ba4a96d7e 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -11,10 +11,10 @@ jobs: name: Lint, build and test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Use Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: "lts/*" @@ -36,9 +36,9 @@ jobs: name: Cypress runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Use Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: "lts/*" - uses: cypress-io/github-action@v6 @@ -47,12 +47,12 @@ jobs: wait-on: "http://localhost:9009" browser: chrome env: port=9009 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v6 if: failure() with: name: cypress-screenshots path: cypress/screenshots - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v6 if: failure() with: name: cypress-videos @@ -64,7 +64,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Check inclusive naming uses: canonical/inclusive-naming@main diff --git a/.github/workflows/tics-coverage.yml b/.github/workflows/tics-coverage.yml index 4e69e7a10..bf8c10558 100644 --- a/.github/workflows/tics-coverage.yml +++ b/.github/workflows/tics-coverage.yml @@ -8,9 +8,9 @@ jobs: tics-report: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Use Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: "lts/*" - name: Install dependencies diff --git a/Dockerfile b/Dockerfile index f77d8e3bd..b37bcf288 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ # Build stage: Install yarn dependencies # === -FROM node:24 AS yarn-dependencies +FROM node:25 AS yarn-dependencies WORKDIR /srv ADD package.json . ADD yarn.lock . diff --git a/eslint.config.mjs b/eslint.config.mjs index 489eecfeb..23df452d0 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -23,9 +23,7 @@ export default [ { ignores: ["src/external/"], }, - ...fixupConfigRules( - compat.extends("plugin:cypress/recommended", "plugin:prettier/recommended"), - ), + ...fixupConfigRules(compat.extends("plugin:prettier/recommended")), ...tseslint.configs.recommended, react.configs.flat.recommended, { @@ -91,6 +89,8 @@ export default [ varsIgnorePattern: "^_", }, ], + "react-hooks/exhaustive-deps": "warn", + "react-hooks/refs": "off", }, }, ...fixupConfigRules(compat.extends("plugin:prettier/recommended")).map( @@ -134,4 +134,24 @@ export default [ "testing-library/no-render-in-lifecycle": "off", }, }, + { + files: ["cypress/**/*.js"], + plugins: { + cypress: fixupPluginRules(cypress), + }, + rules: { + "cypress/no-assigning-return-values": "error", + "cypress/no-unnecessary-waiting": "error", + "cypress/assertion-before-screenshot": "warn", + "cypress/no-force": "warn", + "cypress/no-async-tests": "error", + "cypress/no-pause": "error", + }, + languageOptions: { + globals: { + cy: "readonly", + Cypress: "readonly", + }, + }, + }, ]; diff --git a/package.json b/package.json index c1c39c705..c0dadddbc 100644 --- a/package.json +++ b/package.json @@ -34,11 +34,11 @@ "@babel/preset-env": "7.28.6", "@babel/preset-react": "7.28.5", "@babel/preset-typescript": "7.28.5", - "@eslint/compat": "1.4.1", + "@eslint/compat": "2.0.1", "@eslint/eslintrc": "3.3.3", "@eslint/js": "9.39.2", "@percy/cli": "1.31.8", - "@percy/storybook": "6.0.4", + "@percy/storybook": "9.1.0", "@semantic-release/changelog": "6.0.3", "@semantic-release/git": "10.0.1", "@storybook/addon-a11y": "8.6.15", @@ -55,28 +55,28 @@ "@testing-library/jest-dom": "6.9.1", "@testing-library/react": "16.3.1", "@testing-library/user-event": "14.6.1", - "babel-jest": "29.7.0", - "babel-loader": "9.2.1", + "babel-jest": "30.2.0", + "babel-loader": "10.0.0", "babel-plugin-module-resolver": "5.0.2", "babel-plugin-typescript-to-proptypes": "2.1.0", "concurrently": "9.2.1", "css-loader": "7.1.2", - "cypress": "14.5.4", + "cypress": "15.9.0", "deepmerge": "4.3.1", "eslint": "9.39.2", "eslint-config-prettier": "10.1.8", - "eslint-plugin-cypress": "4.3.0", + "eslint-plugin-cypress": "5.2.1", "eslint-plugin-flowtype": "8.0.3", "eslint-plugin-import": "2.32.0", "eslint-plugin-jsx-a11y": "6.10.2", "eslint-plugin-prettier": "5.5.5", "eslint-plugin-react": "7.37.5", - "eslint-plugin-react-hooks": "5.2.0", + "eslint-plugin-react-hooks": "7.0.1", "eslint-plugin-storybook": "0.12.0", "eslint-plugin-testing-library": "7.15.4", "formik": "2.4.9", "jest": "29.7.0", - "npm-package-json-lint": "8.0.0", + "npm-package-json-lint": "9.1.0", "prettier": "3.8.0", "react": "19.2.3", "react-docgen-typescript-loader": "3.7.2", @@ -87,28 +87,28 @@ "storybook": "8.6.15", "strip-ansi": "7.1.2", "style-loader": "4.0.0", - "stylelint": "16.26.1", + "stylelint": "17.0.0", "stylelint-config-prettier": "9.0.5", - "stylelint-config-recommended-scss": "14.1.0", - "stylelint-order": "6.0.4", + "stylelint-config-recommended-scss": "17.0.0", + "stylelint-order": "7.0.1", "stylelint-prettier": "5.0.3", "ts-jest": "29.2.5", "tsc-alias": "1.8.10", "typescript": "5.7.3", "typescript-eslint": "8.24.1", "vanilla-framework": "4.44.0", - "wait-on": "8.0.2", + "wait-on": "9.0.3", "webpack": "5.105.0" }, "dependencies": { - "@types/jest": "29.5.14", + "@types/jest": "30.0.0", "@types/node": "20.19.30", - "@types/react": "19.0.10", - "@types/react-dom": "19.0.4", + "@types/react": "19.2.0", + "@types/react-dom": "19.2.0", "@types/react-table": "7.7.20", "classnames": "2.5.1", "fast-deep-equal": "3.1.3", - "jest-environment-jsdom": "29.7.0", + "jest-environment-jsdom": "30.2.0", "prop-types": "15.8.1", "react-table": "7.8.0" }, diff --git a/src/components/Accordion/AccordionSection/__snapshots__/AccordionSection.test.tsx.snap b/src/components/Accordion/AccordionSection/__snapshots__/AccordionSection.test.tsx.snap index b65588f0a..a931149d2 100644 --- a/src/components/Accordion/AccordionSection/__snapshots__/AccordionSection.test.tsx.snap +++ b/src/components/Accordion/AccordionSection/__snapshots__/AccordionSection.test.tsx.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`AccordionSection renders 1`] = `
  • diff --git a/src/components/CustomSelect/__snapshots__/CustomSelect.test.tsx.snap b/src/components/CustomSelect/__snapshots__/CustomSelect.test.tsx.snap index d4942a188..ccddcfd86 100644 --- a/src/components/CustomSelect/__snapshots__/CustomSelect.test.tsx.snap +++ b/src/components/CustomSelect/__snapshots__/CustomSelect.test.tsx.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`CustomSelect renders 1`] = `
    = ({ (totalValue, segment) => (totalValue += segment.value), 0, ); - let accumulatedLength = 0; - const segmentNodes = segments.map(({ color, tooltip, value }, i) => { + + // Pre-calculate the accumulated lengths. + const segmentsWithOffsets = segments.reduce((acc, segment, i) => { + const previousSegment = i > 0 ? acc[i - 1] : null; // The start position is the value of all previous segments. - const startPosition = accumulatedLength; + const startPosition = + i === 0 + ? 0 + : previousSegment.startPosition + previousSegment.segmentLength; // The length of the segment (as a portion of the doughnut circumference) - const segmentLength = (value / total) * circumference; + const segmentLength = (segment.value / total) * circumference; // The space left until the end of the circle. const remainingSpace = circumference - (segmentLength + startPosition); - // Add this segment length to the running tally. - accumulatedLength += segmentLength; - return ( - { - // Hide the tooltip. - setTooltipMessage(null); - } - : undefined - } - onMouseOver={ - tooltip - ? () => { - setTooltipMessage(tooltip); - } - : undefined - } - r={radius} - style={{ - stroke: color, - strokeWidth: segmentThickness, - // The dash array used is: - // 1 - We want there to be a space before the first visible dash so - // by setting this to 0 we can use the next dash for the space. - // 2 - This gap is the distance of all previous segments - // so that the segment starts in the correct spot. - // 3 - A dash that is the length of the segment. - // 4 - A gap from the end of the segment to the start of the circle - // so that the dash array doesn't repeat and be visible. - strokeDasharray: `0 ${startPosition.toFixed( - 2, - )} ${segmentLength.toFixed(2)} ${remainingSpace.toFixed(2)}`, - }} - // Rotate the segment so that the segments start at the top of - // the chart. - transform={`rotate(-90 ${radius},${radius})`} - /> - ); - }); + acc.push({ + ...segment, + startPosition, + segmentLength, + remainingSpace, + }); + return acc; + }, []); + + // Map over the enriched data. + const segmentNodes = segmentsWithOffsets.map( + ( + { color, tooltip, value, startPosition, segmentLength, remainingSpace }, + i, + ) => { + return ( + { + // Hide the tooltip. + setTooltipMessage(null); + } + : undefined + } + onMouseOver={ + tooltip + ? () => { + setTooltipMessage(tooltip); + } + : undefined + } + r={radius} + style={{ + stroke: color, + strokeWidth: segmentThickness, + // The dash array used is: + // 1 - We want there to be a space before the first visible dash so + // by setting this to 0 we can use the next dash for the space. + // 2 - This gap is the distance of all previous segments + // so that the segment starts in the correct spot. + // 3 - A dash that is the length of the segment. + // 4 - A gap from the end of the segment to the start of the circle + // so that the dash array doesn't repeat and be visible. + strokeDasharray: `0 ${startPosition.toFixed( + 2, + )} ${segmentLength.toFixed(2)} ${remainingSpace.toFixed(2)}`, + }} + // Rotate the segment so that the segments start at the top of + // the chart. + transform={`rotate(-90 ${radius},${radius})`} + /> + ); + }, + ); return (
    diff --git a/src/components/Label/__snapshots__/Label.test.tsx.snap b/src/components/Label/__snapshots__/Label.test.tsx.snap index 63d9aebe2..31b14bf16 100644 --- a/src/components/Label/__snapshots__/Label.test.tsx.snap +++ b/src/components/Label/__snapshots__/Label.test.tsx.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`Label renders 1`] = `