Skip to content

Commit

Permalink
feature: add option --unused-steps to bddgen export, see #113
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalets committed Mar 26, 2024
1 parent 408e583 commit e2f3907
Show file tree
Hide file tree
Showing 12 changed files with 84 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## dev
* feature: add option `--unused-steps` to `bddgen export`, [#113](https://github.com/vitalets/playwright-bdd/issues/113)
* feature: show stdout / stderr in Cucumber reports, [#116](https://github.com/vitalets/playwright-bdd/issues/116)
* feature: call step from step, [#110](https://github.com/vitalets/playwright-bdd/issues/110)

Expand Down
10 changes: 5 additions & 5 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,17 @@ $ npx bddgen export
```
Example output:
```
List of all steps found by config: playwright.config.ts
Using config: playwright.config.ts
List of all steps (4):
* Given I am on todo page
* When I add todo {string}
* When I remove todo {string}
* Then visible todos count is {int}
```
To run it with custom Playwright config use `--config` option:
```
npx bddgen export --config path/to/playwright.config.ts
```
#### Options
* `--config` - path to Playwright config
* `--unused-step` - output only unused steps

## `bddgen env`
Displays info about current environment:
Expand Down
33 changes: 27 additions & 6 deletions src/cli/commands/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,24 @@ import { TestFilesGenerator } from '../../gen';

const logger = new Logger({ verbose: true });

type Opts = ConfigOption & {
unusedSteps?: boolean;
};

export const exportCommand = new Command('export')
.description('Prints all step definitions')
.description('Prints step definitions')
.addOption(configOption)
.action(async (opts: ConfigOption) => {
.option('--unused-steps', 'Output only unused steps')
.action(async (opts: Opts) => {
const { resolvedConfigFile } = await loadPlaywrightConfig(opts.config);
logger.log(
`List of all steps found by config: ${path.relative(process.cwd(), resolvedConfigFile)}\n`,
);
logger.log(`Using config: ${path.relative(process.cwd(), resolvedConfigFile)}`);
const configs = Object.values(getEnvConfigs());
assertConfigsCount(configs);
await showStepsForConfigs(configs);
if (opts.unusedSteps) {
await showUnusedStepsForConfigs(configs);
} else {
await showStepsForConfigs(configs);
}
});

async function showStepsForConfigs(configs: BDDConfig[]) {
Expand All @@ -35,6 +42,20 @@ async function showStepsForConfigs(configs: BDDConfig[]) {

await Promise.all(tasks);

logger.log(`List of all steps (${steps.size}):`);
steps.forEach((stepText) => logger.log(stepText));
}

async function showUnusedStepsForConfigs(configs: BDDConfig[]) {
const steps = new Set<string>();
const tasks = configs.map(async (config) => {
const stepDefinitions = await new TestFilesGenerator(config).extractUnusedSteps();
stepDefinitions.forEach((s) => steps.add(`* ${getStepText(s)}`));
});

await Promise.all(tasks);

logger.log(`List of unused steps (${steps.size}):`);
steps.forEach((stepText) => logger.log(stepText));
}

Expand Down
2 changes: 1 addition & 1 deletion src/cucumber/resolveFeaturePaths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { resolvePackageRoot } from '../utils';
export async function resovleFeaturePaths(
runConfiguration: IRunConfiguration,
environment: IRunEnvironment = {},
) {
): Promise<{ featurePaths: string[]; unexpandedFeaturePaths: string[] }> {
const { cwd, stderr, debug } = mergeEnvironment(environment);
const logger: ILogger = new ConsoleLogger(stderr, debug);
const cucumberRoot = resolvePackageRoot('@cucumber/cucumber');
Expand Down
22 changes: 18 additions & 4 deletions src/gen/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ export class TestFilesGenerator {
return this.supportCodeLibrary.stepDefinitions;
}

// todo: combine with extractSteps
async extractUnusedSteps() {
await this.loadCucumberConfig();
await Promise.all([this.loadFeatures(), this.loadSteps()]);
this.buildFiles();
return this.supportCodeLibrary.stepDefinitions.filter((stepDefinition) => {
const isUsed = this.files.some((file) => file.usedStepDefinitions.has(stepDefinition));
return !isUsed;
});
}

private async loadCucumberConfig() {
const environment = { cwd: getPlaywrightConfigDir() };
const { runConfiguration } = await loadCucumberConfig(
Expand All @@ -69,11 +80,14 @@ export class TestFilesGenerator {

private async loadFeatures() {
const cwd = getPlaywrightConfigDir();
const { paths, defaultDialect } = this.runConfiguration.sources;
this.logger.log(`Loading features from: ${paths.join(', ')}`);
const { defaultDialect } = this.runConfiguration.sources;
const { featurePaths } = await resovleFeaturePaths(this.runConfiguration, { cwd });
await this.featuresLoader.load(featurePaths, { relativeTo: cwd, defaultDialect });
this.handleParseErrors();
this.logger.log(`Loading features from paths (${featurePaths.length}):`);
featurePaths.forEach((featurePath) => this.logger.log(featurePath));
if (featurePaths.length) {
await this.featuresLoader.load(featurePaths, { relativeTo: cwd, defaultDialect });
this.handleParseErrors();
}
this.logger.log(`Loaded features: ${this.featuresLoader.getDocumentsCount()}`);
}

Expand Down
3 changes: 3 additions & 0 deletions src/gen/testFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export class TestFile {
public hasCustomTest = false;
public undefinedSteps: UndefinedStep[] = [];
public featureUri: string;
public usedStepDefinitions = new Set<StepDefinition>();

constructor(private options: TestFileOptions) {
this.formatter = new Formatter(options.config);
Expand Down Expand Up @@ -332,6 +333,8 @@ export class TestFile {
return this.getMissingStep(enKeyword, keywordType, pickleStep);
}

this.usedStepDefinitions.add(stepDefinition);

// for cucumber-style stepConfig is undefined
const stepConfig = getStepConfig(stepDefinition);
if (stepConfig?.hasCustomTest) this.hasCustomTest = true;
Expand Down
6 changes: 6 additions & 0 deletions test/cli-command-export/features/sample.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Feature: cli-command-export
Scenario: Simple scenario
Given I am on todo page
Then visible todos count is 2


5 changes: 3 additions & 2 deletions test/cli-command-export/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ export default defineConfig({
name: 'project1',
testDir: defineBddConfig({
outputDir: '.features-gen/one',
require: ['steps.ts'],
paths: ['features'],
require: ['steps/steps.ts'],
}),
},
{
name: 'project2',
testDir: defineBddConfig({
outputDir: '.features-gen/two',
require: ['steps.ts', 'steps2.ts'],
require: ['steps/steps.ts', 'steps/steps2.ts'],
}),
},
],
Expand Down
File renamed without changes.
File renamed without changes.
22 changes: 18 additions & 4 deletions test/cli-command-export/test.mjs
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
import { expect } from '@playwright/test';
import { test, getTestName, execPlaywrightTest, BDDGEN_CMD } from '../helpers.mjs';
import { test, TestDir, execPlaywrightTest, BDDGEN_CMD } from '../helpers.mjs';

const testDir = new TestDir(import.meta);

test(`${testDir.name} (all steps)`, () => {
const stdout = execPlaywrightTest(testDir.name, `${BDDGEN_CMD} export`);
expect(stdout).toContain('Using config: playwright.config.ts');
expect(stdout).toContain('List of all steps (5):');

test(getTestName(import.meta), (t) => {
const stdout = execPlaywrightTest(t.name, `${BDDGEN_CMD} export`);
expect(stdout).toContain('List of all steps found by config: playwright.config.ts');
expect(stdout).toContain('* Given I am on todo page');
expect(stdout).toContain('* When I add todo {string}');
expect(stdout).toContain('* Then visible todos count is (\\d+)');
expect(stdout).toContain('* When some step');
expect(stdout).toContain('* Given I am on another todo page');
});

test(`${testDir.name} (unused steps)`, () => {
const stdout = execPlaywrightTest(testDir.name, `${BDDGEN_CMD} export --unused-steps`);
expect(stdout).toContain('Using config: playwright.config.ts');
expect(stdout).toContain(`List of unused steps (3):`);

expect(stdout).toContain('* When I add todo {string}');
expect(stdout).toContain('* When some step');
expect(stdout).toContain('* Given I am on another todo page');
});
3 changes: 2 additions & 1 deletion test/cli-option-verbose/test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ const testDir = new TestDir(import.meta);

test(testDir.name, () => {
const stdout = execPlaywrightTest(testDir.name, `${BDDGEN_CMD} --verbose`);
expect(stdout).toContain('Loading features from: features/*.feature');
expect(stdout).toContain('Loading features from paths (1):');
expect(stdout).toContain(path.normalize('cli-option-verbose/features/sample.feature'));
expect(stdout).toContain('Loading steps from: steps.ts');
expect(stdout).toContain('Clearing output dir:');
expect(stdout).toContain(
Expand Down

0 comments on commit e2f3907

Please sign in to comment.