Skip to content

Commit

Permalink
feat(init): document test runner homepage url in stryker.conf.json (#…
Browse files Browse the repository at this point in the history
…3817)

Add the test runner homepage URL in a comment inside the stryker.conf.json file, generated when running `stryker init`.
  • Loading branch information
Giovds committed Oct 29, 2022
1 parent 7d42139 commit 92c0852
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 25 deletions.
8 changes: 4 additions & 4 deletions packages/core/src/initializer/npm-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ interface NpmSearchResult {
results: Array<{ package: PackageInfo }>;
}

interface NpmPackage {
export interface NpmPackage {
name: string;
homepage?: string;
initStrykerConfig?: Record<string, unknown>;
}

Expand Down Expand Up @@ -50,18 +51,17 @@ export class NpmClient {
return this.search('/v2/search?q=keywords:@stryker-mutator/reporter-plugin').then(mapSearchResultToPromptOption);
}

public getAdditionalConfig(pkgInfo: PackageInfo): Promise<Record<string, unknown>> {
public getAdditionalConfig(pkgInfo: PackageInfo): Promise<NpmPackage> {
const path = `/${pkgInfo.name}@${pkgInfo.version}/package.json`;
return this.packageClient
.get<NpmPackage>(path)
.then(handleResult(path))
.then((pkg) => pkg.initStrykerConfig ?? {})
.catch((err) => {
this.log.warn(
`Could not fetch additional initialization config for dependency ${pkgInfo.name}. You might need to configure it manually`,
err
);
return {};
return { name: pkgInfo.name };
});
}

Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/initializer/stryker-config-writer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,16 @@ export class StrykerConfigWriter {
selectedPackageManager: PromptOption,
requiredPlugins: string[],
additionalPiecesOfConfig: Array<Partial<StrykerOptions>>,
homepageOfSelectedTestRunner: string,
exportAsJson: boolean
): Promise<string> {
const configObject: Partial<StrykerOptions> & { _comment: string } = {
_comment:
"This config was generated using 'stryker init'. Please take a look at: https://stryker-mutator.io/docs/stryker-js/configuration/ for more information",
"This config was generated using 'stryker init'. Please take a look at: https://stryker-mutator.io/docs/stryker-js/configuration/ for more information.",
packageManager: selectedPackageManager.name as 'npm' | 'pnpm' | 'yarn',
reporters: selectedReporters.map((rep) => rep.name),
testRunner: selectedTestRunner.name,
testRunner_comment: `More information about the ${selectedTestRunner.name} plugin can be found here: ${homepageOfSelectedTestRunner}`,
coverageAnalysis: CommandTestRunner.is(selectedTestRunner.name) ? 'off' : 'perTest',
};

Expand Down
13 changes: 9 additions & 4 deletions packages/core/src/initializer/stryker-initializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { commonTokens, tokens } from '@stryker-mutator/api/plugin';
import { Logger } from '@stryker-mutator/api/logging';
import { notEmpty } from '@stryker-mutator/util';

import { NpmClient } from './npm-client.js';
import { NpmClient, NpmPackage } from './npm-client.js';
import { PackageInfo } from './package-info.js';
import { Preset } from './presets/preset.js';
import { PromptOption } from './prompt-option.js';
Expand Down Expand Up @@ -104,13 +104,18 @@ export class StrykerInitializer {
const selectedPackageManager = await this.selectPackageManager();
const isJsonSelected = await this.selectJsonConfigType();
const npmDependencies = this.getSelectedNpmDependencies([selectedTestRunner].concat(selectedReporters));
const packageInfo = await this.fetchAdditionalConfig(npmDependencies);
const pkgInfoOfSelectedTestRunner = packageInfo.find((pkg) => pkg.name == selectedTestRunner.pkg?.name);
const additionalConfig = packageInfo.map((dep) => dep.initStrykerConfig ?? {}).filter(notEmpty);

const configFileName = await configWriter.write(
selectedTestRunner,
buildCommand,
selectedReporters,
selectedPackageManager,
npmDependencies.map((pkg) => pkg.name),
await this.fetchAdditionalConfig(npmDependencies),
additionalConfig,
pkgInfoOfSelectedTestRunner?.homepage ?? 'URL not found',
isJsonSelected
);
this.installNpmDependencies(
Expand Down Expand Up @@ -213,7 +218,7 @@ export class StrykerInitializer {
}
}

private async fetchAdditionalConfig(dependencies: PackageInfo[]): Promise<Array<Record<string, unknown>>> {
return (await Promise.all(dependencies.map((dep) => this.client.getAdditionalConfig(dep)))).filter(notEmpty);
private async fetchAdditionalConfig(dependencies: PackageInfo[]): Promise<NpmPackage[]> {
return await Promise.all(dependencies.map((dep) => this.client.getAdditionalConfig(dep)));
}
}
58 changes: 42 additions & 16 deletions packages/core/test/unit/initializer/stryker-initializer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import typedRestClient, { type RestClient, type IRestResponse } from 'typed-rest

import { fileUtils } from '../../../src/utils/file-utils.js';
import { initializerTokens } from '../../../src/initializer/index.js';
import { NpmClient } from '../../../src/initializer/npm-client.js';
import { NpmClient, NpmPackage } from '../../../src/initializer/npm-client.js';
import { PackageInfo } from '../../../src/initializer/package-info.js';
import { Preset } from '../../../src/initializer/presets/preset.js';
import { PresetConfiguration } from '../../../src/initializer/presets/preset-configuration.js';
Expand Down Expand Up @@ -251,10 +251,11 @@ describe(StrykerInitializer.name, () => {
const expectedOutput = `// @ts-check
/** @type {import('@stryker-mutator/api/core').PartialStrykerOptions} */
const config = {
"_comment": "This config was generated using 'stryker init'. Please take a look at: https://stryker-mutator.io/docs/stryker-js/configuration/ for more information",
"_comment": "This config was generated using 'stryker init'. Please take a look at: https://stryker-mutator.io/docs/stryker-js/configuration/ for more information.",
"packageManager": "pnpm",
"reporters": [],
"testRunner": "awesome",
"testRunner_comment": "More information about the awesome plugin can be found here: URL not found",
"coverageAnalysis": "perTest",
"plugins": [ "@stryker-mutator/awesome-runner" ]
};
Expand Down Expand Up @@ -310,7 +311,7 @@ describe(StrykerInitializer.name, () => {
expect(fs.promises.writeFile).calledWith(
'stryker.conf.json',
sinon.match(
'"_comment": "This config was generated using \'stryker init\'. Please take a look at: https://stryker-mutator.io/docs/stryker-js/configuration/ for more information"'
'"_comment": "This config was generated using \'stryker init\'. Please take a look at: https://stryker-mutator.io/docs/stryker-js/configuration/ for more information."'
)
);
});
Expand Down Expand Up @@ -400,6 +401,35 @@ describe(StrykerInitializer.name, () => {
expect(out).calledWith('An error occurred during installation, please try it yourself: "npm i --save-dev stryker-ghost-runner"');
expect(fs.promises.writeFile).called;
});

it('should write not found if test runner homepage url as comment when not found', async () => {
inquirerPrompt.resolves({
packageManager: 'npm',
reporters: [],
testRunner: 'hyper',
configType: 'JSON',
});
await sut.initialize();
expect(fs.promises.writeFile).calledWith(
'stryker.conf.json',
sinon.match('"testRunner_comment": "More information about the hyper plugin can be found here: URL not found"')
);
});

it('should write URL if test runner homepage url as comment', async () => {
stubPackageClient({ 'stryker-hyper-runner': { name: 'hyper' } }, 'https://url-to-hyper.com');
inquirerPrompt.resolves({
packageManager: 'npm',
reporters: [],
testRunner: 'hyper',
configType: 'JSON',
});
await sut.initialize();
expect(fs.promises.writeFile).calledWith(
'stryker.conf.json',
sinon.match('"testRunner_comment": "More information about the hyper plugin can be found here: https://url-to-hyper.com"')
);
});
});

describe('initialize() when no internet', () => {
Expand Down Expand Up @@ -509,21 +539,17 @@ describe(StrykerInitializer.name, () => {
statusCode: 200,
} as unknown as IRestResponse<PackageInfo[]>);
};
const stubPackageClient = (packageConfigPerPackage: Record<string, Record<string, unknown> | null>) => {
Object.keys(packageConfigPerPackage).forEach((packageName) => {
const pkgConfig: PackageInfo & { initStrykerConfig?: Record<string, unknown> } = {
keywords: [],
name: packageName,
version: '1.1.1',
};
const cfg = packageConfigPerPackage[packageName];
if (cfg) {
pkgConfig.initStrykerConfig = cfg;
}
const stubPackageClient = (initStrykerConfigPerPackage: Record<string, Record<string, unknown> | null>, homepage?: string | null) => {
Object.keys(initStrykerConfigPerPackage).forEach((packageName) => {
const cfg = initStrykerConfigPerPackage[packageName];
restClientPackage.get.withArgs(`/${packageName}@1.1.1/package.json`).resolves({
result: pkgConfig,
result: {
name: packageName,
homepage: homepage,
initStrykerConfig: cfg ?? null,
},
statusCode: 200,
} as unknown as IRestResponse<PackageInfo[]>);
} as unknown as IRestResponse<NpmPackage[]>);
});
};

Expand Down

0 comments on commit 92c0852

Please sign in to comment.