Skip to content

Commit

Permalink
fix(mutant-id): escape html in mutant attributes (#2070)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicojs committed Sep 2, 2022
1 parent a5e12d1 commit d96d53c
Show file tree
Hide file tree
Showing 11 changed files with 4,965 additions and 5 deletions.
4 changes: 2 additions & 2 deletions .vscode/launch.json
Expand Up @@ -26,8 +26,8 @@
"name": "Integration tests (Mutation testing elements)",
"program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
"env": {
"TS_NODE_IGNORE_DIAGNOSTICS": "1149,6133"
// "HEADLESS": "true",
"TS_NODE_IGNORE_DIAGNOSTICS": "1149,6133",
"HEADLESS": "true"
// "UPDATE_ALL_SCREENSHOTS": "true",
},
"args": ["--no-timeout", "--colors", "--config", "${workspaceFolder}/packages/elements/test/integration/.mocharc.jsonc"],
Expand Down
1 change: 1 addition & 0 deletions packages/elements/src/components/app/theme.scss
Expand Up @@ -61,6 +61,7 @@
--bs-list-group-active-bg: #{$darkly-list-group-active-bg};
--bs-list-group-active-border-color: #{$darkly-list-group-active-border-color};
--bs-table-border-color: #{$darkly-table-border-color};
--bs-table-hover-color: #{$darkly-body-color};
--bs-table-bg-hover: #{$darkly-table-hover-bg};
--bs-progress-bg: #{$darkly-progress-bg};

Expand Down
8 changes: 6 additions & 2 deletions packages/elements/src/components/file/file.component.ts
Expand Up @@ -7,7 +7,7 @@ import { bootstrap, prismjs } from '../../style';
import { findDiffIndices, gte, highlightCode, transformHighlightedLines } from '../../lib/code-helpers';
import { MutantResult, MutantStatus } from 'mutation-testing-report-schema/api';
import style from './file.scss';
import { getContextClassForStatus, getEmojiForStatus, scrollToCodeFragmentIfNeeded } from '../../lib/html-helpers';
import { escapeHtml, getContextClassForStatus, getEmojiForStatus, scrollToCodeFragmentIfNeeded } from '../../lib/html-helpers';
import { FileUnderTestModel, MutantModel } from 'mutation-testing-metrics';
import { createCustomEvent, MteCustomEvent } from '../../lib/custom-events';

Expand Down Expand Up @@ -202,7 +202,11 @@ export class FileComponent extends LitElement {
yield {
elementName: 'span',
id: mutant.id,
attributes: { class: `mutant ${mutant.status}`, title: title(mutant), 'mutant-id': mutant.id },
attributes: {
class: escapeHtml(`mutant ${mutant.status}`),
title: escapeHtml(title(mutant)),
'mutant-id': escapeHtml(mutant.id),
},
};
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/elements/test/integration/po/MutantElement.po.ts
Expand Up @@ -24,4 +24,7 @@ export abstract class MutantElement extends PageObject {
return;
}) as MutantStatus | undefined;
}
public async mutantId() {
return this.host.getAttribute('mutant-id');
}
}
4 changes: 4 additions & 0 deletions packages/elements/test/integration/po/MutantView.po.ts
Expand Up @@ -23,6 +23,10 @@ export class MutantView extends View {
public mutantMarker(mutantId: number | string) {
return new MutantMarker(this.$(`mte-file >>> span.mutant[mutant-id="${mutantId}"]`), this.browser);
}
public async mutantMarkers() {
const spans = await this.$$(`mte-file >>> span.mutant[mutant-id]`);
return spans.map((span) => new MutantMarker(span, this.browser));
}

public stateFilter() {
const context = selectShadowRoot(this.$('mte-file >>> mte-state-filter'));
Expand Down
33 changes: 33 additions & 0 deletions packages/elements/test/integration/unsanitized.it.spec.ts
@@ -0,0 +1,33 @@
import { expect } from 'chai';
import { getCurrent } from './lib/browser';
import { MutantMarker } from './po/MutantMarker.po';
import { ReportPage } from './po/ReportPage';

describe('Unsanitized example', () => {
let page: ReportPage;

beforeEach(() => {
page = new ReportPage(getCurrent());
});

describe('mutant view', () => {
beforeEach(async () => {
await page.navigateTo('unsanitized-example/#mutant/platform.ts');
});

it('should escape quotes in mutant ids', async () => {
const mutantMarkers = await page.mutantView.mutantMarkers();
let m: MutantMarker | undefined;
for (const mutantMarker of mutantMarkers) {
const mutantId = await mutantMarker.mutantId();
if (mutantId === 'src/platform.ts@7:31-7:38\nStringLiteral: ""') {
m = mutantMarker;
break;
}
}
expect(m).ok;
await m!.toggle();
expect(await page.mutantView.mutantDrawer().whenHalfOpen()).eq(true);
});
});
});
26 changes: 26 additions & 0 deletions packages/elements/test/unit/components/file.component.spec.ts
Expand Up @@ -73,6 +73,32 @@ describe(FileComponent.name, () => {
expect(sut.$('.mutant[mutant-id="2"]').title).eq('BlockStatement Survived');
});

it('should escape html inside mutant attributes', async () => {
// Arrange
const fileResult = createFileResult({
mutants: [
createMutantResult({
id: '"&test',
replacement: '-',
status: '"&test' as MutantStatus.NoCoverage,
mutatorName: 'ArithmeticOperator"&<script>alert</script>',
location: { start: { line: 2, column: 12 }, end: { line: 2, column: 13 } },
}),
],
source: 'function add(a, b) {\n return a + b;\n}',
});

// Act
sut.element.model = new FileUnderTestModel(fileResult, 'foo.js');
await sut.whenStable();

// Assert
const mutant = sut.$('.mutant');
expect(mutant.getAttribute('mutant-id')).eq('"&test');
expect(mutant.className).eq('mutant "&test');
expect(mutant.title).eq('ArithmeticOperator"&<script>alert</script> "&test');
});

it('should hide the mutant-dot if it is filtered', async () => {
// Arrange
const fileResult = createFileResult({
Expand Down
1 change: 1 addition & 0 deletions packages/elements/testResources/index.html
Expand Up @@ -28,6 +28,7 @@ <h1 class="display-1">Test resources</h1>
<a class="list-group-item list-group-item-action" href="/test-files-example">Test files example</a>
<a class="list-group-item list-group-item-action" href="/lighthouse-example">Lighthouse example</a>
<a class="list-group-item list-group-item-action" href="/large-example">Large example</a>
<a class="list-group-item list-group-item-action" href="/unsanitized-example">Unsanitized example</a>
</div>
</div>
</div>
Expand Down
21 changes: 21 additions & 0 deletions packages/elements/testResources/unsanitized-example/index.html
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<head>
<title>Test files example - Mutation test elements</title>
<script src="/mutation-test-elements.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=0.5" />
</head>

<body>
<a href="/">Back</a>
<mutation-test-report-app src="mutation-report.json"></mutation-test-report-app>
<script>
const app = document.getElementsByTagName('mutation-test-report-app').item(0);
function updateTheme() {
document.body.style.backgroundColor = app.themeBackgroundColor;
}
app.addEventListener('theme-changed', updateTheme);
updateTheme();
</script>
</body>
</html>

0 comments on commit d96d53c

Please sign in to comment.