Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Add more tests / fix removal of coverage dir #431

Merged
merged 5 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .nycrc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"src/linter/xmlTemplate/lib/JSTokenizer.js"
],
"check-coverage": true,
"statements": 82,
"branches": 74,
"functions": 89,
"lines": 82,
"statements": 87,
"branches": 79,
"functions": 94,
"lines": 87,
"watermarks": {
"statements": [70, 90],
"branches": [70, 90],
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@
"type": "module",
"types": "lib/index.d.ts",
"scripts": {
"build": "npm run cleanup && tsc -p tsconfig.build.json",
"build": "npm run clean-lib && tsc -p tsconfig.build.json",
"build-test": "tsc --noEmit -p .",
"build-watch": "npm run cleanup && tsc -w -p tsconfig.build.json",
"build-watch": "npm run clean-lib && tsc -w -p tsconfig.build.json",
"check-licenses": "licensee --errors-only",
"cleanup": "rimraf lib coverage",
"coverage": "nyc ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\"",
"clean-coverage": "rimraf coverage",
"clean-lib": "rimraf lib",
"coverage": "npm run clean-coverage && nyc ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\"",
"depcheck": "depcheck --ignores @commitlint/config-conventional,@istanbuljs/esm-loader-hook,rimraf,sap,mycomp,@ui5/linter",
"hooks:pre-push": "npm run lint:commit",
"lint": "eslint .",
Expand Down
2 changes: 1 addition & 1 deletion src/cli/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ async function handleLint(argv: ArgumentsCamelCase<LinterArg>) {

if (coverage) {
const coverageFormatter = new Coverage();
await writeFile("ui5lint-report.html", await coverageFormatter.format(res));
await writeFile("ui5lint-report.html", await coverageFormatter.format(res, new Date()));
}

if (format === "json") {
Expand Down
12 changes: 5 additions & 7 deletions src/formatter/coverage.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import path from "node:path";
import {
LintResult,
CoverageInfo,
CoverageCategory,
} from "../linter/LinterContext.js";
import {readFile} from "fs/promises";
import {readFile} from "node:fs/promises";
import {LintMessageSeverity} from "../linter/messages.js";

const visualizedSpace = "\u00b7";
Expand All @@ -17,7 +16,7 @@ function formatSeverity(severity: LintMessageSeverity) {
} else if (severity === LintMessageSeverity.Warning) {
return "warning";
} else {
throw new Error(`Unknown severity: ${LintMessageSeverity[severity]}`);
throw new Error(`Unknown severity: ${severity as number}`);
}
}

Expand Down Expand Up @@ -45,13 +44,13 @@ function escape(str: string) {
export class Coverage {
#buffer = "";

async format(lintResults: LintResult[]) {
async format(lintResults: LintResult[], reportDate: Date) {
this.#writeln(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UI5Lint Coverage Report ${new Date().toLocaleString()}</title>
<title>UI5Lint Coverage Report ${reportDate.toLocaleString("en-US")}</title>
<style>
html {
font-family: Arial, sans-serif;
Expand Down Expand Up @@ -97,9 +96,8 @@ export class Coverage {

for (const {filePath, messages, coverageInfo} of lintResults) {
const fileContent = await readFile(filePath, {encoding: "utf-8"});
const relativeFilePath = path.relative(process.cwd(), filePath);

this.#writeln(`<div class="file"><span>${escape(relativeFilePath)}</span>`);
this.#writeln(`<div class="file"><span>${escape(filePath)}</span>`);

fileContent.split("\n").forEach((code, i) => {
const line = i + 1;
Expand Down
8 changes: 5 additions & 3 deletions src/linter/ui5Types/amdTranspiler/transpiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,17 +103,19 @@ export default function transpileAmdToEsm(
if (strict) {
throw err;
}
// Usually the UnsupportedModuleError is already caught inside and not thrown, but this is a safety net
// in case it is thrown anyway.
if (err instanceof UnsupportedModuleError) {
log.verbose(`Failed to transform module ${fileName}: ${err.message}`);
if (err.stack && log.isLevelEnabled("verbose")) {
if (err.stack) {
log.verbose(`Stack trace:`);
log.verbose(err.stack);
}
return {source: content, map: ""};
} else if (err instanceof Error && err.message.startsWith("Debug Failure")) {
// We probably failed to create a valid AST
// We probably failed to create a valid AST. The error is thrown by TypeScript itself.
log.verbose(`AST transformation failed for module ${fileName}: ${err.message}`);
if (err.stack && log.isLevelEnabled("verbose")) {
if (err.stack) {
log.verbose(`Stack trace:`);
log.verbose(err.stack);
}
Expand Down
Binary file not shown.
136 changes: 136 additions & 0 deletions test/lib/formatter/coverage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import anyTest, {TestFn} from "ava";
import esmock from "esmock";
import sinonGlobal, {SinonStub} from "sinon";
import {LintResult} from "../../../src/linter/LinterContext.js";
import {CoverageCategory} from "../../../src/linter/LinterContext.js";
import {LintMessageSeverity} from "../../../src/linter/messages.js";

const test = anyTest as TestFn<{
lintResults: LintResult[];
sinon: sinonGlobal.SinonSandbox;
readFileStub: SinonStub;
Coverage: typeof import("../../../src/formatter/coverage.js").Coverage;
}>;

test.beforeEach(async (t) => {
const sinon = t.context.sinon = sinonGlobal.createSandbox();
const lintResults: LintResult[] = [
{
filePath: "manifest.json",
messages: [
{
ruleId: "async-component-flags",
severity: 1,
line: 17,
column: 12,
message: "<message>",
messageDetails: "<details>",
},
],
coverageInfo: [],
errorCount: 0,
warningCount: 1,
fatalErrorCount: 0,
},
{
filePath: "Test.js",
messages: [
{
ruleId: "no-deprecated-api",
severity: 2,
line: 2,
column: 9,
message: "<message>",
messageDetails: "<details>",
},
{
ruleId: "no-globals",
severity: 2,
line: 2,
column: 2,
message: "<message>",
messageDetails: "<details>",
},
],
coverageInfo: [
{
category: CoverageCategory.CallExpressionUnknownType,
line: 3,
column: 2,
message: "Unable to analyze this method call because the type of identifier in " +
"\"unknownFunctionCall()\"\" could not be determined",
},
],
errorCount: 2,
warningCount: 0,
fatalErrorCount: 0,
},
];
t.context.lintResults = lintResults;

t.context.readFileStub = sinon.stub().rejects(new Error("ENOENT: no such file or directory"));
t.context.readFileStub.withArgs("manifest.json", {encoding: "utf-8"}).resolves(
`{
"_version": "1.61.0",
"sap.app": {
"id": "sap.ui.demo.todo",
"type": "application"
},
"sap.ui5": {
"dependencies": {
"minUI5Version": "1.121.0",
"libs": {
"sap.ui.core": {}
}
},
"rootView": {
"viewName": "sap.ui.demo.todo.view.App",
"type": "XML",
"id": "app",
"async": true
}
}
}
`
);
t.context.readFileStub.withArgs("Test.js", {encoding: "utf-8"}).resolves(
`sap.ui.define(() => {
sap.ui.getCore();
unknownFunctionCall();
});
`
);

const {Coverage} = await esmock("../../../src/formatter/coverage.js", {
"node:fs/promises": {
readFile: t.context.readFileStub,
},
});
t.context.Coverage = Coverage;
});

test.afterEach.always((t) => {
t.context.sinon.restore();
});

test("Coverage Formatter", async (t) => {
const {lintResults, Coverage} = t.context;
const coverageFormatter = new Coverage();
const reportDate = new Date(Date.parse("2024-01-01T01:23:45"));
const coverageResult = await coverageFormatter.format(lintResults, reportDate);

t.snapshot(coverageResult);
});

test("Error: Unknown severity", async (t) => {
const {lintResults, Coverage} = t.context;
const coverageFormatter = new Coverage();
const reportDate = new Date(1731500927354);

lintResults[0].messages[0].severity =
3 as unknown as LintMessageSeverity; // Setting an invalid LintMessageSeverity value

await t.throwsAsync(coverageFormatter.format(lintResults, reportDate), {
message: "Unknown severity: 3",
});
});
Loading