mirror of
https://github.com/joinmarket-webui/jam.git
synced 2026-08-13 12:33:26 +02:00
build(ci): report test coverage (#1241)
This commit is contained in:
parent
1b37ad3169
commit
a5d47c8be0
6 changed files with 57 additions and 24 deletions
14
.github/workflows/build.yml
vendored
14
.github/workflows/build.yml
vendored
|
|
@ -15,10 +15,10 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup (Node.js ${{ matrix.node-version }})
|
||||
uses: actions/setup-node@v5
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
run: echo "PLAYWRIGHT_VERSION=$(node -e "console.log(require('./package-lock.json').packages['node_modules/@playwright/test'].version)")" >> $GITHUB_ENV
|
||||
|
||||
- name: Cache Playwright
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
id: playwright-cache
|
||||
with:
|
||||
path: |
|
||||
|
|
@ -50,7 +50,13 @@ jobs:
|
|||
run: npm run format:check
|
||||
|
||||
- name: Test
|
||||
run: npm test
|
||||
run: npm test -- --coverage.enabled
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Upload coverage report
|
||||
# Set if: always() to also generate the report if tests are failing
|
||||
# Only works if you set `reportOnFailure: true` in vite config
|
||||
if: always()
|
||||
uses: davelosert/vitest-coverage-report-action@v2
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -29,3 +29,4 @@ dist-ssr
|
|||
|
||||
*storybook.log
|
||||
storybook-static/
|
||||
coverage/
|
||||
|
|
|
|||
12
src/lib/hash.slow.test.ts
Normal file
12
src/lib/hash.slow.test.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { describe, it, expect } from 'vitest'
|
||||
import { DEFAULT_PBKDF_ITERATIONS, hashPassword } from './hash'
|
||||
|
||||
// **NOTE**: Seems there are issues generating code coverage via v8 for long running/blocking tests.
|
||||
// Externalized to own file for exclusion in coverage settings.
|
||||
describe('hash (slow)', () => {
|
||||
it('hashPassword', { timeout: 20_000 }, async () => {
|
||||
expect(await hashPassword('test', 'Satoshi.jmdat', DEFAULT_PBKDF_ITERATIONS)).toBe(
|
||||
'da41454ecc40c48499decbca7b1df4595f0a856caada3f182d47293fbad03004',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
@ -2,20 +2,23 @@ import { describe, it, expect } from 'vitest'
|
|||
import { DEFAULT_PBKDF_ITERATIONS, hashPassword } from './hash'
|
||||
|
||||
describe('hash', () => {
|
||||
it('DEFAULT_PBKDF_ITERATIONS', () => {
|
||||
expect(DEFAULT_PBKDF_ITERATIONS).toBe(210_000)
|
||||
})
|
||||
|
||||
it('hashPassword', { timeout: 20_000 }, async () => {
|
||||
expect(await hashPassword('', '', 1)).toBe('6d2ecbbbfb2e6dcd7056faf9af6aa06eae594391db983279a6bf27e0eb228614')
|
||||
expect(await hashPassword('password', 'salt', 1)).toBe(
|
||||
'867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252',
|
||||
)
|
||||
expect(await hashPassword('test', 'Satoshi.jmdat', 21)).toBe(
|
||||
'1acb29f6e7c841823a9a2369d2f2cc7e9ee19c78621c4d7194d1f45eb0d5e8ed',
|
||||
)
|
||||
expect(await hashPassword('test', 'Satoshi.jmdat', DEFAULT_PBKDF_ITERATIONS)).toBe(
|
||||
'da41454ecc40c48499decbca7b1df4595f0a856caada3f182d47293fbad03004',
|
||||
)
|
||||
describe('hashPassword', () => {
|
||||
it('DEFAULT_PBKDF_ITERATIONS', () => {
|
||||
expect(DEFAULT_PBKDF_ITERATIONS).toBe(210_000)
|
||||
})
|
||||
it('hashPassword success', { timeout: 20_000 }, async () => {
|
||||
expect(await hashPassword('', '', 1)).toBe('6d2ecbbbfb2e6dcd7056faf9af6aa06eae594391db983279a6bf27e0eb228614')
|
||||
expect(await hashPassword('password', 'salt', 1)).toBe(
|
||||
'867f70cf1ade02cff3752599a3a53dc4af34c7a669815ae5d513554e1c8cf252',
|
||||
)
|
||||
expect(await hashPassword('test', 'Satoshi.jmdat', 21)).toBe(
|
||||
'1acb29f6e7c841823a9a2369d2f2cc7e9ee19c78621c4d7194d1f45eb0d5e8ed',
|
||||
)
|
||||
})
|
||||
it('hashPassword error', { timeout: 20_000 }, async () => {
|
||||
await expect(async () => {
|
||||
return await hashPassword('', '', -1)
|
||||
}).rejects.toThrowError('Failed to hash password: "c" expected integer >= 0, got -1')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { pbkdf2Async } from '@noble/hashes/pbkdf2.js'
|
||||
import { pbkdf2Async, type Pbkdf2Opt } from '@noble/hashes/pbkdf2.js'
|
||||
import { sha512 } from '@noble/hashes/sha2.js'
|
||||
import { bytesToHex } from '@noble/hashes/utils.js'
|
||||
|
||||
// see https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pbkdf2 (last check: 2026-01)
|
||||
export const DEFAULT_PBKDF_ITERATIONS = 210_000
|
||||
export const DEFAULT_PBKDF_ITERATIONS: Pbkdf2Opt['c'] = 210_000
|
||||
|
||||
/**
|
||||
* Securely hashes a password using PBKDF2 with SHA-512.
|
||||
|
|
@ -16,7 +16,7 @@ export const DEFAULT_PBKDF_ITERATIONS = 210_000
|
|||
export async function hashPassword(
|
||||
password: string,
|
||||
salt: string,
|
||||
iterations = DEFAULT_PBKDF_ITERATIONS,
|
||||
iterations: Pbkdf2Opt['c'] = DEFAULT_PBKDF_ITERATIONS,
|
||||
): Promise<string> {
|
||||
try {
|
||||
const passwordBuffer = new TextEncoder().encode(password)
|
||||
|
|
@ -24,7 +24,6 @@ export async function hashPassword(
|
|||
const derivedKey = await pbkdf2Async(sha512, passwordBuffer, saltBuffer, { c: iterations, dkLen: 32 })
|
||||
return bytesToHex(derivedKey)
|
||||
} catch (error: unknown) {
|
||||
console.error('Password hashing failed:', error)
|
||||
const reason = (error instanceof Error ? (error.message ?? '') : '') || 'Unknown error'
|
||||
throw new Error(`Failed to hash password: ${reason}`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,18 @@ export default defineConfig((args: ConfigEnv): ViteUserConfig => {
|
|||
env: {
|
||||
LC_ALL: 'en_US.UTF-8',
|
||||
},
|
||||
coverage: {
|
||||
// 'json-summary' is required for ci coverage report
|
||||
reporter: ['text', 'json', 'json-summary'],
|
||||
// If you want a coverage reports even if your tests are failing, include the reportOnFailure option
|
||||
reportOnFailure: true,
|
||||
thresholds: {
|
||||
lines: 70,
|
||||
functions: 60,
|
||||
branches: 60,
|
||||
statements: 70,
|
||||
},
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
extends: true,
|
||||
|
|
@ -37,7 +49,7 @@ export default defineConfig((args: ConfigEnv): ViteUserConfig => {
|
|||
environment: 'jsdom',
|
||||
setupFiles: './vitest.setup.ts',
|
||||
include: ['**/*.test.{ts,tsx}'],
|
||||
exclude: ['node_modules', '.storybook'],
|
||||
exclude: ['src/lib/hash.slow.test.ts', 'node_modules', '.storybook'],
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue