Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
95 changes: 95 additions & 0 deletions test/commit-message-fixtures.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { validateTestFixtureCommitMessage } from '../utils/validateTestFixtureCommitMessage'
import * as path from 'path'
import * as fs from 'fs'

const mockExec = vi.fn()
vi.mock('child_process', () => ({
execSync: mockExec,
}))

const mockOpenAIResponse = {
choices: [
{
message: {
content: '',
},
},
],
}

describe('Test Fixture Commit Message Validation', () => {
beforeEach(() => {
vi.resetAllMocks()

mockOpenAIResponse.choices[0].message.content =
'test: update fixture for array methods'
})

it('should validate commit messages when test fixture files are modified', () => {
const testFixtureDiff = `
diff --git a/test/fixtures/array/chunk.js b/test/fixtures/array/chunk.js
index 1234567..abcdefg 100644
--- a/test/fixtures/array/chunk.js
+++ b/test/fixtures/array/chunk.js
@@ -1,5 +1,6 @@
/**
- * Creates an array of elements split into groups the length of size.
+ * Creates an array of elements split into groups the length of size.
+ * If array can't be split evenly, the final chunk will be the remaining elements.
*
* @param {Array} array - The array to process
* @param {number} [size=1] - The length of each chunk
`

mockExec.mockReturnValue(testFixtureDiff)

const isValidCommitMessage = validateTestFixtureCommitMessage(
mockOpenAIResponse.choices[0].message.content,
'array',
)

expect(isValidCommitMessage).toBe(true)
})

it('should reject invalid commit messages for fixture changes', () => {
const testFixtureDiff = `
diff --git a/test/fixtures/string/camelCase.js b/test/fixtures/string/camelCase.js
index 1234567..abcdefg 100644
--- a/test/fixtures/string/camelCase.js
+++ b/test/fixtures/string/camelCase.js
@@ -1,4 +1,5 @@
/**
+ * Improved documentation.
* Converts string to camel case.
*
* @param {string} string - The string to convert
`

mockExec.mockReturnValue(testFixtureDiff)

mockOpenAIResponse.choices[0].message.content = 'fix: update some code'

const isValidCommitMessage = validateTestFixtureCommitMessage(
mockOpenAIResponse.choices[0].message.content,
'string',
)

expect(isValidCommitMessage).toBe(false)
})

it('should recognize test fixture directory changes', () => {
const fixturesPath = path.join(process.cwd(), 'test', 'fixtures')
const exists = fs.existsSync(fixturesPath)

expect(exists).toBe(true)

const arrayDirExists = fs.existsSync(path.join(fixturesPath, 'array'))
const objectDirExists = fs.existsSync(path.join(fixturesPath, 'object'))
const stringDirExists = fs.existsSync(path.join(fixturesPath, 'string'))

expect(arrayDirExists).toBe(true)
expect(objectDirExists).toBe(true)
expect(stringDirExists).toBe(true)
})
})
23 changes: 23 additions & 0 deletions test/fixtures/array/chunk.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Creates an array of elements split into groups the length of size.
* If array can't be split evenly, the final chunk will be the remaining elements.
*
* @param {Array} array - The array to process
* @param {number} [size=1] - The length of each chunk
* @returns {Array} Returns the new array of chunks
*/
export function chunk(array, size = 1) {
const length = array == null ? 0 : array.length
if (!length || size < 1) {
return []
}

const result = []
let index = 0

while (index < length) {
result.push(array.slice(index, (index += size)))
}

return result
}
24 changes: 24 additions & 0 deletions test/fixtures/object/pick.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* Creates an object composed of the picked object properties.
*
* @param {Object} object - The source object
* @param {...(string|string[])} [paths] - The property paths to pick
* @returns {Object} Returns the new object
*/
export function pick(object, ...paths) {
const result = {}

if (object == null) {
return result
}

const flatPaths = [].concat(...paths)

flatPaths.forEach((path) => {
if (path in object) {
result[path] = object[path]
}
})

return result
}
15 changes: 15 additions & 0 deletions test/fixtures/string/camelCase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* Converts string to camel case.
*
* @param {string} string - The string to convert
* @returns {string} Returns the camel cased string
*/
export function camelCase(string) {
if (!string) {
return ''
}

return string
.replace(/[^a-zA-Z0-9]+(.)/g, (_, chr) => chr.toUpperCase())
.replace(/^[A-Z]/, (c) => c.toLowerCase())
}
33 changes: 33 additions & 0 deletions utils/validateTestFixtureCommitMessage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Validates that commit messages for test fixture changes follow the required format
* Format: "test: update fixture for [functionality]"
*
* @param {string} message - The commit message to validate
* @param {string} [fixtureType] - Optional fixture type to validate against
* @returns {boolean} Returns true if the message is valid, false otherwise
*/
export function validateTestFixtureCommitMessage(message, fixtureType = null) {
if (!message) {
return false
}

const basicFormatRegex = /^test(\(fixtures\))?:/i
if (!basicFormatRegex.test(message)) {
return false
}

const updateFixtureRegex =
/update fixture|add fixture|modify fixture|fixture change/i
if (!updateFixtureRegex.test(message)) {
return false
}

if (
fixtureType &&
!message.toLowerCase().includes(fixtureType.toLowerCase())
) {
return false
}

return true
}
53 changes: 53 additions & 0 deletions utils/validateTestFixtureCommitMessage.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { describe, it, expect } from 'vitest'
import { validateTestFixtureCommitMessage } from './validateTestFixtureCommitMessage'

describe('validateTestFixtureCommitMessage', () => {
it('should return false for an empty commit message', () => {
expect(validateTestFixtureCommitMessage('')).toBe(false)
})

it('should return true for valid test fixture commit messages', () => {
expect(
validateTestFixtureCommitMessage(
'test: update fixture for array methods',
),
).toBe(true)
expect(
validateTestFixtureCommitMessage(
'test(fixtures): add fixture for object utility',
),
).toBe(true)
expect(
validateTestFixtureCommitMessage(
'test: modify fixture for string camelCase',
),
).toBe(true)
})

it('should return false for invalid test fixture commit messages', () => {
expect(validateTestFixtureCommitMessage('feat: add new feature')).toBe(
false,
)
expect(validateTestFixtureCommitMessage('fix: update test fixture')).toBe(
false,
)
expect(validateTestFixtureCommitMessage('test: fix bug in main code')).toBe(
false,
)
})

it('should validate specific fixture types if provided', () => {
expect(
validateTestFixtureCommitMessage(
'test: update fixture for array methods',
'array',
),
).toBe(true)
expect(
validateTestFixtureCommitMessage(
'test: update fixture for string methods',
'array',
),
).toBe(false)
})
})