Skip to content

Commit 4686667

Browse files
authored
Merge pull request #33 from LGLabGreg/test-vitest
test: Add vitest
2 parents 099fa28 + fcc5d5a commit 4686667

25 files changed

Lines changed: 2710 additions & 239 deletions

.github/workflows/manual-release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ jobs:
4545
- name: Install Dependencies
4646
run: pnpm install
4747

48+
- name: Run tests
49+
run: pnpm test
50+
4851
- name: Setup Git
4952
run: |
5053
git config user.name 'github-actions[bot]'

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ yarn-debug.log*
66
yarn-error.log*
77
pnpm-debug.log*
88
lerna-debug.log*
9+
coverage
910

1011
node_modules
1112
dist

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
npx --no-install lint-staged
2+
pnpm test

apps/playground/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@
99
},
1010
"dependencies": {
1111
"@lglab/react-qr-code": "workspace:*",
12-
"@tailwindcss/vite": "^4.0.2",
12+
"@tailwindcss/vite": "^4.0.4",
1313
"react": "^19.0.0",
1414
"react-dom": "^19.0.0",
15-
"tailwindcss": "^4.0.1"
15+
"tailwindcss": "^4.0.4"
1616
},
1717
"devDependencies": {
18-
"@types/node": "^22.12.0",
18+
"@types/node": "^22.13.1",
1919
"@types/react": "^19.0.8",
2020
"@types/react-dom": "^19.0.3",
2121
"@vitejs/plugin-react": "^4.3.4",
2222
"globals": "^15.14.0",
2323
"typescript": "~5.7.3",
24-
"vite": "^6.0.5"
24+
"vite": "^6.1.0"
2525
}
2626
}

package.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
"build:lib": "pnpm --filter \"./packages/**\" run build",
1515
"build:app": "pnpm --filter \"./apps/**\" run build",
1616
"ci:publish": "pnpm publish -r",
17+
"test": "vitest run",
18+
"test:watch": "vitest",
19+
"test:coverage": "vitest run --coverage",
1720
"lint": "eslint .",
1821
"prepare": "husky"
1922
},
@@ -26,19 +29,27 @@
2629
"devDependencies": {
2730
"@changesets/cli": "^2.27.12",
2831
"@eslint/js": "^9.19.0",
32+
"@testing-library/jest-dom": "^6.6.3",
33+
"@testing-library/react": "^16.2.0",
2934
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
35+
"@types/jsdom": "^21.1.7",
36+
"@types/node": "^22.12.0",
37+
"@vitejs/plugin-react": "^4.3.4",
38+
"@vitest/coverage-v8": "3.0.5",
3039
"concurrently": "^9.1.2",
3140
"eslint": "^9.19.0",
3241
"eslint-plugin-react": "^7.37.4",
3342
"eslint-plugin-react-hooks": "^5.1.0",
3443
"eslint-plugin-react-refresh": "^0.4.18",
3544
"globals": "^15.14.0",
3645
"husky": "^9.1.7",
46+
"jsdom": "^26.0.0",
3747
"lint-staged": "^15.4.3",
3848
"react": "^19.0.0",
3949
"react-dom": "^19.0.0",
4050
"typescript": "~5.7.3",
4151
"typescript-eslint": "^8.23.0",
42-
"vite": "^6.0.5"
52+
"vite": "^6.1.0",
53+
"vitest": "^3.0.5"
4354
}
4455
}

packages/react-qr-code/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
"react": "^18 || ^19"
3131
},
3232
"devDependencies": {
33-
"@types/node": "^22.12.0",
33+
"@types/node": "^22.13.1",
3434
"@types/react": "^19.0.8",
3535
"@types/react-dom": "^19.0.3",
3636
"@vitejs/plugin-react": "^4.3.4",
@@ -39,7 +39,7 @@
3939
"react-dom": "^19.0.0",
4040
"typescript": "~5.7.3",
4141
"typescript-eslint": "^8.23.0",
42-
"vite": "^6.0.5",
42+
"vite": "^6.1.0",
4343
"vite-plugin-dts": "^4.5.0"
4444
}
4545
}

