Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build: add noImplicitAny and noImplicitReturns, fix compilation #1286

Merged
merged 33 commits into from Mar 7, 2020
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b88ae4d
add noImplicitReturns to tsconfig.json
davidjgoss Feb 3, 2020
fda9549
add noImplicitAny to tsconfig.json
davidjgoss Feb 3, 2020
8812c5e
some progress
davidjgoss Feb 3, 2020
13c7828
more progress
davidjgoss Feb 3, 2020
428296b
add typings for verror package
davidjgoss Feb 3, 2020
825064d
more progress
davidjgoss Feb 3, 2020
da5c23c
more progress
davidjgoss Feb 3, 2020
45ba630
whoops
davidjgoss Feb 3, 2020
8d7d71c
more progress
davidjgoss Feb 3, 2020
e332b75
this interface was a bit unnecessary
davidjgoss Feb 3, 2020
0495e31
use I convention consistently on types
davidjgoss Feb 3, 2020
a9fe91f
install types for progress library
davidjgoss Feb 3, 2020
bf61138
more progress
davidjgoss Feb 3, 2020
44d0d4f
more progress
davidjgoss Feb 3, 2020
3d20539
nearly there
davidjgoss Feb 3, 2020
0e99986
add typings for resolve
davidjgoss Feb 3, 2020
c017ecc
almost
davidjgoss Feb 3, 2020
861a873
fix more test code
davidjgoss Feb 4, 2020
59a2975
fix type from any to string
davidjgoss Feb 6, 2020
3a537b5
fix up compilation for feature test support code
davidjgoss Feb 6, 2020
16903e1
declare types in way that works for both typescript and ts-node
davidjgoss Feb 7, 2020
61be36b
fix all of the unit tests!
davidjgoss Feb 7, 2020
085fb83
use `ensureSymlinkSync` as it's in the documented API
davidjgoss Feb 8, 2020
c4a87bd
use EventEmitter instead of custom interface
davidjgoss Mar 5, 2020
0f47556
fix up cucumber-messages imports
davidjgoss Mar 6, 2020
08dce29
remove empty lines
davidjgoss Mar 6, 2020
f7e3975
remove unnecessary Partial
davidjgoss Mar 7, 2020
5798f7a
move type to appropriate file
davidjgoss Mar 7, 2020
7add934
create interfaces for helper function request objects
davidjgoss Mar 7, 2020
7f5ef3a
avoid awkward casting by adding PassThrough to formatter stream inter…
davidjgoss Mar 7, 2020
1946980
drop redundant key from objct literal
davidjgoss Mar 7, 2020
ad6c22d
merge from master
davidjgoss Mar 7, 2020
5a6c4b8
fix last few issues after merging master
davidjgoss Mar 7, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
31 changes: 20 additions & 11 deletions features/step_definitions/file_steps.ts
Expand Up @@ -7,37 +7,46 @@ import path from 'path'
import Mustache from 'mustache'
import { World } from '../support/world'

