Skip to content

Commit

Permalink
test: add main modules tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lekterable committed Apr 25, 2020
1 parent ec50739 commit 8990fd6
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

## Fixes

- replace %message% as last to avoid bugs [ec507396](https://github.com/lekterable/perfekt/commit/ec5073967f83dbcfc98b0ba17a1aa9659a042385)
- stop adding empty line at the end of the file on --root [faee4801](https://github.com/lekterable/perfekt/commit/faee480108aab450a606ac8132f89c9f42ec8ab3)
- stop adding Latest when not applicable [c64fa467](https://github.com/lekterable/perfekt/commit/c64fa4673612f90b349d125912f07d5db4140bcd)

Expand Down
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dev": "webpack --progress --colors --watch",
"prepare": "npm run build",
"test": "jest",
"test:coverage": "jest --collectCoverage",
"test:watch": "jest --watch"
},
"repository": {
Expand Down Expand Up @@ -52,6 +53,7 @@
"eslint-plugin-standard": "^4.0.1",
"husky": "^4.2.5",
"jest": "^25.4.0",
"jest-mock-process": "^1.3.2",
"lint-staged": "^10.1.6",
"prettier": "^2.0.4",
"webpack": "^4.42.1",
Expand Down
3 changes: 2 additions & 1 deletion src/changelog.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ export const changelog = async (version, options, config) => {
const commits = await getCommits(latestTag)
const grouped = groupCommits(commits)
const changelog = generateChangelog(version, grouped, config)
if (!options || !options.write) return process.stdout.write(changelog)

if (!options.write) return process.stdout.write(changelog)

const released = latestTag && (await generateReleased(latestTag, config))

Expand Down
178 changes: 178 additions & 0 deletions src/changelog.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import { writeFileSync } from 'fs'
import { mockProcessStdout } from 'jest-mock-process'
import { defaultChangelogOptions as defaultOptions, defaultConfig } from './'
import { changelog } from './changelog'
import {
generateChangelog,
generateReleased,
getCommits,
getLatestTag,
groupCommits
} from './utils'

jest.mock('./utils', () => ({
generateChangelog: jest.fn(),
generateReleased: jest.fn(),
getCommits: jest.fn(),
getLatestTag: jest.fn(),
groupCommits: jest.fn()
}))
jest.mock('fs', () => ({
writeFileSync: jest.fn(),
readFile: jest.fn()
}))

describe('changelog', () => {
beforeEach(() => jest.resetAllMocks())

it('should print to output', async () => {
const stdoutMock = mockProcessStdout()
const mockedTag = '2.2.3'
const mockedCommits = [
'f2191200bf7b6e5eec3d61fcef9eb756e0129cfb chore(release): 0.1.0',
'aa805ce71ee103965ce3db46d4f6ed2658efd08d feat: add option to write to local CHANGELOG file',
'4e02179cae1234d7083036024080a3f25fcb52c2 feat: add execute release feature',
'bffc2f9e8da1c7ac133689bc9cd14494f3be08e3 refactor: extract line generating logic to function and promisify exec',
'2ea04355c1e81c5088eeabc6e242fb1ade978524 chore(changelog): update CHANGELOG'
]
const mockedGrouped = [
{
feat: [
'aa805ce71ee103965ce3db46d4f6ed2658efd08d feat: add option to write to local CHANGELOG file',
'4e02179cae1234d7083036024080a3f25fcb52c2 feat: add execute release feature'
],
misc: [
'bffc2f9e8da1c7ac133689bc9cd14494f3be08e3 refactor: extract line generating logic to function and promisify exec'
],
release:
'f2191200bf7b6e5eec3d61fcef9eb756e0129cfb chore(release): 0.1.0'
}
]
const mockedChangelog =
'# Latest\n\n## Features\n\n- add %HASH% placeholder to line format a3c93b2f\n- introduce changelog customization using config file e66d6176\n- use higher level of headers for changelog eea23d95\n\n## Fixes\n\n- replace %message% as last to avoid bugs ec507396\n- stop adding empty line at the end of the file on --root faee4801\n- stop adding Latest when not applicable c64fa467\n\n## Misc\n\n- include commit links in the changelog 8f622021\n\n'
const mockedReleased = ''

getLatestTag.mockImplementation(() => mockedTag)
getCommits.mockImplementation(() => mockedCommits)
groupCommits.mockImplementation(() => mockedGrouped)
generateChangelog.mockImplementation(() => mockedChangelog)
generateReleased.mockImplementation(() => mockedReleased)

await changelog(null, defaultOptions, defaultConfig)

expect(getLatestTag).toBeCalledTimes(1)
expect(getLatestTag).toBeCalledWith()
expect(getCommits).toBeCalledTimes(1)
expect(getCommits).toBeCalledWith(mockedTag)
expect(groupCommits).toBeCalledTimes(1)
expect(groupCommits).toBeCalledWith(mockedCommits)
expect(generateChangelog).toBeCalledTimes(1)
expect(generateChangelog).toBeCalledWith(null, mockedGrouped, defaultConfig)
expect(generateReleased).not.toBeCalled()
expect(stdoutMock).toBeCalledTimes(1)
expect(stdoutMock).toBeCalledWith(mockedChangelog)
expect(writeFileSync).not.toBeCalled()
})

it('should generate changelog with version', async () => {
const stdoutMock = mockProcessStdout()
const mockedTag = '2.2.3'
const mockedChangelog =
'# 2.2.3\n\n## Features\n\n- add %HASH% placeholder to line format a3c93b2f\n- introduce changelog customization using config file e66d6176\n- use higher level of headers for changelog eea23d95\n\n## Fixes\n\n- replace %message% as last to avoid bugs ec507396\n- stop adding empty line at the end of the file on --root faee4801\n- stop adding Latest when not applicable c64fa467\n\n## Misc\n\n- include commit links in the changelog 8f622021\n\n'
const mockedGrouped = [
{
feat: [
'aa805ce71ee103965ce3db46d4f6ed2658efd08d feat: add option to write to local CHANGELOG file',
'4e02179cae1234d7083036024080a3f25fcb52c2 feat: add execute release feature'
],
misc: [
'bffc2f9e8da1c7ac133689bc9cd14494f3be08e3 refactor: extract line generating logic to function and promisify exec'
],
release:
'f2191200bf7b6e5eec3d61fcef9eb756e0129cfb chore(release): 0.1.0'
}
]
const mockedReleased = ''

getLatestTag.mockImplementation(() => mockedTag)
groupCommits.mockImplementation(() => mockedGrouped)
generateChangelog.mockImplementation(() => mockedChangelog)
generateReleased.mockImplementation(() => mockedReleased)

await changelog('2.2.3', defaultOptions, defaultConfig)

expect(generateChangelog).toBeCalledTimes(1)
expect(generateChangelog).toBeCalledWith(
mockedTag,
mockedGrouped,
defaultConfig
)
expect(stdoutMock).toBeCalledTimes(1)
expect(stdoutMock).toBeCalledWith(mockedChangelog)
expect(writeFileSync).not.toBeCalled()
})

it('should generate changelog with --root option', async () => {
const stdoutMock = mockProcessStdout()
const options = { ...defaultOptions, root: true }
const mockedTag = '2.2.3'
const mockedChangelog =
'# Latest\n\n## Features\n\n- add %HASH% placeholder to line format a3c93b2f\n- introduce changelog customization using config file e66d6176\n- use higher level of headers for changelog eea23d95\n\n## Fixes\n\n- replace %message% as last to avoid bugs ec507396\n- stop adding empty line at the end of the file on --root faee4801\n- stop adding Latest when not applicable c64fa467\n\n## Misc\n\n- include commit links in the changelog 8f622021\n\n'
const mockedReleased = ''

getLatestTag.mockImplementation(() => mockedTag)
generateChangelog.mockImplementation(() => mockedChangelog)
generateReleased.mockImplementation(() => mockedReleased)

await changelog(null, options, defaultConfig)

expect(stdoutMock).toBeCalledTimes(1)
expect(stdoutMock).toBeCalledWith(mockedChangelog)
expect(writeFileSync).not.toBeCalled()
})

it('should write to file with --write option', async () => {
const options = { ...defaultOptions, write: true }
const mockedTag = '2.2.3'
const mockedChangelog =
'# Latest\n\n## Features\n\n- add %HASH% placeholder to line format a3c93b2f\n- introduce changelog customization using config file e66d6176\n- use higher level of headers for changelog eea23d95\n\n## Fixes\n\n- replace %message% as last to avoid bugs ec507396\n- stop adding empty line at the end of the file on --root faee4801\n- stop adding Latest when not applicable c64fa467\n\n## Misc\n\n- include commit links in the changelog 8f622021\n\n'
const mockedReleased = ''
const mockedFilename = 'CHANGELOG.md'
const mockedOutput =
'# Latest\n\n## Features\n\n- add %HASH% placeholder to line format a3c93b2f\n- introduce changelog customization using config file e66d6176\n- use higher level of headers for changelog eea23d95\n\n## Fixes\n\n- replace %message% as last to avoid bugs ec507396\n- stop adding empty line at the end of the file on --root faee4801\n- stop adding Latest when not applicable c64fa467\n\n## Misc\n\n- include commit links in the changelog 8f622021\n'

getLatestTag.mockImplementation(() => mockedTag)
generateChangelog.mockImplementation(() => mockedChangelog)
generateReleased.mockImplementation(() => mockedReleased)

await changelog(null, options, defaultConfig)

expect(writeFileSync).toBeCalledTimes(1)
expect(writeFileSync).toBeCalledWith(mockedFilename, mockedOutput)
})

it('should write to file with --write option and released', async () => {
const options = { ...defaultOptions, write: true }
const stdoutMock = mockProcessStdout()
const mockedTag = '2.2.3'
const mockedChangelog =
'# 2.2.3\n\n## Features\n\n- add %HASH% placeholder to line format a3c93b2f\n- introduce changelog customization using config file e66d6176\n- use higher level of headers for changelog eea23d95\n\n## Fixes\n\n- replace %message% as last to avoid bugs ec507396\n- stop adding empty line at the end of the file on --root faee4801\n- stop adding Latest when not applicable c64fa467\n\n## Misc\n\n- include commit links in the changelog 8f622021\n\n'
const mockedReleased = '# 2.2.2\n- feat: add feature 2da21c56'
const mockedFilename = 'CHANGELOG.md'

getLatestTag.mockImplementation(() => mockedTag)
generateChangelog.mockImplementation(() => mockedChangelog)
generateReleased.mockImplementation(() => mockedReleased)

await changelog('2.2.3', options, defaultConfig)

expect(generateReleased).toBeCalledTimes(1)
expect(generateReleased).toBeCalledWith(mockedTag, defaultConfig)
expect(stdoutMock).not.toBeCalled()
expect(writeFileSync).toBeCalledTimes(1)
expect(writeFileSync).toBeCalledWith(
mockedFilename,
mockedChangelog + mockedReleased
)
})
})
5 changes: 5 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,8 @@ export const defaultConfig = {
releaseFormat: '# %version%',
lineFormat: '- %message% %hash%'
}

export const defaultChangelogOptions = {
write: false,
root: false
}
2 changes: 1 addition & 1 deletion src/initialize.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { writeFileSync } from 'fs'
import inquirer from 'inquirer'

const questions = [
export const questions = [
{
type: 'list',
name: 'configFormat',
Expand Down
32 changes: 32 additions & 0 deletions src/initialize.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { writeFileSync } from 'fs'
import { prompt } from 'inquirer'
import { initialize, questions } from './initialize'

jest.mock('inquirer', () => ({
prompt: jest.fn()
}))
jest.mock('fs', () => ({
writeFileSync: jest.fn()
}))

describe.only('initialize', () => {
beforeEach(() => jest.resetAllMocks())

describe('initialize', () => {
it('should write to file with --write option and released', async () => {
const mockedConfigFormat = '.prettierrc'
prompt.mockImplementation(() =>
Promise.resolve({
configFormat: mockedConfigFormat
})
)

await initialize()

expect(prompt).toBeCalledTimes(1)
expect(prompt).toBeCalledWith(questions)
expect(writeFileSync).toBeCalledTimes(1)
expect(writeFileSync).toBeCalledWith(mockedConfigFormat, '')
})
})
})
6 changes: 3 additions & 3 deletions src/release.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { changelog } from './changelog'
import { commitRelease, updateVersion } from './utils'

export const release = async version => {
if (!version) throw new Error('Relese requires a version')

const newVersion = semver.valid(semver.coerce(version))

if (!newVersion) {
return console.error(`Version '${version}' doesnt look right`)
}
if (!newVersion) throw new Error(`Version '${version}' doesnt look right`)

try {
await updateVersion(newVersion)
Expand Down
56 changes: 56 additions & 0 deletions src/release.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { changelog } from './changelog'
import { release } from './release'
import { commitRelease, updateVersion } from './utils'

jest.mock('./changelog', () => ({
changelog: jest.fn()
}))
jest.mock('./utils', () => ({
commitRelease: jest.fn(),
updateVersion: jest.fn()
}))
jest.mock('console', () => ({
error: jest.fn()
}))

describe('release', () => {
beforeEach(() => jest.resetAllMocks())

it('should throw if no version passed', () => {
expect(release()).rejects.toThrow('Relese requires a versio')
})

it('should throw if incorrect version passed', () => {
const mockedVersion = 'version'

expect(release(mockedVersion)).rejects.toThrow(
"Version 'version' doesnt look right"
)
})

it('should log error if it occurs', async () => {
const mockedVersion = '2.2.2'
const consoleSpy = jest.spyOn(console, 'error').mockImplementation()

updateVersion.mockImplementation(() => Promise.reject(new Error()))

await release(mockedVersion)

expect(consoleSpy).toBeCalledTimes(1)
expect(consoleSpy).toBeCalledWith(expect.any(Error))

consoleSpy.mockRestore()
})

it('should execute release', async () => {
const mockedVersion = '2.2.2'

await release(mockedVersion)

expect(changelog).toBeCalledTimes(1)
expect(commitRelease).toBeCalledTimes(1)
expect(commitRelease).toBeCalledWith(mockedVersion)
expect(updateVersion).toBeCalledTimes(1)
expect(updateVersion).toBeCalledWith(mockedVersion)
})
})

0 comments on commit 8990fd6

Please sign in to comment.