Skip to content
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
2 changes: 1 addition & 1 deletion docs/functions/findTestById.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

> **findTestById**(`report`, `testId`): `undefined` \| [`Test`](../interfaces/Test.md)

Defined in: src/methods/test-id.ts:84
Defined in: [src/methods/test-id.ts:91](https://github.com/ctrf-io/ctrf-core-js/blob/main/src/methods/test-id.ts#L91)

Finds a test by its ID in a report

Expand Down
2 changes: 1 addition & 1 deletion docs/functions/generateTestIdFromProperties.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

> **generateTestIdFromProperties**(`name`, `suite?`, `filePath?`): `string`

Defined in: src/methods/test-id.ts:95
Defined in: [src/methods/test-id.ts:102](https://github.com/ctrf-io/ctrf-core-js/blob/main/src/methods/test-id.ts#L102)

Generates a new test ID based on test properties (exposed utility)

Expand Down
2 changes: 1 addition & 1 deletion docs/functions/getTestId.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

> **getTestId**(`test`): `string`

Defined in: src/methods/test-id.ts:61
Defined in: [src/methods/test-id.ts:68](https://github.com/ctrf-io/ctrf-core-js/blob/main/src/methods/test-id.ts#L68)

Gets the test ID from a test object, generating one if it doesn't exist

Expand Down
2 changes: 1 addition & 1 deletion docs/functions/setTestId.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

> **setTestId**(`test`): [`Test`](../interfaces/Test.md)

Defined in: src/methods/test-id.ts:49
Defined in: [src/methods/test-id.ts:56](https://github.com/ctrf-io/ctrf-core-js/blob/main/src/methods/test-id.ts#L56)

Sets a test ID for a test object based on its properties

Expand Down
2 changes: 1 addition & 1 deletion docs/functions/setTestIdsForReport.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

> **setTestIdsForReport**(`report`): [`Report`](../interfaces/Report.md)

Defined in: src/methods/test-id.ts:73
Defined in: [src/methods/test-id.ts:80](https://github.com/ctrf-io/ctrf-core-js/blob/main/src/methods/test-id.ts#L80)

Sets test IDs for all tests in a report

Expand Down
2 changes: 1 addition & 1 deletion docs/functions/storePreviousResults.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

> **storePreviousResults**(`currentReport`, `previousReports`): [`Report`](../interfaces/Report.md)

Defined in: [src/methods/store-previous-results.ts:34](https://github.com/ctrf-io/ctrf-core-js/blob/main/src/methods/store-previous-results.ts#L34)
Defined in: [src/methods/store-previous-results.ts:35](https://github.com/ctrf-io/ctrf-core-js/blob/main/src/methods/store-previous-results.ts#L35)

Stores previous results in the current report's previousResults array.
Extracts key metrics from each previous report and adds them to the current report.
Expand Down
2 changes: 1 addition & 1 deletion docs/variables/CTRF_NAMESPACE.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

> `const` **CTRF\_NAMESPACE**: `"6ba7b810-9dad-11d1-80b4-00c04fd430c8"` = `'6ba7b810-9dad-11d1-80b4-00c04fd430c8'`

Defined in: src/methods/test-id.ts:11
Defined in: [src/methods/test-id.ts:11](https://github.com/ctrf-io/ctrf-core-js/blob/main/src/methods/test-id.ts#L11)

The CTRF namespace UUID used for generating deterministic test IDs.
This namespace ensures that all CTRF test IDs are generated consistently
Expand Down
28 changes: 14 additions & 14 deletions examples/test-id-example.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
This example demonstrates how to use the new deterministic test ID functionality.

```typescript
import {
setTestId,
getTestId,
setTestIdsForReport,
import {
setTestId,
getTestId,
setTestIdsForReport,
findTestById,
generateTestIdFromProperties
generateTestIdFromProperties,
} from 'ctrf'
import type { Test, Report } from 'ctrf'

Expand All @@ -18,7 +18,7 @@ const test: Test = {
status: 'passed',
duration: 150,
suite: ['auth', 'login'],
filePath: 'src/auth/login.test.ts'
filePath: 'src/auth/login.test.ts',
}

// Set a test ID (generates deterministic UUID based on properties)
Expand All @@ -40,7 +40,7 @@ console.log('Generated ID:', customId) // Always the same for these inputs
// Demonstrate deterministic behavior
const sameId = generateTestIdFromProperties(
'my test',
['suite1', 'suite2'],
['suite1', 'suite2'],
'my-test.ts'
)
console.log('Same ID?', customId === sameId) // true!
Expand All @@ -59,25 +59,25 @@ const report: Report = {
pending: 0,
other: 0,
start: Date.now(),
stop: Date.now() + 1000
stop: Date.now() + 1000,
},
tests: [
{
name: 'test 1',
status: 'passed',
duration: 100,
suite: ['unit'],
filePath: 'test1.ts'
filePath: 'test1.ts',
},
{
name: 'test 2',
name: 'test 2',
status: 'passed',
duration: 200,
suite: ['integration'],
filePath: 'test2.ts'
}
]
}
filePath: 'test2.ts',
},
],
},
}

// Set IDs for all tests
Expand Down
4 changes: 3 additions & 1 deletion src/methods/store-previous-results.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface PreviousResult {
passed: number
failed: number
skipped: number
pending: number
flaky: number
other: number
duration: number
Expand Down Expand Up @@ -77,10 +78,11 @@ export function storePreviousResults(
buildNumber: report.results.environment?.buildNumber,
buildUrl: report.results.environment?.buildUrl,
result,
tests: summary.skipped,
tests: summary.tests,
passed: summary.passed,
failed: summary.failed,
skipped: summary.skipped,
pending: summary.pending,
flaky: flakyCount,
other: summary.other,
duration,
Expand Down
72 changes: 45 additions & 27 deletions src/methods/test-id.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ describe('test-id', () => {
it('should add a deterministic UUID to a test without one', () => {
const test = { ...mockTest }
const result = setTestId(test)

expect(result.id).toBeDefined()
expect(typeof result.id).toBe('string')
expect(result.id).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i)

expect(result.id).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
)

const test2 = { ...mockTest }
const result2 = setTestId(test2)
expect(result.id).toBe(result2.id)
Expand All @@ -69,7 +71,7 @@ describe('test-id', () => {
it('should not overwrite existing ID', () => {
const test = { ...mockTest, id: 'existing-id' }
const result = setTestId(test)

expect(result.id).toBe('existing-id')
})
})
Expand All @@ -78,19 +80,21 @@ describe('test-id', () => {
it('should return existing ID', () => {
const test = { ...mockTest, id: 'existing-id' }
const result = getTestId(test)

expect(result).toBe('existing-id')
})

it('should generate and return deterministic UUID if none exists', () => {
const test = { ...mockTest }
const result = getTestId(test)

expect(result).toBeDefined()
expect(typeof result).toBe('string')
expect(result).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i)
expect(test.id).toBe(result)

expect(result).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
)
expect(test.id).toBe(result)

const test2 = { ...mockTest }
const result2 = getTestId(test2)
expect(result).toBe(result2)
Expand All @@ -99,9 +103,9 @@ describe('test-id', () => {

describe('setTestIdsForReport', () => {
it('should set IDs for all tests in a report', () => {
const report = JSON.parse(JSON.stringify(mockReport))
const report = JSON.parse(JSON.stringify(mockReport))
const result = setTestIdsForReport(report)

expect(result.results.tests).toHaveLength(2)
expect(result.results.tests[0].id).toBeDefined()
expect(result.results.tests[1].id).toBeDefined()
Expand All @@ -111,9 +115,9 @@ describe('test-id', () => {
it('should not overwrite existing IDs', () => {
const report = JSON.parse(JSON.stringify(mockReport))
report.results.tests[0].id = 'existing-id'

const result = setTestIdsForReport(report)

expect(result.results.tests[0].id).toBe('existing-id')
expect(result.results.tests[1].id).toBeDefined()
expect(result.results.tests[1].id).not.toBe('existing-id')
Expand All @@ -125,18 +129,18 @@ describe('test-id', () => {
const report = JSON.parse(JSON.stringify(mockReport))
report.results.tests[0].id = 'test-id-1'
report.results.tests[1].id = 'test-id-2'

const result = findTestById(report, 'test-id-1')

expect(result).toBeDefined()
expect(result?.name).toBe('test 1')
})

it('should return undefined for non-existent ID', () => {
const report = JSON.parse(JSON.stringify(mockReport))

const result = findTestById(report, 'non-existent-id')

expect(result).toBeUndefined()
})
})
Expand All @@ -148,11 +152,13 @@ describe('test-id', () => {
['suite1', 'suite2'],
'test.ts'
)

expect(result).toBeDefined()
expect(typeof result).toBe('string')
expect(result).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i)

expect(result).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
)

const result2 = generateTestIdFromProperties(
'test name',
['suite1', 'suite2'],
Expand All @@ -163,16 +169,26 @@ describe('test-id', () => {

it('should handle missing optional parameters', () => {
const result = generateTestIdFromProperties('test name')

expect(result).toBeDefined()
expect(typeof result).toBe('string')
expect(result).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i)
expect(result).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
)
})

it('should generate different UUIDs for different properties', () => {
const result1 = generateTestIdFromProperties('test1', ['suite1'], 'file1.ts')
const result2 = generateTestIdFromProperties('test2', ['suite2'], 'file2.ts')

const result1 = generateTestIdFromProperties(
'test1',
['suite1'],
'file1.ts'
)
const result2 = generateTestIdFromProperties(
'test2',
['suite2'],
'file2.ts'
)

expect(result1).not.toBe(result2)
})
})
Expand All @@ -181,11 +197,13 @@ describe('test-id', () => {
it('should be a valid UUID', () => {
expect(CTRF_NAMESPACE).toBeDefined()
expect(typeof CTRF_NAMESPACE).toBe('string')
expect(CTRF_NAMESPACE).toMatch(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
expect(CTRF_NAMESPACE).toMatch(
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
)
})

it('should be stable and not change', () => {
expect(CTRF_NAMESPACE).toBe('6ba7b810-9dad-11d1-80b4-00c04fd430c8')
})
})
})
})
35 changes: 21 additions & 14 deletions src/methods/test-id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Test, Report } from '../../types/ctrf.js'
* The CTRF namespace UUID used for generating deterministic test IDs.
* This namespace ensures that all CTRF test IDs are generated consistently
* across different implementations and tools.
*
*
* @public
*/
export const CTRF_NAMESPACE = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'
Expand All @@ -17,27 +17,34 @@ export const CTRF_NAMESPACE = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'
* @param filePath - Test file path
* @returns A deterministic UUID v5 string based on the properties
*/
function generateTestId(name: string, suite?: string[], filePath?: string): string {
function generateTestId(
name: string,
suite?: string[],
filePath?: string
): string {
const suiteString = suite ? suite.join('/') : ''
const identifier = `${name}|${suiteString}|${filePath || ''}`

const namespaceBytes = CTRF_NAMESPACE.replace(/-/g, '').match(/.{2}/g)!.map(byte => parseInt(byte, 16))


const namespaceBytes = CTRF_NAMESPACE.replace(/-/g, '')
.match(/.{2}/g)!
.map(byte => parseInt(byte, 16))

const input = Buffer.concat([
Buffer.from(namespaceBytes),
Buffer.from(identifier, 'utf8')
Buffer.from(identifier, 'utf8'),
])

const hash = createHash('sha1').update(input).digest('hex')

const uuid = [
hash.substring(0, 8),
hash.substring(8, 12),
'5' + hash.substring(13, 16),
((parseInt(hash.substring(16, 17), 16) & 0x3) | 0x8).toString(16) + hash.substring(17, 20),
hash.substring(20, 32)
((parseInt(hash.substring(16, 17), 16) & 0x3) | 0x8).toString(16) +
hash.substring(17, 20),
hash.substring(20, 32),
].join('-')

return uuid
}

Expand Down Expand Up @@ -93,9 +100,9 @@ export function findTestById(report: Report, testId: string): Test | undefined {
* @returns A deterministic UUID v5 string based on the properties
*/
export function generateTestIdFromProperties(
name: string,
suite?: string[],
name: string,
suite?: string[],
filePath?: string
): string {
return generateTestId(name, suite, filePath)
}
}
6 changes: 5 additions & 1 deletion update-readme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ function extractCategorizedSections(docsContent: string): string {
return `](docs/${url})`
})

if (['Enumerations', 'Interfaces', 'Type Aliases', 'Variables'].includes(section.name)) {
if (
['Enumerations', 'Interfaces', 'Type Aliases', 'Variables'].includes(
section.name
)
) {
if (!utilityTypesAdded) {
apiContent += '\n### Utility Types\n\n'
utilityTypesAdded = true
Expand Down