Skip to content
This repository has been archived by the owner on Jul 4, 2023. It is now read-only.

Commit

Permalink
test(test): improve coverage for test mode logic
Browse files Browse the repository at this point in the history
re #51
  • Loading branch information
tamj0rd2 committed May 7, 2020
1 parent a8a836e commit 6065be5
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 14 deletions.
4 changes: 2 additions & 2 deletions src/commands/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ const groupBy = <T>(items: ReadonlyArray<T>, getKey: (item: T) => string): Map<s
return map
}, new Map<string, T[]>())

const colorInspect = (obj: any, depth?: number): string => inspect(obj, false, depth, true)
const colorInspect = (obj: unknown, depth?: number): string => inspect(obj, false, depth, true)

export const gatherValidationErrors = (problems: ReadonlyArray<Problem>): string =>
export const gatherValidationErrors = (problems: ReadonlyArray<Public<Problem>>): string =>
Array.from(groupBy(problems, (x) => x.path))
.map(([dataPath, groupedProblems]) =>
Array.from(groupBy(groupedProblems, (x) => x.problemType))
Expand Down
75 changes: 75 additions & 0 deletions src/commands/test/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { testConfigs } from './test'
import { randomString, mockFn, mockObj, mocked } from '~test-helpers'
import { FetchResource, TypeValidator, doItAll } from '~validation'
import { Config } from '~config'
import { TestFn } from '~validation/validators'
import logger from '~logger'
import stripAnsi from 'strip-ansi'
import { ProblemType } from '~problem'

jest.unmock('./test')
jest.unmock('~messages')
jest.unmock('~commands/shared')

describe('test configs', () => {
const baseUrl = randomString('base-url')
const mockFetchResource = mockFn<FetchResource>()
const mockTypeValidator = mockObj<TypeValidator>({})
const mockTest = mockFn<TestFn>()
const mockDoItAll = mocked(doItAll)
const mockLogger = mockObj(logger)

beforeEach(() => {
jest.resetAllMocks()
mockDoItAll.mockReturnValue(mockTest)
})

it('calls doItAll with the correct args', async () => {
const configs: Config[] = [{ name: 'yo!', request: { endpoint: randomString('endpoint') } } as Config]
mockTest.mockResolvedValue([])

await testConfigs(baseUrl, mockFetchResource, configs, mockTypeValidator)

expect(mockDoItAll).toBeCalledWith(mockTypeValidator, mockFetchResource)
})

it('logs when a test passes', async () => {
const configs: Config[] = [{ name: 'yo!', request: { endpoint: randomString('endpoint') } } as Config]
mockTest.mockResolvedValue([])

await testConfigs(baseUrl, mockFetchResource, configs, mockTypeValidator)

const expectedMessage = `PASSED: yo! - ${baseUrl}${configs[0].request.endpoint}\n`
expect(mockLogger.info).toBeCalled()
expect(stripAnsi((mockLogger.info.mock.calls[0][0] as unknown) as string)).toEqual(expectedMessage)
})

it('logs when a test fail', async () => {
const configs: Config[] = [{ name: 'yo!', request: { endpoint: randomString('endpoint') } } as Config]
mockTest.mockResolvedValue([{ path: 'some.path', problemType: ProblemType.Request, message: 'message' }])

await expect(testConfigs(baseUrl, mockFetchResource, configs, mockTypeValidator)).rejects.toThrowError(
'Not all tests passed',
)

const expectedMessage = `FAILED: yo!\nURL: ${baseUrl}${configs[0].request.endpoint}\n`
const expectedError1 = `Request some.path message\n`
expect(mockLogger.error).toBeCalled()
expect(stripAnsi((mockLogger.error.mock.calls[0][0] as unknown) as string)).toEqual(
expectedMessage + expectedError1,
)
})

it('logs when a test throws an error', async () => {
const configs: Config[] = [{ name: 'yo!', request: { endpoint: randomString('endpoint') } } as Config]
mockTest.mockRejectedValue(new Error('woah dude'))

await expect(testConfigs(baseUrl, mockFetchResource, configs, mockTypeValidator)).rejects.toThrowError(
'Not all tests passed',
)

const expectedMessage = `ERROR: yo!\nURL: ${baseUrl}${configs[0].request.endpoint}\nwoah dude\n`
expect(mockLogger.error).toBeCalled()
expect(stripAnsi((mockLogger.error.mock.calls[0][0] as unknown) as string)).toEqual(expectedMessage)
})
})
15 changes: 7 additions & 8 deletions src/commands/test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,18 @@ import { testPassed, testFailed, testError } from '~messages'
// TODO: why is this returning a number? yeah, what the fuck?
// TODO: reuse this at config type validaiton type. nononononoooooo
const logTestResults = (baseUrl: string) => (displayName: string, endpoint: string) => (
problems: Problem[],
problems: Public<Problem>[],
): 0 | 1 => {
const displayEndpoint = blue(`${baseUrl}${endpoint}`)
if (!problems.length) {
logger.info(testPassed(displayName, displayEndpoint) + '\n')
logger.info(testPassed(displayName, displayEndpoint))
return 0
} else {
logger.error(testFailed(displayName, displayEndpoint, problems) + '\n')
logger.error(testFailed(displayName, displayEndpoint, problems))
return 1
}
}

const logTestError = (displayName: string) => (err: Error): void => {
logger.error(testError(displayName, err.message) + `\n`)
}

export const testConfigs = async (
baseURL: string,
fetchResource: FetchResource,
Expand All @@ -37,7 +33,10 @@ export const testConfigs = async (
const testTasks = configs.map((testConfig) => {
return test(testConfig)
.then(resultsLogger(testConfig.name, testConfig.request.endpoint))
.catch(logTestError(testConfig.name))
.catch((err) => {
logger.error(testError(testConfig.name, baseURL + testConfig.request.endpoint, err.message))
return 1
})
})

const results = Promise.all(testTasks)
Expand Down
7 changes: 4 additions & 3 deletions src/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ export const validationFailed = ({ name, problems }: ProblemResult): string =>
export const testPassed = (name: string, endpoint: string): string =>
`${green('PASSED')}: ${name} - ${endpoint}\n`

export const testFailed = (name: string, endpoint: string, problems: Problem[]): string =>
`${red.bold('FAILED')}: ${red.bold(name)}\nURL: ${endpoint}\n${gatherValidationErrors(problems)}`
export const testFailed = (name: string, endpoint: string, problems: Public<Problem>[]): string =>
`${red.bold('FAILED')}: ${red.bold(name)}\nURL: ${endpoint}\n${gatherValidationErrors(problems)}\n`

export const testError = (name: string, message: string): string => `${red('FAILED')}: ${name} - ${message}\n`
export const testError = (name: string, endpoint: string, message: string): string =>
`${red.bold('ERROR')}: ${red.bold(name)}\nURL: ${endpoint}\n${message}\n`
2 changes: 1 addition & 1 deletion src/validation/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { shouldBe, problemFetching } from '~messages'

export type LoaderResponse = { status: number; data?: Data }
export type FetchResource = (config: Config) => Promise<LoaderResponse>
export type TestFn = (config: Config) => Promise<Problem[]>
export type TestFn = (config: Config) => Promise<Public<Problem>[]>

const isDeeplyEqual = (expected: unknown, actual: unknown): boolean => {
if (typeof expected === 'object') {
Expand Down

0 comments on commit 6065be5

Please sign in to comment.