Skip to content

Unit Tests, Quality Gate #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Oct 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,8 @@ jobs:
${{ runner.os }}-dist-
${{ runner.os }}-

# - name: UI Unit Tests
# run: yarn test
# working-directory: client
- name: UI Unit Tests
run: yarn test

- if: ${{ steps.cache-build.outputs.cache-hit != 'true' }}
name: Build UI
Expand Down
64 changes: 64 additions & 0 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Quality Gate

on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
types: [opened, synchronize, reopened]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
sonarcloud:
if: github.event.pull_request.draft == false
name: SonarCloud
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'yarn'
cache-dependency-path: 'yarn.lock'

- name: Cache node modules
uses: actions/cache@v4
id: cache-npm
with:
path: |
node_modules
~/.npm
key: ${{ runner.os }}-modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-modules-
${{ runner.os }}-

- if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
name: Install dependencies
run: yarn install

- name: UI Unit Tests
run: yarn test:coverage

- name: Extract version from tag
id: version
run: echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV

- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
args: >
-Dsonar.projectVersion=${{ env.VERSION }}
Binary file modified .yarn/install-state.gz
Binary file not shown.
5 changes: 4 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export default [
'**/eslint.config.mjs',
'**/eslint.config.js',
'**/eslint.config.cjs',
'**/jest.config.ts',
'**/declarations.d.ts',
'**/node_modules/**',
'**/build/**',
Expand Down Expand Up @@ -65,6 +64,10 @@ export default [
'**/.storybook/main.js',
'**/.storybook/preview.js',
'**/storybook-static/',

// Jest
'**/jest.config.ts',
'**/jest.setup.ts',
]
},

Expand Down
16 changes: 16 additions & 0 deletions jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Config } from 'jest'

const config: Config = {
testEnvironment: 'jsdom',
moduleNameMapper: {
'\\.(css|sass|scss)$': 'identity-obj-proxy'
},
transform: {
'^.+\\.tsx?$': ['ts-jest', { useESM: true }]
},
collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/**/*.d.ts'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
transformIgnorePatterns: ['node_modules/(?!(module-to-transform)/)']
}

export default config
12 changes: 12 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
"changeversion": "npx changeset version",
"release": "changeset publish",
"start": "webpack serve --config example/webpack.config.js",
"test": "jest",
"test:coverage": "jest --coverage",
"test:watch": "jest --watch --testNamePattern",
"eslint:check": "eslint",
"eslint:fix": "eslint --fix",
"prettier:check": "prettier --check .",
Expand Down Expand Up @@ -37,6 +40,11 @@
"@rollup/plugin-commonjs": "^28.0.0",
"@rollup/plugin-node-resolve": "^15.3.0",
"@rollup/plugin-terser": "^0.4.4",
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.1",
"@types/identity-obj-proxy": "^3",
"@types/jest": "^29.5.13",
"@types/lodash-es": "^4.17.12",
"@types/react": "^18.3.11",
"@types/react-dom": "^18.3.0",
Expand All @@ -48,7 +56,9 @@
"eslint-plugin-react": "^7.37.1",
"eslint-plugin-simple-import-sort": "^12.1.1",
"globals": "^15.10.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"postcss-sass": "^0.5.0",
"prettier": "^3.3.3",
"rollup": "^4.24.0",
Expand All @@ -58,6 +68,8 @@
"sass": "^1.79.4",
"sass-loader": "^16.0.2",
"style-loader": "^4.0.0",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^5.6.2",
"typescript-eslint": "^8.8.0"
},
Expand Down
23 changes: 23 additions & 0 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Unique project key on SonarCloud
sonar.projectKey=miksrv_simple-react-ui-kit
sonar.organization=miksoft

# Project name and version
sonar.projectName=simple-react-ui-kit
# Version is taken from the tag or package.json
# sonar.projectVersion=1.0

# Path to project sources
sonar.sources=src

# Source code encoding
sonar.sourceEncoding=UTF-8

# Path to test coverage report (if you use Jest for tests)
sonar.javascript.lcov.reportPaths=coverage/lcov.info

# Ignoring folders that should not be scanned (e.g. node_modules or build files)
sonar.exclusions=node_modules/**, build/**, dist/**, storybook/**

# Explicit we indicate that we are analyzing a JavaScript/TypeScript project
sonar.language=js
96 changes: 96 additions & 0 deletions src/components/button/Button.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import React from 'react'

import '@testing-library/jest-dom/jest-globals'
import '@testing-library/jest-dom'

import Button, { ButtonProps } from './Button'

import { fireEvent, screen } from '@testing-library/dom'
import { render } from '@testing-library/react'

describe('Button Component', () => {
const defaultProps: ButtonProps = {
label: 'Click Me',
mode: 'primary',
size: 'medium'
}

it('renders the button with label', () => {
render(<Button {...defaultProps} />)
const buttonElement = screen.getByText(/Click Me/i)
expect(buttonElement).toBeInTheDocument()
})

it('applies the correct className based on mode and size', () => {
render(
<Button
{...defaultProps}
className='custom-class'
/>
)
const buttonElement = screen.getByText(/Click Me/i)
expect(buttonElement).toHaveClass('custom-class')
expect(buttonElement).toHaveClass('button')
expect(buttonElement).toHaveClass('primary')
expect(buttonElement).toHaveClass('medium')
})

it('displays the spinner when loading is true', () => {
const { container } = render(
<Button
{...defaultProps}
loading={true}
/>
)

const iconElement = container.querySelector('svg')
expect(iconElement).toBeInTheDocument()
})

it('renders an icon if icon prop is provided', () => {
const { container } = render(
<Button
{...defaultProps}
icon='CheckCircle'
/>
)
const iconElement = container.querySelector('svg')
expect(iconElement).toBeInTheDocument()
})

it('handles click events', () => {
const handleClick = jest.fn()
render(
<Button
{...defaultProps}
onClick={handleClick}
/>
)
const buttonElement = screen.getByText(/Click Me/i)
fireEvent.click(buttonElement)
expect(handleClick).toHaveBeenCalledTimes(1)
})

it('renders a link if the link prop is provided', () => {
render(
<Button
{...defaultProps}
link='https://example.com'
/>
)
const linkElement = screen.getByRole('link')
expect(linkElement).toHaveAttribute('href', 'https://example.com')
})

it('renders noindex attribute when noIndex is true', () => {
render(
<Button
{...defaultProps}
link='https://example.com'
noIndex={true}
/>
)
const linkElement = screen.getByRole('link')
expect(linkElement).toHaveAttribute('rel', 'noindex nofollow')
})
})
Loading