packages/react-qr-code/src/components/background.tsx

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,25 @@ interface BackgroundProps {
77
numCells: number
88
}
99

10+
const testProps = {
11+
'data-testid': 'background',
12+
}
13+
1014
export const Background = ({ background, numCells }: BackgroundProps) => {
1115
if (!background) {
12-
return <path fill={DEFAULT_BGCOLOR} d={`M0,0 h${numCells}v${numCells}H0z`} />
16+
return (
17+
<path
18+
fill={DEFAULT_BGCOLOR}
19+
d={`M0,0 h${numCells}v${numCells}H0z`}
20+
{...testProps}
21+
/>
22+
)
1323
}
1424

1525
if (typeof background === 'string') {
16-
return <path fill={background} d={`M0,0 h${numCells}v${numCells}H0z`} />
26+
return (
27+
<path fill={background} d={`M0,0 h${numCells}v${numCells}H0z`} {...testProps} />
28+
)
1729
}
1830

1931
const vectors = calculateGradientVectors(background?.rotation || 0)
@@ -41,7 +53,11 @@ export const Background = ({ background, numCells }: BackgroundProps) => {
4153
</radialGradient>
4254
)}
4355
</defs>
44-
<path fill={`url(#${BG_GRADIENT_ID})`} d={`M0,0 h${numCells}v${numCells}H0z`} />
56+
<path
57+
fill={`url(#${BG_GRADIENT_ID})`}
58+
d={`M0,0 h${numCells}v${numCells}H0z`}
59+
{...testProps}
60+
/>
4561
</>
4662
)
4763
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { render } from '@testing-library/react'
2+
import { describe, expect, it, vi } from 'vitest'
3+
4+
import {
5+
dataModulesHorizontalLineNeighbours,
6+
dataModulesLeafNeighbours,
7+
dataModulesRoundedNeighbours,
8+
dataModulesVerticalLineNeighbours,
9+
} from '../test/data-modules-neightbours'
10+
import type { DataModulesStyle } from '../types/lib'
11+
import type { DataModulesNeighbours } from '../types/utils'
12+
import * as dataModulesUtils from '../utils/data-modules'
13+
import * as svgUtils from '../utils/svg'
14+
import { DataModules } from './data-modules'
15+
16+
describe('DataModules', () => {
17+
const mockModules = [
18+
[true, false, true],
19+
[false, true, false],
20+
[true, false, true],
21+
]
22+
23+
const getModuleNeighboursSpy = vi.spyOn(dataModulesUtils, 'getModuleNeighbours')
24+
25+
const defaultProps = {
26+
modules: mockModules,
27+
margin: 2,
28+
}
29+
30+
it('calls the correct shape function based on style prop', () => {
31+
const stylesToMethods = {
32+
square: 'square',
33+
circle: 'circle',
34+
diamond: 'diamond',
35+
heart: 'heart',
36+
star: 'star',
37+
}
38+
39+
Object.entries(stylesToMethods).forEach(([style, method]) => {
40+
const utils = style === 'heart' || style === 'star' ? svgUtils : dataModulesUtils
41+
const spy = vi.spyOn(utils, method as keyof typeof utils)
42+
43+
render(
44+
<DataModules settings={{ style: style as DataModulesStyle }} {...defaultProps} />,
45+
)
46+
47+
expect(spy).toHaveBeenCalled()
48+
})
49+
})
50+
51+
it.each(dataModulesRoundedNeighbours)(
52+
`with neighbours %j calls the correct shape function %s for style rounded`,
53+
(neighbours, method) => {
54+
getModuleNeighboursSpy.mockImplementation(() => neighbours as DataModulesNeighbours)
55+
const methodSpy = vi.spyOn(
56+
dataModulesUtils,
57+
method as keyof typeof dataModulesUtils,
58+
)
59+
60+
render(<DataModules settings={{ style: 'rounded' }} {...defaultProps} />)
61+
62+
expect(methodSpy).toHaveBeenCalled()
63+
},
64+
)
65+
66+
it.each(dataModulesLeafNeighbours)(
67+
`with neighbours %j calls the correct shape function %s for style leaf`,
68+
(neighbours, method) => {
69+
getModuleNeighboursSpy.mockImplementation(() => neighbours as DataModulesNeighbours)
70+
const methodSpy = vi.spyOn(
71+
dataModulesUtils,
72+
method as keyof typeof dataModulesUtils,
73+
)
74+
75+
render(<DataModules settings={{ style: 'leaf' }} {...defaultProps} />)
76+
77+
expect(methodSpy).toHaveBeenCalled()
78+
},
79+
)
80+
81+
it.each(dataModulesVerticalLineNeighbours)(
82+
`with neighbours %j calls the correct shape function %s for style leaf`,
83+
(neighbours, method) => {
84+
getModuleNeighboursSpy.mockImplementation(() => neighbours as DataModulesNeighbours)
85+
const methodSpy = vi.spyOn(
86+
dataModulesUtils,
87+
method as keyof typeof dataModulesUtils,
88+
)
89+
90+
render(<DataModules settings={{ style: 'vertical-line' }} {...defaultProps} />)
91+
92+
expect(methodSpy).toHaveBeenCalled()
93+
},
94+
)
95+
96+
it.each(dataModulesHorizontalLineNeighbours)(
97+
`with neighbours %j calls the correct shape function %s for style leaf`,
98+
(neighbours, method) => {
99+
getModuleNeighboursSpy.mockImplementation(() => neighbours as DataModulesNeighbours)
100+
const methodSpy = vi.spyOn(
101+
dataModulesUtils,
102+
method as keyof typeof dataModulesUtils,
103+
)
104+
105+
render(<DataModules settings={{ style: 'horizontal-line' }} {...defaultProps} />)
106+
107+
expect(methodSpy).toHaveBeenCalled()
108+
},
109+
)
110+
})

