Skip to content

Commit

Permalink
feat(serenity-bdd): auto-detect requirements hierarchy root directory
Browse files Browse the repository at this point in the history
when calling serenity-bdd run

Related tickets: re #1147
  • Loading branch information
jan-molak committed Jan 11, 2024
1 parent 863dd43 commit e2011b0
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 57 deletions.
3 changes: 0 additions & 3 deletions examples/playwright-test-todomvc/serenity.properties
@@ -1,6 +1,3 @@
serenity.project.name=Serenity/JS with Playwright
serenity.compress.filenames=false
#serenity.test.root=spec
#serenity.requirements.dir=spec
serenity.features.directory=spec
#serenity.estimated.tests.per.requirement=4
29 changes: 0 additions & 29 deletions packages/serenity-bdd/spec/index.spec.ts
Expand Up @@ -2,7 +2,6 @@ import { expect } from '@integration/testing-tools';
import { Stage } from '@serenity-js/core';
import { FileSystem, Path } from '@serenity-js/core/lib/io';
import { describe, it } from 'mocha';
import { given } from 'mocha-testdata';
import { createStubInstance } from 'sinon';
import type { JSONObject } from 'tiny-types';

Expand All @@ -27,23 +26,6 @@ describe('SerenityBDDReporter', () => {
expect(reporter.assignedTo).to.be.a('function');
});

given([
`features`,
`spec`,
`tests`,
`test`,
`src`,
]).
it('auto-detects the spec directory ', (specDirectory) => {
const reporter = SerenityBDDReporter.fromJSON({ specDirectory: specDirectory }).build({
stage,
fileSystem: fileSystem({ '/home/alice/my-project': { [`${ specDirectory }`]: {} } }),
outputStream: undefined,
});

expect((reporter as any).specDirectory).to.equal(cwd.resolve(Path.from(`/home/alice/my-project/${ specDirectory }`)));
})

it('can be configured to use a custom spec directory, as long as it exists', () => {
const specDirectory = 'e2e';
const reporter = SerenityBDDReporter.fromJSON({ specDirectory }).build({
Expand All @@ -66,17 +48,6 @@ describe('SerenityBDDReporter', () => {
})
).to.throw(`Configured specDirectory \`${ specDirectory }\` does not exist`);
});

it('defaults to the current working directory when no custom specDirectory is provided', () => {
const specDirectory = undefined;
const reporter = SerenityBDDReporter.fromJSON({ specDirectory }).build({
stage,
fileSystem: fileSystem({ '/home/alice/my-project': { } }),
outputStream: undefined,
});

expect((reporter as any).specDirectory).to.equal(cwd.resolve(Path.from(`/home/alice/my-project`)));
});
});
});

Expand Down
46 changes: 46 additions & 0 deletions packages/serenity-bdd/spec/stage/crew/SpecDirectory.spec.ts
@@ -0,0 +1,46 @@
import { expect } from '@integration/testing-tools';
import { FileSystem, Path } from '@serenity-js/core/lib/io';
import { describe, it } from 'mocha';
import { given } from 'mocha-testdata';
import type { JSONObject } from 'tiny-types';

import { SpecDirectory } from '../../../src/stage/crew/serenity-bdd-reporter/SpecDirectory';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { memfs } = require('memfs'); // Typings incorrectly assume the presence of "dom" lib

describe('SerenityBDDReporter', () => {

const cwd = Path.from(process.cwd());

describe('factory method', () => {

given([
`features`,
`spec`,
`tests`,
`test`,
`src`,
]).
it('auto-detects the spec directory ', (specDirectory) => {
const guessedSpecDirectory = new SpecDirectory(
fileSystem({ '/home/alice/my-project': { [`${ specDirectory }`]: {} } })
).guessLocation();

expect(guessedSpecDirectory).to.equal(cwd.resolve(Path.from(`/home/alice/my-project/${ specDirectory }`)));
})

it('defaults to the current working directory when no custom specDirectory is provided', () => {
const guessedSpecDirectory = new SpecDirectory(
fileSystem({ '/home/alice/my-project': { } })
).guessLocation();

expect(guessedSpecDirectory).to.equal(cwd.resolve(Path.from(`/home/alice/my-project`)));
});
});
});

function fileSystem(fakeDirectoryStructure: JSONObject) {
const cwd = Path.from(Object.keys(fakeDirectoryStructure)[0]);
return new FileSystem(cwd, memfs(fakeDirectoryStructure).fs)
}
16 changes: 9 additions & 7 deletions packages/serenity-bdd/src/cli/commands/run.ts
@@ -1,17 +1,19 @@
import { actorCalled, configure } from '@serenity-js/core';
import { Path } from '@serenity-js/core/lib/io';
import * as path from 'path'; // eslint-disable-line unicorn/import-style

