Skip to content

Commit

Permalink
fix(serenity-bdd): escape HTML tags in scenaio name and title
Browse files Browse the repository at this point in the history
Older versions of Serenity BDD don't escape HTML tags in scenario name and title.
This can lead to
reports getting truncated when a valid HTML tag, like `\<title /\>`, is used in scenario name.
This
change ensures that Serenity/JS escapes HTML tags it Serenity BDD json reports it produces.

Related tickets: closes #1630
  • Loading branch information
jan-molak committed Apr 15, 2023
1 parent 59a3b90 commit c5ca1bf
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 8 deletions.
2 changes: 1 addition & 1 deletion integration/web-specs/spec/screenplay/models/Page.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe('Page', () => {
describe('title()', () => {

/** @test {Page#title()} */
it('returns the value of the HTML title tag of the current page', async () => {
it('returns the value of the <title /> tag of the current page', async () => {
const page = await Page.current().answeredBy(actorCalled('Bernie'));
const title = await page.title();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
/* eslint-disable unicorn/filename-case, @typescript-eslint/indent */
import { EventRecorder, expect, PickEvent } from '@integration/testing-tools';
import { Stage } from '@serenity-js/core';
import { ArtifactGenerated, FeatureNarrativeDetected, SceneBackgroundDetected, SceneDescriptionDetected, SceneFinished, SceneStarts, TestRunFinishes } from '@serenity-js/core/lib/events';
import { CorrelationId, Description, ExecutionSuccessful, Name } from '@serenity-js/core/lib/model';
import {
ArtifactGenerated,
FeatureNarrativeDetected,
SceneBackgroundDetected,
SceneDescriptionDetected,
SceneFinished,
SceneStarts,
TestRunFinishes
} from '@serenity-js/core/lib/events';
import { FileSystemLocation, Path } from '@serenity-js/core/lib/io';
import {
Category,
CorrelationId,
Description,
ExecutionSuccessful,
Name,
ScenarioDetails
} from '@serenity-js/core/lib/model';
import { beforeEach, describe, it } from 'mocha';

import { defaultCardScenario } from '../../samples';
Expand Down Expand Up @@ -70,4 +86,31 @@ describe('SerenityBDDReporter', () => {
expect(report.userStory.narrative).to.equal('Feature narrative');
});
});

// https://github.com/serenity-js/serenity-js/pull/1630
it('escapes HTML entities in scenario name', () => {
const scenario = new ScenarioDetails(
new Name(`<abbr title="Questions and Answers">'Q&A'</abbr>`),
new Category('Support'),
new FileSystemLocation(
new Path(`payments/qna.feature`),
),
);

const escaped = `&lt;abbr title=&quot;Questions and Answers&quot;&gt;&apos;Q&amp;A&apos;&lt;/abbr&gt;`;

stage.announce(
new SceneStarts(sceneId, scenario),
new SceneFinished(sceneId, scenario, new ExecutionSuccessful()),
new TestRunFinishes(),
);

PickEvent.from(recorder.events)
.last(ArtifactGenerated, event => {
const report = event.artifact.map(_ => _);

expect(report.name).to.equal(escaped);
expect(report.title).to.equal(escaped);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/**
* @package
* @param text
*/
export function escapeHtml(text: string): string {
const replacements = {
'&': '&amp;',
'"': '&quot;',
'\'': '&apos;',
'<': '&lt;',
'>': '&gt;'
};

return text.replace( /["&'<>]/g, character => replacements[character] );
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './dashify';
export * from './errorReportFrom';
export * from './escapeHtml';
export * from './outcomeReportFrom';
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Path } from '@serenity-js/core/lib/io';
import { ScenarioDetails } from '@serenity-js/core/lib/model';
import { ensure, isNotBlank } from 'tiny-types';

import { dashify } from '../mappers';
import { dashify, escapeHtml } from '../mappers';
import { SerenityBDDReportContext } from '../SerenityBDDReportContext';

/**
Expand All @@ -13,13 +13,13 @@ export function scenarioDetailsOf<Context extends SerenityBDDReportContext>(deta
const name = ensure('scenario name', details.name.value, isNotBlank());
const category = ensure('scenario category', details.category.value, isNotBlank());

context.report.name = name;
context.report.title = name;
context.report.name = escapeHtml(name);
context.report.title = escapeHtml(name);
context.report.manual = false;
context.report.testSteps = [];
context.report.userStory = {
id: dashify(category),
storyName: category,
storyName: escapeHtml(category),
path: isFeatureFile(details.location.path)
? details.location.path.value
: '',
Expand All @@ -33,7 +33,6 @@ export function scenarioDetailsOf<Context extends SerenityBDDReportContext>(deta
/**
* @package
* @param {Path} path
* @returns {boolean}
*/
function isFeatureFile(path: Path): boolean {
return path && path.value.endsWith('.feature');
Expand Down

0 comments on commit c5ca1bf

Please sign in to comment.