Skip to content

Commit

Permalink
chore(tests): added more test cases to improve code coverage
Browse files Browse the repository at this point in the history
- updated readme file with minor changes
- added pending changelog version for notes
- refactored tsconfig functions into a class for easier test case
stubbing
  • Loading branch information
toddbluhm committed Sep 1, 2019
1 parent 7598375 commit 329a370
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 63 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 1.0.2 - Pending

-- **Tests**: Added more test cases and improved overall code coverage

## 1.0.1

- **Change**: Updates to readme file and badges
Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
[![Travis](https://travis-ci.com/toddbluhm/ts-standard.svg?branch=master)](https://travis-ci.com/toddbluhm/ts-standard)
[![Coverage Status](https://coveralls.io/repos/github/toddbluhm/ts-standard/badge.svg?branch=master)](https://coveralls.io/github/toddbluhm/ts-standard?branch=master)
[![npm](https://img.shields.io/npm/v/ts-standard.svg?maxAge=86400)](https://www.npmjs.com/package/ts-standard)
[![npm](https://img.shields.io/npm/dm/ts-standard.svg?maxAge=86400)](https://www.npmjs.com/package/ts-standard)
[![npm](https://img.shields.io/npm/l/ts-standard.svg?maxAge=2592000)](https://www.npmjs.com/package/ts-standard)
Expand Down Expand Up @@ -26,8 +27,8 @@ npx ts-standard --fix
```

Note: A `tsconfig.json` or similar project file is required. See
**[TSConfig](https://github.com/toddbluhm/ts-standard#tsconfig-linting-with-type-information)**
below for more details
**[TSConfig](https://github.com/toddbluhm/ts-standard#-tsconfig-linting-with-type-information)**
section below for more details

## 📜 Help

Expand Down Expand Up @@ -109,7 +110,7 @@ You can also choose to just use [`eslint`](https://github.com/eslint/eslint) wit
this project. But `ts-standard` saves you from having to manually install all the extra dependencies
and may reduce configuration overhead.

## 🎊 Special Thanks
## 🎉 Special Thanks

Special thanks to [`standard`](https://github.com/standard/standard) for inspiration and some shared code and
to [`eslint-config-standard-with-typescript`](https://github.com/standard/eslint-config-standard-with-typescript) for
Expand Down
5 changes: 3 additions & 2 deletions src/options.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { join } from 'path'
import * as eslint from 'eslint'
import { getTSConfigFile } from './tsconfig'
import { TSConfig } from './tsconfig'

export interface Options {
cmd: string
Expand All @@ -13,6 +13,7 @@ export interface Options {
}

export async function getOptions (): Promise<Options> {
const tsConfig = new TSConfig()
return {
// cmd, homepage, bugs all pulled from package.json
cmd: 'ts-standard',
Expand All @@ -24,7 +25,7 @@ export async function getOptions (): Promise<Options> {
eslintConfig: {
configFile: join(__dirname, '../eslintrc.json'),
parserOptions: {
project: await getTSConfigFile()
project: await tsConfig.getConfigFilePath()
}
}
}
Expand Down
63 changes: 34 additions & 29 deletions src/tsconfig.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as path from 'path'
import { statSync } from 'fs'
import * as pkgConf from 'pkg-conf'
import pkgConf from 'pkg-conf'

interface TSStandardConfig {
project?: string
Expand All @@ -15,45 +15,50 @@ interface TSStandardConfig {
parser: string
}

const DEFAULT_TSCONFIG_LOCATIONS = [
export const DEFAULT_TSCONFIG_LOCATIONS = [
'tsconfig.eslint.json',
'tsconfig.json'
]

function getTSConfigFromDefaultLocations (): string | undefined {
const cwd = process.cwd()
for (const tsFile of DEFAULT_TSCONFIG_LOCATIONS) {
const absPath = path.join(cwd, tsFile)
if (isValidPath(absPath)) {
return absPath
export class TSConfig {
private readonly cwd: string;
constructor () {
this.cwd = process.cwd()
}

async getConfigFilePath (): Promise<string | undefined> {
const settingsPath = await this._getTSConfigPathFromSettings()
if (settingsPath !== undefined) {
return settingsPath
}
return this._getTSConfigFromDefaultLocations()
}
}

function isValidPath (pathToValidate: string): boolean {
try {
statSync(pathToValidate)
} catch (e) {
return false
async _getTSConfigPathFromSettings (): Promise<string | undefined> {
const res: TSStandardConfig = await pkgConf('ts-standard', { cwd: this.cwd }) as any
if (res.project !== undefined) {
const settingsPath = path.join(this.cwd, res.project)
if (this._isValidPath(settingsPath)) {
return settingsPath
}
}
}
return true
}

async function getTSConfigPathFromSettings (): Promise<string | undefined> {
const cwd = process.cwd()
const res: TSStandardConfig = await pkgConf('ts-standard', { cwd }) as any
if (res.project !== undefined) {
const settingsPath = path.join(cwd, res.project)
if (isValidPath(settingsPath)) {
return settingsPath
_getTSConfigFromDefaultLocations (): string | undefined {
for (const tsFile of DEFAULT_TSCONFIG_LOCATIONS) {
const absPath = path.join(this.cwd, tsFile)
if (this._isValidPath(absPath)) {
return absPath
}
}
}
}

export async function getTSConfigFile (): Promise<string | undefined> {
const settingsPath = await getTSConfigPathFromSettings()
if (settingsPath !== undefined) {
return settingsPath
_isValidPath (pathToValidate: string): boolean {
try {
statSync(pathToValidate)
} catch (e) {
return false
}
return true
}
return getTSConfigFromDefaultLocations()
}
6 changes: 6 additions & 0 deletions test/assert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export function assertNotUndefined<T> (value: T | undefined): T {
if (value === undefined) {
throw new TypeError('Expected value to !== undefined.')
}
return value
}
59 changes: 30 additions & 29 deletions test/options.spec.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,42 @@
import * as sinon from 'sinon'
import { assert } from 'chai'
import * as tsconfigLib from '../src/tsconfig'
import { assertNotUndefined } from './assert'
import { TSConfig } from '../src/tsconfig'
import * as optionsLib from '../src/options'

describe('CLI', (): void => {
let getTSConfigFileStub: sinon.SinonStub<any, any>
describe('options', () => {
describe('getOptions', (): void => {
let getTSConfigFileStub: sinon.SinonStub<any, any>

before((): void => {
getTSConfigFileStub = sinon.stub(tsconfigLib, 'getTSConfigFile')
})
before((): void => {
getTSConfigFileStub = sinon.stub(TSConfig.prototype, 'getConfigFilePath')
})

after((): void => {
sinon.restore()
})
after((): void => {
sinon.restore()
})

afterEach((): void => {
sinon.resetHistory()
sinon.resetBehavior()
})
afterEach((): void => {
sinon.resetHistory()
sinon.resetBehavior()
})

it('should return the correct options', async (): Promise<void> => {
const projectPath = 'some/project.path'
getTSConfigFileStub.returns(projectPath)
const options = await optionsLib.getOptions()
assert.equal(options.cmd, 'ts-standard')
assert.equal(options.version, require('../package.json').version)
assert.equal(options.homepage, require('../package.json').homepage)
assert.equal(options.bugs, require('../package.json').bugs.url)
assert.equal(options.tagline, 'Standard for Typescript!')
assert.ok(options.eslint)
assert.ok(options.eslintConfig.configFile)
if (options.eslintConfig.configFile !== undefined) {
it('should return the correct options', async (): Promise<void> => {
const projectPath = 'some/project.path'
getTSConfigFileStub.returns(projectPath)
const options = await optionsLib.getOptions()
assert.equal(options.cmd, 'ts-standard')
assert.equal(options.version, require('../package.json').version)
assert.equal(options.homepage, require('../package.json').homepage)
assert.equal(options.bugs, require('../package.json').bugs.url)
assert.equal(options.tagline, 'Standard for Typescript!')
assert.ok(options.eslint)
assert.ok(options.eslintConfig.configFile)
options.eslintConfig.configFile = assertNotUndefined(options.eslintConfig.configFile)
assert.match(options.eslintConfig.configFile, /eslintrc\.json/gi)
}
assert.ok(options.eslintConfig.parserOptions)
if (options.eslintConfig.parserOptions !== undefined) {
assert.ok(options.eslintConfig.parserOptions)
options.eslintConfig.parserOptions = assertNotUndefined(options.eslintConfig.parserOptions)
assert.equal(options.eslintConfig.parserOptions.project, projectPath)
}
})
})
})
145 changes: 145 additions & 0 deletions test/tsconfig.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import * as sinon from 'sinon'
import { assert } from 'chai'
import { join } from 'path'
import * as pkgConfLib from 'pkg-conf'
import { assertNotUndefined } from './assert'
import { TSConfig } from '../src/tsconfig'

describe('tsconfig', () => {
let tsConfig: TSConfig
before(() => {
tsConfig = new TSConfig()
})

describe('_isValidPath', () => {
it('should return true for a valid path', () => {
const validPath = join(__dirname, '/options.spec.ts')
const isValid = tsConfig._isValidPath(validPath)
assert.isTrue(isValid)
})

it('should return false for an invalid path', () => {
const invalidPath = join(__dirname, '/non-existent-file.ts')
const isValid = tsConfig._isValidPath(invalidPath)
assert.isFalse(isValid)
})
})

describe('_getTSConfigFromDefaultLocations', (): void => {
let _isValidPathStub: sinon.SinonStub<any, any>

before((): void => {
_isValidPathStub = sinon.stub(tsConfig, '_isValidPath')
})

after((): void => {
sinon.restore()
})

afterEach((): void => {
sinon.resetHistory()
sinon.resetBehavior()
})

it('should return a valid path if one is found found', (): void => {
_isValidPathStub.returns(true)
let validPath = tsConfig._getTSConfigFromDefaultLocations()
validPath = assertNotUndefined(validPath)
assert.match(validPath, /tsconfig\.eslint\.json/gi)
})

it('should return the first path found if a valid path is found', (): void => {
_isValidPathStub.returns(false)
_isValidPathStub.onSecondCall().returns(true)
let validPath = tsConfig._getTSConfigFromDefaultLocations()
validPath = assertNotUndefined(validPath)
assert.match(validPath, /tsconfig\.json/gi)
})

it('should return undefined if no valid path found', (): void => {
_isValidPathStub.returns(false)
const validPath = tsConfig._getTSConfigFromDefaultLocations()
assert.isUndefined(validPath)
})
})

describe('_getTSConfigPathFromSettings', (): void => {
let _pkgConfStub: sinon.SinonStub<any, any>

before((): void => {
_pkgConfStub = sinon.stub(pkgConfLib, 'default')
})

after((): void => {
sinon.restore()
})

afterEach((): void => {
sinon.resetHistory()
sinon.resetBehavior()
})

it('should return a valid path if one is found found', async (): Promise<void> => {
_pkgConfStub.returns({ project: './tsconfig.eslint.json' })
let validPath = await tsConfig._getTSConfigPathFromSettings()
validPath = assertNotUndefined(validPath)
assert.match(validPath, /tsconfig.eslint.json/gi)
})

it('should return undefined if no valid path found', async (): Promise<void> => {
_pkgConfStub.returns({ project: './non-existent-file.ts' })
const validPath = await tsConfig._getTSConfigPathFromSettings()
assert.isUndefined(validPath)
})

it('should return undefined if project settings provided', async (): Promise<void> => {
_pkgConfStub.returns({})
const validPath = await tsConfig._getTSConfigPathFromSettings()
assert.isUndefined(validPath)
})
})

describe('getConfigFilePath', (): void => {
let _getTSConfigPathFromSettingsStub: sinon.SinonStub<any, any>
let _getTSConfigFromDefaultLocationsStub: sinon.SinonStub<any, any>
const packageJsonPath = '/path/from/package.json'
const defaultLocationPath = '/path/from/default-location.json'

before((): void => {
_getTSConfigPathFromSettingsStub = sinon.stub(tsConfig, '_getTSConfigPathFromSettings')
_getTSConfigFromDefaultLocationsStub = sinon.stub(tsConfig, '_getTSConfigFromDefaultLocations')
})

after((): void => {
sinon.restore()
})

afterEach((): void => {
sinon.resetHistory()
sinon.resetBehavior()
})

it('should return a valid path from package.json first', async (): Promise<void> => {
_getTSConfigPathFromSettingsStub.returns(packageJsonPath)
_getTSConfigFromDefaultLocationsStub.returns(defaultLocationPath)
let validPath = await tsConfig.getConfigFilePath()
validPath = assertNotUndefined(validPath)
assert.equal(validPath, packageJsonPath)
})

it('should return a valid path from default location if no package.json setting found', async (): Promise<void> => {
_getTSConfigPathFromSettingsStub.returns(undefined)
_getTSConfigFromDefaultLocationsStub.returns(defaultLocationPath)
let validPath = await tsConfig.getConfigFilePath()
validPath = assertNotUndefined(validPath)
assert.equal(validPath, defaultLocationPath)
})

it('should return undefined if no valid paths found', async (): Promise<void> => {
_getTSConfigPathFromSettingsStub.returns(undefined)
_getTSConfigFromDefaultLocationsStub.returns(undefined)
const validPath = await tsConfig.getConfigFilePath()
assert.isUndefined(validPath)
})
})
})

0 comments on commit 329a370

Please sign in to comment.