Skip to content

Commit

Permalink
feat: Create Component "Tag" (#48) (#35)
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasOmar authored Mar 7, 2023
2 parents 3380b6d + 9013a67 commit 225378c
Show file tree
Hide file tree
Showing 19 changed files with 372 additions and 39 deletions.
2 changes: 2 additions & 0 deletions src/components/atoms/Block/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import { BlockProps } from '../../../interfaces/atomProps'

const Block: React.FC<BlockProps> = ({
testId = 'test-block',
style = null,
children = null
}) =>
children ? (
<section
data-testid={testId}
className='block'
style={style || undefined}
>
{children}
</section>
Expand Down
1 change: 1 addition & 0 deletions src/components/atoms/Button/index.mocks.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"basicTestId": "test-button-primary",
"dummyText": "Hello there",
"testStyles": {
"paddingTop": "10px",
Expand Down
2 changes: 1 addition & 1 deletion src/components/atoms/Button/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default {
const Template: ComponentStory<typeof Button> = args => <Button {...args} />

export const NoText = Template.bind({})
NoText.storyName = 'Basic'
NoText.storyName = 'No Text'

export const WithText = Template.bind({})
WithText.storyName = 'With Text'
Expand Down
16 changes: 9 additions & 7 deletions src/components/atoms/Button/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@ import Button from '.'
import mocks from './index.mocks.json'

describe('Button', () => {
const buttonTestId = 'test-button'

test('Should render the Button without text', () => {
render(<Button />)
const testButton = screen.getByTestId(buttonTestId)
const testButton = screen.getByTestId(mocks.basicTestId)
expect(testButton).toBeInTheDocument()
})

Expand All @@ -26,7 +24,7 @@ describe('Button', () => {
const styleValue = (mocks.testStyles as any)[prop]
const styleObj = { [prop]: styleValue }
render(<Button style={styleObj} />)
const styleButton = screen.getByTestId(buttonTestId)
const styleButton = screen.getByTestId(mocks.basicTestId)
expect(styleButton.style[prop as any]).toContain(styleValue)
cleanup()
})
Expand All @@ -36,8 +34,12 @@ describe('Button', () => {
Object.keys(mocks.testClasses).forEach(prop => {
const classValue = (mocks.testClasses as any)[prop]
const classObj = { [prop]: classValue }
const testIdWithClass = `${mocks.basicTestId}-${classValue.replace(
'is-',
''
)}`
render(<Button {...classObj} />)
const classButton = screen.getByTestId(buttonTestId)
const classButton = screen.getByTestId(testIdWithClass)
expect(classButton.className).toContain(classValue)
cleanup()
})
Expand All @@ -46,7 +48,7 @@ describe('Button', () => {
test('Should check that the button has been clicked', () => {
const clickeableConfig = { onClick: jest.fn() }
render(<Button {...clickeableConfig} />)
const clickButton = screen.getByTestId(buttonTestId)
const clickButton = screen.getByTestId(mocks.basicTestId)
fireEvent.click(clickButton)
expect(clickeableConfig.onClick).toHaveBeenCalled()
expect(clickeableConfig.onClick).toHaveBeenCalledTimes(1)
Expand All @@ -59,7 +61,7 @@ describe('Button', () => {
}

render(<Button {...notClickeableBtn} />)
const disabledButton = screen.getByTestId(buttonTestId)
const disabledButton = screen.getByTestId(mocks.basicTestId)

fireEvent.click(disabledButton)
expect(notClickeableBtn.onClick).not.toHaveBeenCalled()
Expand Down
7 changes: 5 additions & 2 deletions src/components/atoms/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import React from 'react'
// COMPONENT
import { ButtonProps } from '../../../interfaces/atomProps'
// PARSERS
import { parseClasses } from '../../../functions/persers'
import { parseClasses, parseTestId } from '../../../functions/persers'

const Button: React.FC<ButtonProps> = ({
text = null,
type = 'button',
testId = null,
style = null,
color = 'is-primary',
isLightColor = false,
Expand All @@ -30,10 +31,12 @@ const Button: React.FC<ButtonProps> = ({
isStatic ? 'is-static' : null,
size
])
const _testId =
testId ?? parseTestId({ tag: 'button', parsedClasses: buttonClasses })

return (
<button
data-testid='test-button'
data-testid={_testId}
type={type}
className={buttonClasses}
style={style ?? undefined}
Expand Down
13 changes: 9 additions & 4 deletions src/components/atoms/Column/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,30 @@ import React from 'react'
// PROPS
import { ColumnProps } from '../../../interfaces/atomProps'
// PARSERS
import { parseClasses } from '../../../functions/persers'
import { parseClasses, parseTestId } from '../../../functions/persers'

const Column: React.FC<ColumnProps> = ({
testId = null,
style = null,
size = null,
offset = null,
isNarrow = false,
children = null
}) => {
const classes = parseClasses([
const columnClasses = parseClasses([
'column',
size,
offset,
isNarrow ? 'is-narrow' : null
])
const _testId =
testId ?? parseTestId({ tag: 'column', parsedClasses: columnClasses })

return (
<section
data-testid='test-column'
className={classes}
data-testid={_testId}
className={columnClasses}
style={style || undefined}
>
{children}
</section>
Expand Down
1 change: 1 addition & 0 deletions src/components/atoms/ProgressBar/index.mocks.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"basicTestId": "test-progress-primary",
"test": {
"inputValues": [0, 20, 100, 130, 200, -1, -20],
"outputValues": [0, 20, 100, 0, 0, 0, 0]
Expand Down
7 changes: 3 additions & 4 deletions src/components/atoms/ProgressBar/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,18 @@ import ProgressBar from '.'
import mocks from './index.mocks.json'

describe('ProgressBar', () => {
const progressBarId = 'test-progress-bar'
const { inputValues, outputValues } = mocks.test

test('Should render without any props', () => {
render(<ProgressBar />)
const testProgressBar = screen.getByTestId(progressBarId)
const testProgressBar = screen.getByTestId(mocks.basicTestId)
expect(testProgressBar).toBeInTheDocument()
})

test('Should render the value having in mind fixed logic', () => {
inputValues.forEach((_input, i) => {
render(<ProgressBar value={_input} />)
const testInputProgress = screen.getByTestId(progressBarId)
const testInputProgress = screen.getByTestId(mocks.basicTestId)
expect(testInputProgress.innerHTML).toBe(`${outputValues[i]}%`)
cleanup()
})
Expand All @@ -33,7 +32,7 @@ describe('ProgressBar', () => {
isLoading={true}
/>
)
const testInputProgress = screen.getByTestId(progressBarId)
const testInputProgress = screen.getByTestId(mocks.basicTestId)
expect(testInputProgress.innerHTML).toBe('0%')
cleanup()
})
Expand Down
13 changes: 10 additions & 3 deletions src/components/atoms/ProgressBar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
import React from 'react'
import { parseClasses } from '../../../functions/persers'
import { parseClasses, parseTestId } from '../../../functions/persers'
import { ProgressBarProps } from '../../../interfaces/atomProps'

const ProgressBar: React.FC<ProgressBarProps> = ({
value = 0,
max = 100,
testId = null,
style = null,
color = 'is-primary',
size = null,
isLoading = false
}) => {
const progressClasses: string = parseClasses(['progress', color, size])
const fixedValue: number = value > max || value < 0 ? 0 : value
const progressClasses: string = parseClasses(['progress', color, size])
const _testId =
testId ??
parseTestId({
tag: 'progress',
parsedClasses: progressClasses
})

return (
<progress
data-testid='test-progress-bar'
data-testid={_testId}
className={progressClasses}
style={style ?? undefined}
value={isLoading ? undefined : value}
Expand Down
17 changes: 17 additions & 0 deletions src/components/atoms/Tag/index.mocks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"test": {
"baseConfig": {
"text": "Test text"
},
"colors": ["is-black", "is-danger", "is-warning"],
"sizes": ["is-small", "is-medium", "is-large"],
"testClasses": {
"isLight": "is-light",
"isRounded": "is-rounded"
},
"addonConfig": {
"withAddon": true,
"addonText": "Addon Text"
}
}
}
74 changes: 74 additions & 0 deletions src/components/atoms/Tag/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react'
import { ComponentStory, ComponentMeta } from '@storybook/react'
// COMPONENTS
import Tag from '.'
// MOCKS
import mocks from './index.mocks.json'

export default {
title: 'Atoms/Tag',
component: Tag
} as ComponentMeta<typeof Tag>

const Template: ComponentStory<typeof Tag> = args => <Tag {...args} />

export const BasicExample = Template.bind({})
BasicExample.storyName = 'With a text'
BasicExample.args = { ...mocks.test.baseConfig }

export const Colored = Template.bind({})
Colored.storyName = 'Colored'
Colored.args = {
...BasicExample.args,
color: 'is-danger'
}

export const Rounded = Template.bind({})
Rounded.storyName = 'Rounded'
Rounded.args = {
...Colored.args,
isRounded: true
}

export const Light = Template.bind({})
Light.storyName = 'Light color'
Light.args = {
...Colored.args,
isLight: true
}

export const LargeSize = Template.bind({})
LargeSize.storyName = 'Large Size'
LargeSize.args = {
...Colored.args,
size: 'is-large'
}

export const WithDelete = Template.bind({})
WithDelete.storyName = 'With a Delete'
WithDelete.args = {
...Colored.args,
withDelete: true
}

export const WithAddon = Template.bind({})
WithAddon.storyName = 'With an Addon'
WithAddon.args = {
...Colored.args,
withAddon: true,
addonText: 'Addon'
}

export const ColoredAddon = Template.bind({})
ColoredAddon.storyName = 'Colored Addon'
ColoredAddon.args = {
...WithAddon.args,
addonColor: 'is-info'
}

export const WithDeleteAddon = Template.bind({})
WithDeleteAddon.storyName = 'With a Delete Addon'
WithDeleteAddon.args = {
...WithAddon.args,
withDelete: true
}
84 changes: 84 additions & 0 deletions src/components/atoms/Tag/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import React from 'react'
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
import '@testing-library/jest-dom'
// COMPONENT
import Tag from '.'
// TYPES & INTERFACES
import { basicColorType, sizeType } from '../../../types/styleTypes'
import { TagProps } from '../../../interfaces/atomProps'
// MOCKS
import mocks from './index.mocks.json'

describe('Tag', () => {
const { baseConfig, colors, testClasses, addonConfig, sizes } = mocks.test
let tagConfig: TagProps = baseConfig

test('Should render with required props only', () => {
render(<Tag {...tagConfig} />)
const testTag = screen.getByText(tagConfig.text)
expect(testTag).toBeInTheDocument()
})

test('Should render with different colors', () => {
colors.forEach(_color => {
const coloredTestId = `test-tag-${_color.replace('is-', '')}`
render(<Tag {...{ ...baseConfig, color: _color as basicColorType }} />)
const testColorTag = screen.getByTestId(coloredTestId)
expect(testColorTag.classList).toContain(_color)
})
})

test('Should render with different sizes', () => {
sizes.forEach(_size => {
const coloredTestId = `test-tag-${_size.replace('is-', '')}`
render(
<Tag
{...{ ...baseConfig, size: _size as Exclude<sizeType, 'is-normal'> }}
/>
)
const testColorTag = screen.getByTestId(coloredTestId)
expect(testColorTag.classList).toContain(_size)
})
})

test('Should render with different classes', () => {
Object.keys(testClasses).forEach(prop => {
const classValue = (testClasses as any)[prop]
const testIdWithClass = `test-tag-${classValue.replace('is-', '')}`
render(<Tag {...{ ...baseConfig, [prop]: classValue }} />)
const classButton = screen.getByTestId(testIdWithClass)
expect(classButton.className).toContain(classValue)
cleanup()
})
})

test('Should check that its delete button has been clicked', () => {
tagConfig = { ...baseConfig, withDelete: true, onDeleteClick: jest.fn() }
render(<Tag {...tagConfig} />)
const clickButton = screen.getByTestId('test-tag-delete')
fireEvent.click(clickButton)
expect(tagConfig.onDeleteClick).toHaveBeenCalled()
expect(tagConfig.onDeleteClick).toHaveBeenCalledTimes(1)
})

test('Should render the tags variation with its addon text', () => {
const tagsTestId = 'test-tags-has-addons'
render(<Tag {...{ ...baseConfig, ...addonConfig }} />)
const testTags = screen.getByTestId(tagsTestId)
expect(testTags).toBeInTheDocument()
})

test('Should check that its delete button has been clicked with the tags variation', () => {
tagConfig = {
...baseConfig,
withAddon: true,
withDelete: true,
onDeleteClick: jest.fn()
}
render(<Tag {...tagConfig} />)
const clickButton = screen.getByTestId('test-tags-has-addons-delete')
fireEvent.click(clickButton)
expect(tagConfig.onDeleteClick).toHaveBeenCalled()
expect(tagConfig.onDeleteClick).toHaveBeenCalledTimes(1)
})
})
Loading

0 comments on commit 225378c

Please sign in to comment.