Given(/^a file named "(.*)" with:$/, function(
Given(/^a file named "(.*)" with:$/, async function(
this: World,
filePath,
fileContent
filePath: string,
fileContent: any
davidjgoss marked this conversation as resolved.
Show resolved Hide resolved
) {
const absoluteFilePath = path.join(this.tmpDir, filePath)
if (filePath === '@rerun.txt') {
fileContent = fileContent.replace(/\//g, path.sep)
}
return fsExtra.outputFile(absoluteFilePath, fileContent)
await fsExtra.outputFile(absoluteFilePath, fileContent)
})

Given(/^an empty file named "(.*)"$/, function(this: World, filePath) {
Given(/^an empty file named "(.*)"$/, async function(
this: World,
filePath: string
) {
const absoluteFilePath = path.join(this.tmpDir, filePath)
return fsExtra.outputFile(absoluteFilePath, '')
await fsExtra.outputFile(absoluteFilePath, '')
})

Given(/^a directory named "(.*)"$/, function(this: World, filePath) {
Given(/^a directory named "(.*)"$/, async function(
this: World,
filePath: string
) {
const absoluteFilePath = path.join(this.tmpDir, filePath)
return fsExtra.mkdirp(absoluteFilePath)
await fsExtra.mkdirp(absoluteFilePath)
})

Given(/^"([^"]*)" is an absolute path$/, function(this: World, filePath) {
Given(/^"([^"]*)" is an absolute path$/, function(
this: World,
filePath: string
) {
filePath = Mustache.render(filePath, this)
expect(path.isAbsolute(filePath)).to.eql(true)
})

Then(/^the file "([^"]*)" has the text:$/, async function(
this: World,
filePath,
text
filePath: string,
text: string
) {
filePath = Mustache.render(filePath, this)
const absoluteFilePath = path.resolve(this.tmpDir, filePath)
Expand Down
4 changes: 3 additions & 1 deletion features/step_definitions/fixture_steps.ts
Expand Up @@ -6,13 +6,15 @@ import {
} from '../support/formatter_output_helpers'
import fs from 'mz/fs'
import path from 'path'
import { messages } from 'cucumber-messages'
import Envelope = messages.Envelope
davidjgoss marked this conversation as resolved.
Show resolved Hide resolved

Then(
'the {string} formatter output matches the fixture {string}',
async function(formatter: string, filePath: string) {
let actual: any
if (formatter === 'message') {
actual = this.lastRun.envelopes.map(e => e.toJSON())
actual = this.lastRun.envelopes.map((e: Envelope) => e.toJSON())
actual = normalizeMessageOutput(actual, this.tmpDir)
} else {
const actualPath = path.join(this.tmpDir, `${formatter}.out`)
Expand Down
6 changes: 3 additions & 3 deletions features/step_definitions/usage_json_steps.ts
@@ -1,11 +1,11 @@
import _ from 'lodash'
import { Then } from '../../'
import { Then, DataTable } from '../../'
import { expect } from 'chai'
import path from 'path'

Then('it outputs the usage data:', function(table) {
Then('it outputs the usage data:', function(table: DataTable) {
const usageData = JSON.parse(this.lastRun.output)
table.hashes().forEach(row => {
table.hashes().forEach((row: any) => {
const rowUsage = _.find(
usageData,
datum =>
Expand Down
2 changes: 2 additions & 0 deletions features/support/hooks.ts
Expand Up @@ -37,6 +37,7 @@ Before(function(

const tmpDirNodeModulesPath = path.join(this.tmpDir, 'node_modules')
const tmpDirCucumberPath = path.join(tmpDirNodeModulesPath, 'cucumber')
// @ts-ignore
davidjgoss marked this conversation as resolved.
Show resolved Hide resolved
fsExtra.createSymlinkSync(projectPath, tmpDirCucumberPath)
this.localExecutablePath = path.join(projectPath, 'bin', 'cucumber-js')
})
Expand All @@ -55,6 +56,7 @@ Before('@global-install', function(this: World) {
'node_modules',
moduleName
)
// @ts-ignore
fsExtra.createSymlinkSync(
projectNodeModulePath,
globalInstallNodeModulePath
Expand Down
4 changes: 2 additions & 2 deletions features/support/world.ts
Expand Up @@ -4,7 +4,7 @@ import { expect } from 'chai'
import toString from 'stream-to-string'
import { PassThrough } from 'stream'
import colors from 'colors/safe'
import fs from 'fs'
import fs, { WriteStream } from 'fs'
import path from 'path'
import VError from 'verror'
import _ from 'lodash'
Expand Down Expand Up @@ -59,7 +59,7 @@ export class World {
})
})
} else {
const stdout = new PassThrough()
const stdout = (new PassThrough() as unknown) as WriteStream
const cli = new Cli({
argv: args,
cwd,
Expand Down
10 changes: 10 additions & 0 deletions package.json
Expand Up @@ -185,10 +185,20 @@
},
"devDependencies": {
"@types/bluebird": "^3.5.29",
"@types/chai": "^4.2.8",
"@types/dirty-chai": "^2.0.2",
"@types/fs-extra": "^8.0.1",
"@types/glob": "^7.1.1",
"@types/lodash": "^4.14.149",
"@types/mocha": "^7.0.1",
"@types/mustache": "^4.0.0",
"@types/mz": "^2.7.0",
"@types/node": "^13.1.1",
"@types/progress": "^2.0.3",
"@types/resolve": "^1.14.0",
"@types/sinon-chai": "^3.2.3",
"@types/tmp": "^0.1.0",
"@types/verror": "^1.10.3",
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"ansi-html": "^0.0.7",
Expand Down
6 changes: 3 additions & 3 deletions src/cli/configuration_builder.ts
Expand Up @@ -64,8 +64,8 @@ export default class ConfigurationBuilder {
const listI18nKeywordsFor = this.options.i18nKeywords
const listI18nLanguages = this.options.i18nLanguages
const unexpandedFeaturePaths = await this.getUnexpandedFeaturePaths()
let featurePaths = []
let supportCodePaths = []
let featurePaths: string[] = []
let supportCodePaths: string[] = []
if (listI18nKeywordsFor === '' && !listI18nLanguages) {
featurePaths = await this.expandFeaturePaths(unexpandedFeaturePaths)
let unexpandedSupportCodePaths = this.options.require
Expand Down Expand Up @@ -156,7 +156,7 @@ export default class ConfigurationBuilder {
}

getFormats(): IConfigurationFormat[] {
const mapping = { '': 'progress' }
const mapping: { [key: string]: string } = { '': 'progress' }
this.options.format.forEach(format => {
const [type, outputTo] = OptionSplitter.split(format)
mapping[outputTo] = type
Expand Down
8 changes: 5 additions & 3 deletions src/cli/configuration_builder_spec.ts
Expand Up @@ -6,14 +6,16 @@ import ConfigurationBuilder, {
} from './configuration_builder'
import fsExtra from 'fs-extra'
import path from 'path'
import tmp from 'tmp'
import tmp, { DirOptions } from 'tmp'
import { promisify } from 'util'
import { SnippetInterface } from '../formatter/step_definition_snippet_builder/snippet_syntax'

describe('Configuration', () => {
beforeEach(async function() {
this.tmpDir = await promisify(tmp.dir)({ unsafeCleanup: true })
await promisify(fsExtra.mkdirp)(path.join(this.tmpDir, 'features'))
this.tmpDir = await promisify<DirOptions, string>(tmp.dir)({
unsafeCleanup: true,
})
await fsExtra.mkdirp(path.join(this.tmpDir, 'features'))
this.argv = ['path/to/node', 'path/to/cucumber.js']
this.configurationOptions = {
argv: this.argv,
Expand Down
2 changes: 1 addition & 1 deletion src/cli/helpers.ts
Expand Up @@ -47,7 +47,7 @@ export async function parseGherkinMessageStream({
pickleFilter,
}: IParseGherkinMessageStreamRequest): Promise<string[]> {
return new Promise<string[]>((resolve, reject) => {
const result = []
const result: string[] = []
gherkinMessageStream.on('data', envelope => {
eventBroadcaster.emit('envelope', envelope)
if (doesHaveValue(envelope.pickle)) {
Expand Down
2 changes: 1 addition & 1 deletion src/cli/i18n.ts
Expand Up @@ -14,7 +14,7 @@ const keywords = [
'then',
'and',
'but',
]
] as const
davidjgoss marked this conversation as resolved.
Show resolved Hide resolved

function getAsTable(header: string[], rows: string[][]): string {
const table = new Table({
Expand Down
22 changes: 18 additions & 4 deletions src/cli/index.ts
Expand Up @@ -22,7 +22,7 @@ import { doesNotHaveValue } from '../value_checker'
import Gherkin from 'gherkin'
import { ISupportCodeLibrary } from '../support_code_library_builder/types'
import { IParsedArgvFormatOptions } from './argv_parser'

import { WriteStream } from 'fs'
const { incrementing, uuid } = IdGenerator

export interface ICliRunResult {
Expand All @@ -38,12 +38,26 @@ interface IInitializeFormattersRequest {
supportCodeLibrary: ISupportCodeLibrary
}

interface IGetSupportCodeLibraryRequest {
newId: IdGenerator.NewId
supportCodeRequiredModules: string[]
supportCodePaths: string[]
}

export default class Cli {
private readonly argv: string[]
private readonly cwd: string
private readonly stdout: IFormatterStream

constructor({ argv, cwd, stdout }) {
constructor({
argv,
cwd,
stdout,
}: {
argv: string[]
cwd: string
stdout: IFormatterStream
}) {
this.argv = argv
this.cwd = cwd
this.stdout = stdout
Expand All @@ -61,7 +75,7 @@ export default class Cli {
formats,
supportCodeLibrary,
}: IInitializeFormattersRequest): Promise<() => Promise<void>> {
const streamsToClose = []
const streamsToClose: WriteStream[] = []
await bluebird.map(formats, async ({ type, outputTo }) => {
let stream: IFormatterStream = this.stdout
if (outputTo !== '') {
Expand Down Expand Up @@ -101,7 +115,7 @@ export default class Cli {
newId,
supportCodeRequiredModules,
supportCodePaths,
}): ISupportCodeLibrary {
}: IGetSupportCodeLibraryRequest): ISupportCodeLibrary {
supportCodeRequiredModules.map(module => require(module))
supportCodeLibraryBuilder.reset(this.cwd, newId)
supportCodePaths.forEach(codePath => require(codePath))
Expand Down
4 changes: 3 additions & 1 deletion src/cli/install_validator.ts
Expand Up @@ -9,7 +9,9 @@ export async function validateInstall(cwd: string): Promise<void> {
return // cucumber testing itself
}
const currentCucumberPath = require.resolve(projectPath)
let localCucumberPath = await promisify(resolve)('cucumber', {
let localCucumberPath: string = await promisify<string, resolve.Opts, string>(
resolve
)('cucumber', {
basedir: cwd,
})
localCucumberPath = await fs.realpath(localCucumberPath)
Expand Down
1 change: 1 addition & 0 deletions src/formatter/get_color_fns.ts
Expand Up @@ -23,6 +23,7 @@ export default function getColorFns(enabled: boolean): IColorFns {
[Status.PENDING]: colors.yellow.bind(colors),
[Status.SKIPPED]: colors.cyan.bind(colors),
[Status.UNDEFINED]: colors.yellow.bind(colors),
[Status.UNKNOWN]: colors.yellow.bind(colors),
charlierudolph marked this conversation as resolved.
Show resolved Hide resolved
}[status]
},
location: colors.gray.bind(colors),
Expand Down
6 changes: 5 additions & 1 deletion src/formatter/helpers/event_data_collector.ts
Expand Up @@ -20,13 +20,17 @@ export interface ITestCaseAttempt {
testCase: messages.ITestCase
}

export interface IEventBroadcaster {
on(name: string, handler: Function): void
}
davidjgoss marked this conversation as resolved.
Show resolved Hide resolved

export default class EventDataCollector {
private gherkinDocumentMap: Dictionary<messages.IGherkinDocument> = {}
private pickleMap: Dictionary<messages.IPickle> = {}
private testCaseMap: Dictionary<messages.ITestCase> = {}
private testCaseAttemptDataMap: Dictionary<ITestCaseAttemptData> = {}

constructor(eventBroadcaster) {
constructor(eventBroadcaster: IEventBroadcaster) {
eventBroadcaster.on('envelope', this.parseEnvelope.bind(this))
}

Expand Down
15 changes: 14 additions & 1 deletion src/formatter/helpers/issue_helpers.ts
Expand Up @@ -2,6 +2,10 @@ import indentString from 'indent-string'
import Status from '../../status'
import { formatTestCaseAttempt } from './test_case_attempt_formatter'
import { messages } from 'cucumber-messages'
import { IColorFns } from '../get_color_fns'
import StepDefinitionSnippetBuilder from '../step_definition_snippet_builder'
import { ISupportCodeLibrary } from '../../support_code_library_builder/types'
import { ITestCaseAttempt } from './event_data_collector'

export function isFailure(result: messages.ITestResult): boolean {
return (
Expand All @@ -22,14 +26,23 @@ export function isIssue(result: messages.ITestResult): boolean {
return isFailure(result) || isWarning(result)
}

export interface IFormatIssueRequest {
colorFns: IColorFns
cwd: string
number: number
snippetBuilder: StepDefinitionSnippetBuilder
testCaseAttempt: ITestCaseAttempt
supportCodeLibrary: ISupportCodeLibrary
}

export function formatIssue({
colorFns,
cwd,
number,
snippetBuilder,
testCaseAttempt,
supportCodeLibrary,
}): string {
}: IFormatIssueRequest): string {
const prefix = `${number}) `
const formattedTestCaseAttempt = formatTestCaseAttempt({
colorFns,
Expand Down
8 changes: 4 additions & 4 deletions src/formatter/helpers/keyword_type.ts
@@ -1,6 +1,7 @@
import _ from 'lodash'
import Gherkin from 'gherkin'
import { doesHaveValue } from '../../value_checker'
import Dialect from 'gherkin/dist/src/Dialect'
charlierudolph marked this conversation as resolved.
Show resolved Hide resolved

export enum KeywordType {
Precondition = 'precondition',
Expand All @@ -19,10 +20,9 @@ export function getStepKeywordType({
language,
previousKeywordType,
}: IGetStepKeywordTypeOptions): KeywordType {
const dialect = Gherkin.dialects()[language]
const type = _.find(['given', 'when', 'then', 'and', 'but'], key =>
_.includes(dialect[key], keyword)
)
const dialect: Dialect = Gherkin.dialects()[language]
const stepKeywords = ['given', 'when', 'then', 'and', 'but'] as const
const type = _.find(stepKeywords, key => _.includes(dialect[key], keyword))
switch (type) {
case 'when':
return KeywordType.Event
Expand Down
2 changes: 1 addition & 1 deletion src/formatter/helpers/summary_helpers.ts
Expand Up @@ -77,7 +77,7 @@ function getCountSummary({
.value()
let text = `${total} ${type}${total === 1 ? '' : 's'}`
if (total > 0) {
const details = []
const details: string[] = []
STATUS_REPORT_ORDER.forEach(status => {
if (counts[status] > 0) {
details.push(
Expand Down
15 changes: 13 additions & 2 deletions src/formatter/helpers/test_case_attempt_formatter.ts
Expand Up @@ -9,8 +9,11 @@ import {
import { formatStepArgument } from './step_argument_formatter'
import { IColorFns } from '../get_color_fns'
import { valueOrDefault, doesHaveValue } from '../../value_checker'
import { ITestCaseAttempt } from './event_data_collector'
import StepDefinitionSnippetBuilder from '../step_definition_snippet_builder'
import { ISupportCodeLibrary } from '../../support_code_library_builder/types'

const CHARACTERS = {
const CHARACTERS: { [status: number]: string } = {
[Status.AMBIGUOUS]: figures.cross,
[Status.FAILED]: figures.cross,
[Status.PASSED]: figures.tick,
Expand Down Expand Up @@ -66,13 +69,21 @@ function formatStep({ colorFns, testStep }: IFormatStepRequest): string {
return text
}

export interface IFormatTestCaseAttemptRequest {
colorFns: IColorFns
cwd: string
testCaseAttempt: ITestCaseAttempt
snippetBuilder: StepDefinitionSnippetBuilder
supportCodeLibrary: ISupportCodeLibrary
}

export function formatTestCaseAttempt({
colorFns,
cwd,
snippetBuilder,
supportCodeLibrary,
testCaseAttempt,
}): string {
}: IFormatTestCaseAttemptRequest): string {
const parsed = parseTestCaseAttempt({
cwd,
snippetBuilder,
Expand Down