import { FileSystem, Path } from '@serenity-js/core/lib/io';
import * as path from 'path'; // eslint-disable-line unicorn/import-style
import type { Argv } from '../Argv';
import { defaults } from '../defaults';
import { formatError } from '../io';
import { GAV } from '../model';
import { Printer } from '../Printer';
import { InvokeSerenityBDD, SerenityBDDArguments, SystemProperties } from '../screenplay';
import { NotificationReporter, ProgressReporter, RunCommandActors } from '../stage';
import { SpecDirectory } from '../../stage/crew/serenity-bdd-reporter/SpecDirectory';

const yargs = require('yargs'); // eslint-disable-line @typescript-eslint/no-var-requires

const cwd = new Path(process.cwd());

export = {
command: 'run',
desc: 'Invokes the Serenity BDD CLI jar to produce a Serenity BDD HTML report from the Serenity/JS JSON reports',
Expand All @@ -25,8 +27,8 @@ export = {
describe: 'A relative path to the directory where the Serenity BDD report should be produced',
},
features: {
default: defaults.featuresDir,
describe: 'A relative path to the directory containing the Cucumber.js feature files',
default: cwd.relative(new SpecDirectory(new FileSystem(cwd)).guessLocation()),
describe: 'A relative path to the requirements hierarchy root directory, such as "./features" or "./spec"',
},
artifact: {
default: defaults.artifact,
Expand All @@ -46,7 +48,7 @@ export = {
describe: `Base URL of your JIRA server`,
},
project: {
default: path.basename(process.cwd()),
default: cwd.basename(),
describe: `Project name to appear in the Serenity reports`,
},
shortFilenames: {
Expand All @@ -69,7 +71,7 @@ export = {
moduleRoot = path.resolve(__dirname, '../../../');

configure({
actors: new RunCommandActors(new Path(process.cwd())),
actors: new RunCommandActors(cwd),
crew: [
new NotificationReporter(printer),
new ProgressReporter(printer),
Expand Down
1 change: 0 additions & 1 deletion packages/serenity-bdd/src/cli/defaults.ts
Expand Up @@ -19,6 +19,5 @@ export const defaults = {
cacheDir: 'node_modules/@serenity-js/serenity-bdd/cache',
sourceDir: 'target/site/serenity',
reportDir: 'target/site/serenity',
featuresDir: 'features',
log: 'warn',
};
Expand Up @@ -9,6 +9,7 @@ import { ensure, isDefined } from 'tiny-types';

import { EventQueueProcessors } from './processors';
import type { SerenityBDDReporterConfig } from './SerenityBDDReporterConfig';
import { SpecDirectory } from './SpecDirectory';

/**
* A {@apilink StageCrewMember} that produces [Serenity BDD](http://serenity-bdd.info/)-standard JSON reports
Expand Down Expand Up @@ -199,14 +200,6 @@ export class SerenityBDDReporter implements StageCrewMember {

class SerenityBDDReporterBuilder implements StageCrewMemberBuilder<SerenityBDDReporter> {

private readonly specDirectoryCandidates = [
`features`,
`spec`,
`tests`,
`test`,
`src`,
];

constructor(private readonly config: SerenityBDDReporterConfig) {
}

Expand Down Expand Up @@ -234,14 +227,6 @@ class SerenityBDDReporterBuilder implements StageCrewMemberBuilder<SerenityBDDRe
}

private guessedSpecDir(fileSystem: FileSystem): Path {
for (const candidate of this.specDirectoryCandidates) {
const candidateSpecDirectory = Path.from(candidate);
if (fileSystem.exists(Path.from(candidate))) {
return fileSystem.resolve(candidateSpecDirectory);
}
}

// default to current working directory
return fileSystem.resolve(Path.from('.'));
return new SpecDirectory(fileSystem).guessLocation();
}
}
@@ -0,0 +1,27 @@
import { FileSystem, Path } from '@serenity-js/core/lib/io';

export class SpecDirectory {

private static readonly specDirectoryCandidates = [
`features`,
`spec`,
`tests`,
`test`,
`src`,
];

constructor(private readonly fileSystem: FileSystem) {
}

guessLocation(): Path {
for (const candidate of SpecDirectory.specDirectoryCandidates) {
const candidateSpecDirectory = Path.from(candidate);
if (this.fileSystem.exists(Path.from(candidate))) {
return this.fileSystem.resolve(candidateSpecDirectory);
}
}

// default to current working directory
return this.fileSystem.resolve(Path.from('.'));
}
}

0 comments on commit e2011b0

Please sign in to comment.