packages/react-qr-code/src/components/data-modules.tsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
circle,
88
dataModuleCanBeRandomSize,
99
diamond,
10+
getScaleFactor,
1011
leaf,
1112
leftRounded,
1213
rightRounded,
@@ -40,14 +41,10 @@ export const DataModules = ({
4041
const numCells = modules.length
4142
const isRandom = dataModuleCanBeRandomSize(style) && randomSize
4243

43-
const getScaleFactor = useCallback(() => {
44-
if (style === 'square-sm') {
45-
return 0.75
46-
} else if (isRandom) {
47-
return Math.random() * (1 - 0.75) + 0.75
48-
}
49-
return 1
50-
}, [style, isRandom])
44+
const scaleFactor = useCallback(
45+
() => getScaleFactor(style, isRandom),
46+
[style, isRandom],
47+
)
5148

5249
modules.forEach((row, y) => {
5350
row.forEach((cell, x) => {
@@ -59,9 +56,9 @@ export const DataModules = ({
5956
return
6057
}
6158

62-
const scaleFactor = getScaleFactor()
63-
const size = 1 * scaleFactor
64-
const posOffset = (1 - 1 * scaleFactor) / 2
59+
const scale = scaleFactor()
60+
const size = 1 * scale
61+
const posOffset = (1 - 1 * scale) / 2
6562
const xPos = x + margin + posOffset
6663
const yPos = y + margin + posOffset
6764

@@ -152,6 +149,7 @@ export const DataModules = ({
152149
fill={gradient ? `url(#${GRADIENT_ID})` : color}
153150
d={ops.join('')}
154151
shapeRendering={style === 'square' ? 'crispEdges' : 'geometricPrecision'}
152+
data-testid='data-modules'
155153
/>
156154
)
157155
}

0 commit comments

Comments
 (0)