Socket
Socket
Sign inDemoInstall

automutate-tests

Package Overview
Dependencies
32
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.3.5 to 0.4.0

.eslintrc.json

6

lib/describeTests.d.ts

@@ -1,2 +0,2 @@

import { IHierarchy } from "./hierarchyCrawler";
import { Hierarchy } from "./hierarchyCrawler";
/**

@@ -8,3 +8,3 @@ * Handler for a hierarchy containing test files.

*/
export declare type IOnTest = (hierarchy: IHierarchy) => Promise<void>;
export declare type IOnTest = (hierarchy: Hierarchy) => Promise<void>;
/**

@@ -16,2 +16,2 @@ * Recursively describes nested test cases in a hierarchy.

*/
export declare const describeTests: (hierarchy: IHierarchy, onTest: IOnTest, includes: RegExp[] | undefined, pathToTest?: string) => void;
export declare const describeTests: (hierarchy: Hierarchy, onTest: IOnTest, includes: RegExp[] | undefined, pathToTest?: string) => void;
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var _this = this;
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", { value: true });
exports.describeTests = void 0;
/**

@@ -45,9 +10,7 @@ * Recursively describes nested test cases in a hierarchy.

*/
exports.describeTests = function (hierarchy, onTest, includes, pathToTest) {
if (pathToTest === void 0) { pathToTest = ""; }
var subPathToTest = joinPathToTest(pathToTest, hierarchy.groupName);
exports.describeTests = (hierarchy, onTest, includes, pathToTest = "") => {
const subPathToTest = joinPathToTest(pathToTest, hierarchy.groupName);
if (!hierarchy.containsTest) {
describe(hierarchy.groupName, function () {
for (var _i = 0, _a = hierarchy.children; _i < _a.length; _i++) {
var child = _a[_i];
describe(hierarchy.groupName, () => {
for (const child of hierarchy.children) {
exports.describeTests(child, onTest, includes, subPathToTest);

@@ -58,22 +21,11 @@ }

}
var definer = isTestSkipped(includes, subPathToTest)
? it.skip
: it;
definer(hierarchy.groupName, function () { return __awaiter(_this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, onTest(hierarchy)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
}); });
const definer = isTestSkipped(includes, subPathToTest) ? it.skip : it;
definer(hierarchy.groupName, async () => {
await onTest(hierarchy);
});
};
var joinPathToTest = function (a, b) { return [a, b].join("/"); };
var isTestSkipped = function (includes, pathToTest) {
return includes === undefined || includes.length === 0
? false
: !includes.some(function (include) { return pathToTest.match(include) !== null; });
};
const joinPathToTest = (a, b) => [a, b].join("/");
const isTestSkipped = (includes, pathToTest) => includes === undefined || includes.length === 0
? false
: !includes.some((include) => pathToTest.match(include) !== null);
//# sourceMappingURL=describeTests.js.map
/**
* Nested hierarchy of test cases.
*/
export interface IHierarchy {
export interface Hierarchy {
/**
* Child test hierarchies.
*/
children: IHierarchy[];
children: Hierarchy[];
/**

@@ -23,23 +23,9 @@ * Whether this contains its own test files.

/**
* Generates a directory-based test hierarchy from the file system.
* Crawls a directory to generate a test hierarchy.
*
* @param indicatingFileName File name that must exist in a test case.
* @param topGroupName Friendly name of the directory.
* @param topDirectoryPath Full path to the directory.
* @returns The directory's generated test hierarchy.
*/
export declare class HierarchyCrawler {
/**
* File name that must exist in a test case.
*/
private readonly indicatingFileName;
/**
* Initialize a new instance of the HierarchyCrawler class.
*
* @param indicatingFileName File name that must exist in a test case.
*/
constructor(indicatingFileName: string);
/**
* Crawls a directory to generate a test hierarchy.
*
* @param groupName Friendly name of the directory.
* @param directoryPath Full path to the directory.
* @returns The directory's generated test hierarchy.
*/
crawl(groupName: string, directoryPath: string): IHierarchy;
}
export declare const crawlHierarchy: (indicatingFileName: string, topGroupName: string, topDirectoryPath: string) => Hierarchy;
"use strict";
exports.__esModule = true;
var fs = require("fs");
var glob = require("glob");
var path = require("path");
Object.defineProperty(exports, "__esModule", { value: true });
exports.crawlHierarchy = void 0;
const fs = require("fs");
const glob = require("glob");
const path = require("path");
/**
* Generates a directory-based test hierarchy from the file system.
* Crawls a directory to generate a test hierarchy.
*
* @param indicatingFileName File name that must exist in a test case.
* @param topGroupName Friendly name of the directory.
* @param topDirectoryPath Full path to the directory.
* @returns The directory's generated test hierarchy.
*/
var HierarchyCrawler = /** @class */ (function () {
/**
* Initialize a new instance of the HierarchyCrawler class.
*
* @param indicatingFileName File name that must exist in a test case.
*/
function HierarchyCrawler(indicatingFileName) {
this.indicatingFileName = indicatingFileName;
}
/**
* Crawls a directory to generate a test hierarchy.
*
* @param groupName Friendly name of the directory.
* @param directoryPath Full path to the directory.
* @returns The directory's generated test hierarchy.
*/
HierarchyCrawler.prototype.crawl = function (groupName, directoryPath) {
var _this = this;
var childDirectories = fs.readdirSync(directoryPath)
.filter(function (fileName) {
return fs.statSync(path.join(directoryPath, fileName)).isDirectory();
});
var matched = glob.sync(path.join(directoryPath, this.indicatingFileName));
exports.crawlHierarchy = (indicatingFileName, topGroupName, topDirectoryPath) => {
const crawl = (groupName, directoryPath) => {
const childDirectories = fs
.readdirSync(directoryPath)
.filter((fileName) => fs.statSync(path.join(directoryPath, fileName)).isDirectory());
const matched = glob.sync(path.join(directoryPath, indicatingFileName));
return {
children: childDirectories.map(function (childDirectory) {
return _this.crawl(childDirectory, path.join(directoryPath, childDirectory));
}),
children: childDirectories.map((childDirectory) => crawl(childDirectory, path.join(directoryPath, childDirectory))),
containsTest: matched.length > 0,
directoryPath: directoryPath,
groupName: groupName
directoryPath,
groupName,
};
};
return HierarchyCrawler;
}());
exports.HierarchyCrawler = HierarchyCrawler;
return crawl(topGroupName, topDirectoryPath);
};
//# sourceMappingURL=hierarchyCrawler.js.map
export * from "./hierarchyCrawler";
export * from "./testCase";
export * from "./testsFactory";
"use strict";
function __export(m) {
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
}
exports.__esModule = true;
__export(require("./hierarchyCrawler"));
__export(require("./testCase"));
__export(require("./testsFactory"));
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./hierarchyCrawler"), exports);
__exportStar(require("./testCase"), exports);
__exportStar(require("./testsFactory"), exports);
//# sourceMappingURL=index.js.map

@@ -1,2 +0,2 @@

import { IMutationsProvider } from "automutate";
import { MutationsProvider } from "automutate";
/**

@@ -9,4 +9,4 @@ * Creates mutation providers for files.

*/
export interface IMutationsProviderFactory {
(fileName: string, settingsFileName?: string): IMutationsProvider;
export interface MutationsProviderFactory {
(fileName: string, settingsFileName?: string): MutationsProvider;
}
"use strict";
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=mutationsProviderFactory.js.map

@@ -1,6 +0,6 @@

import { IMutationsProviderFactory } from "./mutationsProviderFactory";
import { MutationsProviderFactory } from "./mutationsProviderFactory";
/**
* File names and settings for test cases.
*/
export interface ITestCaseSettings {
export interface TestCaseSettings {
/**

@@ -38,2 +38,2 @@ * Whether to override the expected file content's with the actual results, instead of checking equality.

*/
export declare const runTestCase: (settings: ITestCaseSettings, mutationsProviderFactory: IMutationsProviderFactory) => Promise<void>;
export declare const runTestCase: (settings: TestCaseSettings, mutationsProviderFactory: MutationsProviderFactory) => Promise<void>;
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
var _this = this;
exports.__esModule = true;
var automutate_1 = require("automutate");
var chai_1 = require("chai");
var fs = require("mz/fs");
Object.defineProperty(exports, "__esModule", { value: true });
exports.runTestCase = void 0;
const automutate_1 = require("automutate");
const chai_1 = require("chai");
const fs = require("mz/fs");
/**

@@ -49,61 +14,30 @@ * Runs a single test case.

*/
exports.runTestCase = function (settings, mutationsProviderFactory) { return __awaiter(_this, void 0, void 0, function () {
var expectedContents, logger, actualContents;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
// Arrange
return [4 /*yield*/, arrangeFiles(settings.actual, settings.original)];
case 1:
// Arrange
_a.sent();
return [4 /*yield*/, fs.readFile(settings.expected)];
case 2:
expectedContents = (_a.sent()).toString();
logger = new automutate_1.Logger();
// Act
return [4 /*yield*/, automutate_1.runMutations({
logger: logger,
mutationsApplier: new automutate_1.FileMutationsApplier({ logger: logger }),
mutationsProvider: mutationsProviderFactory(settings.actual, settings.settings)
})];
case 3:
// Act
_a.sent();
return [4 /*yield*/, fs.readFile(settings.actual)];
case 4:
actualContents = (_a.sent()).toString();
if (settings.normalizeEndlines !== undefined) {
actualContents = actualContents.replace(/\r\n|\n/g, settings.normalizeEndlines);
}
if (!settings.accept) return [3 /*break*/, 6];
return [4 /*yield*/, fs.writeFile(settings.expected, actualContents)];
case 5:
_a.sent();
return [3 /*break*/, 7];
case 6:
chai_1.expect(actualContents).to.be.equal(expectedContents);
_a.label = 7;
case 7: return [2 /*return*/];
}
exports.runTestCase = async (settings, mutationsProviderFactory) => {
// Arrange
await arrangeFiles(settings.actual, settings.original);
const expectedContents = (await fs.readFile(settings.expected)).toString();
const logger = new automutate_1.NoopLogger();
// Act
await automutate_1.runMutations({
logger,
mutationsProvider: mutationsProviderFactory(settings.actual, settings.settings),
});
}); };
// Assert
let actualContents = (await fs.readFile(settings.actual)).toString();
if (settings.normalizeEndlines !== undefined) {
actualContents = actualContents.replace(/\r\n|\n/g, settings.normalizeEndlines);
}
if (settings.accept) {
await fs.writeFile(settings.expected, actualContents);
}
else {
chai_1.expect(actualContents).to.be.equal(expectedContents);
}
};
/**
* Resets a test case's files.
*/
var arrangeFiles = function (actual, original) { return __awaiter(_this, void 0, void 0, function () {
var _a, _b, _c;
return __generator(this, function (_d) {
switch (_d.label) {
case 0:
_b = (_a = fs).writeFile;
_c = [actual];
return [4 /*yield*/, fs.readFile(original)];
case 1: return [4 /*yield*/, _b.apply(_a, _c.concat([_d.sent()]))];
case 2:
_d.sent();
return [2 /*return*/];
}
});
}); };
const arrangeFiles = async (actual, original) => {
await fs.writeFile(actual, await fs.readFile(original));
};
//# sourceMappingURL=testCase.js.map

@@ -1,6 +0,6 @@

import { IMutationsProviderFactory } from "./mutationsProviderFactory";
import { MutationsProviderFactory } from "./mutationsProviderFactory";
/**
* Settings to describe test cases, namely file names and CLI flag equivalents.
*/
export interface ITestDescriptionSettings {
export interface TestDescriptionSettings {
/**

@@ -36,41 +36,2 @@ * Whether to override the expected file content's with the actual results, instead of checking equality.

/**
* Creates tests for provided cases.
*
* @deprecated Use {@link describeMutationTestCases} instead.
*/
export declare class TestsFactory {
/**
* Generates a directory-based test hierarchy from the file system.
*/
private readonly hierarchyCrawler;
/**
* Creates test cases from test case settings.
*/
private readonly mutationsProviderFactory;
/**
* Settings for the test cases.
*/
private readonly settings;
/**
* Initializes a new instance of the TestsFactory class.
*
* @param mutationsProviderFactory Creates test cases from test case settings.
* @param extension File extension of test case files.
*/
constructor(mutationsProviderFactory: IMutationsProviderFactory, settings: ITestDescriptionSettings);
/**
* Describes tests for the cases directory.
*
* @param casesPath Path to the test cases.
*/
describe(casesPath: string): void;
/**
* Creates and runs a test case.
*
* @param hierarchy The case's hierarchy.
* @returns A Promise for running the test.
*/
private runTest;
}
/**
* @param casesPath Path to the test cases.

@@ -80,2 +41,2 @@ * @param mutationsProviderFactory Creates test cases from test case settings.

*/
export declare const describeMutationTestCases: (casesPath: string, mutationsProviderFactory: IMutationsProviderFactory, settings: ITestDescriptionSettings) => void;
export declare const describeMutationTestCases: (casesPath: string, mutationsProviderFactory: MutationsProviderFactory, settings: TestDescriptionSettings) => void;
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (this && this.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
exports.__esModule = true;
var chalk_1 = require("chalk");
var glob = require("glob");
var path = require("path");
var describeTests_1 = require("./describeTests");
var hierarchyCrawler_1 = require("./hierarchyCrawler");
var testCase_1 = require("./testCase");
Object.defineProperty(exports, "__esModule", { value: true });
exports.describeMutationTestCases = void 0;
const chalk_1 = require("chalk");
const glob = require("glob");
const path = require("path");
const describeTests_1 = require("./describeTests");
const hierarchyCrawler_1 = require("./hierarchyCrawler");
const testCase_1 = require("./testCase");
/**
* Creates tests for provided cases.
*
* @deprecated Use {@link describeMutationTestCases} instead.
*/
var TestsFactory = /** @class */ (function () {
/**
* Initializes a new instance of the TestsFactory class.
*
* @param mutationsProviderFactory Creates test cases from test case settings.
* @param extension File extension of test case files.
*/
function TestsFactory(mutationsProviderFactory, settings) {
this.mutationsProviderFactory = mutationsProviderFactory;
this.settings = settings;
this.hierarchyCrawler = new hierarchyCrawler_1.HierarchyCrawler(this.settings.original);
}
/**
* Describes tests for the cases directory.
*
* @param casesPath Path to the test cases.
*/
TestsFactory.prototype.describe = function (casesPath) {
var _this = this;
if (this.settings.includes !== undefined && this.settings.includes.length !== 0) {
console.log("Including only tests that match any of:\n - ", chalk_1["default"].cyan(this.settings.includes.join("\n - ")));
}
describeTests_1.describeTests(this.hierarchyCrawler.crawl("cases", casesPath), function (hierarchy) { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) {
return [2 /*return*/, this.runTest(hierarchy)];
}); }); }, this.settings.includes);
};
/**
* Creates and runs a test case.
*
* @param hierarchy The case's hierarchy.
* @returns A Promise for running the test.
*/
TestsFactory.prototype.runTest = function (hierarchy) {
return __awaiter(this, void 0, void 0, function () {
var caseSettings;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
caseSettings = createTestCaseSettings(this.settings, hierarchy.directoryPath);
if (caseSettings === undefined) {
throw new Error("Could not find " + this.settings.original + " under " + hierarchy.directoryPath + ".");
}
return [4 /*yield*/, testCase_1.runTestCase(caseSettings, this.mutationsProviderFactory)];
case 1:
_a.sent();
return [2 /*return*/];
}
});
});
};
return TestsFactory;
}());
exports.TestsFactory = TestsFactory;
/**
* Creates settings for a test case.

@@ -109,24 +17,20 @@ *

*/
var createTestCaseSettings = function (settings, casePath) {
var matches = glob.sync(path.join(casePath, settings.original));
const createTestCaseSettings = (settings, casePath) => {
const matches = glob.sync(path.join(casePath, settings.original));
if (matches.length === 0) {
return undefined;
}
var original = matches[0];
var actual = path.join(casePath, getSettingsFile(settings, settings.actual, original));
var expected = path.join(casePath, getSettingsFile(settings, settings.expected, original));
const original = matches[0];
const actual = path.join(casePath, getSettingsFile(settings.actual, original));
const expected = path.join(casePath, getSettingsFile(settings.expected, original));
return {
accept: settings.accept,
actual: actual,
expected: expected,
actual,
expected,
normalizeEndlines: settings.normalizeEndlines,
original: original,
settings: path.join(casePath, settings.settings)
original,
settings: path.join(casePath, settings.settings),
};
};
var getSettingsFile = function (settings, filePath, original) {
return typeof filePath === "string"
? filePath
: filePath(original);
};
const getSettingsFile = (filePath, original) => (typeof filePath === "string" ? filePath : filePath(original));
/**

@@ -137,7 +41,21 @@ * @param casesPath Path to the test cases.

*/
exports.describeMutationTestCases = function (casesPath, mutationsProviderFactory, settings) {
// tslint:disable-next-line:deprecation
var testsFactory = new TestsFactory(mutationsProviderFactory, settings);
testsFactory.describe(casesPath);
exports.describeMutationTestCases = (casesPath, mutationsProviderFactory, settings) => {
/**
* Creates and runs a test case.
*
* @param hierarchy The case's hierarchy.
* @returns A Promise for running the test.
*/
const runTest = async (hierarchy) => {
const caseSettings = createTestCaseSettings(settings, hierarchy.directoryPath);
if (caseSettings === undefined) {
throw new Error(`Could not find ${settings.original} under ${hierarchy.directoryPath}.`);
}
await testCase_1.runTestCase(caseSettings, mutationsProviderFactory);
};
if (settings.includes !== undefined && settings.includes.length !== 0) {
console.log("Including only tests that match any of:\n - ", chalk_1.default.cyan(settings.includes.join("\n - ")));
}
describeTests_1.describeTests(hierarchyCrawler_1.crawlHierarchy(settings.original, "cases", casesPath), async (hierarchy) => runTest(hierarchy), settings.includes);
};
//# sourceMappingURL=testsFactory.js.map

@@ -0,0 +0,0 @@ Permission is hereby granted, free of charge, to any person obtaining

{
"name": "automutate-tests",
"version": "0.3.5",
"description": "Test harness for automutators.",
"version": "0.4.0",
"description": "Test harness for automutate consumers.",
"main": "lib/index.js",

@@ -18,5 +18,3 @@ "types": "lib/index.d.ts",

"quality",
"tslint",
"eslint",
"lesshint",
"tests"

@@ -35,8 +33,12 @@ ],

"@types/mz": "0.0.32",
"@types/node": "^11.13.4",
"tslint": "^5.15.0",
"@types/node": "^12.0.0",
"@typescript-eslint/eslint-plugin": "^5.3.0",
"@typescript-eslint/parser": "^5.3.0",
"eslint": "^8.2.0",
"eslint-config-prettier": "^8.3.0",
"prettier": "^2.4.1",
"typescript": "^3.4.3"
},
"dependencies": {
"automutate": "^0.7.2",
"automutate": "^0.8.0",
"chai": "^4.2.0",

@@ -48,6 +50,8 @@ "chalk": "^2.4.2",

"scripts": {
"src": "npm run src:tsc && npm run src:tslint",
"src:tsc": "tsc -p .",
"src:tslint": "tslint -c tslint.json -p tsconfig.json -t stylish"
"compile": "tsc",
"format": "yarn prettier --write",
"format:verify": "yarn prettier --list-different \"**/*.{js,json,md,ts,yml}\"",
"format:write-all": "yarn format:verify --write",
"lint": "eslint \"./src/*.ts\" \"./src/**/*.ts\" --max-warnings 0 --report-unused-disable-directives"
}
}
# automutate-tests
[![Greenkeeper badge](https://badges.greenkeeper.io/automutate/automutate-tests.svg)](https://greenkeeper.io/)
End-to-end test utilities for packages that rely on `automutate`.

@@ -6,0 +4,0 @@

@@ -1,2 +0,2 @@

import { IHierarchy } from "./hierarchyCrawler";
import { Hierarchy } from "./hierarchyCrawler";

@@ -9,3 +9,3 @@ /**

*/
export type IOnTest = (hierarchy: IHierarchy) => Promise<void>;
export type IOnTest = (hierarchy: Hierarchy) => Promise<void>;

@@ -19,25 +19,23 @@ /**

export const describeTests = (
hierarchy: IHierarchy,
onTest: IOnTest,
includes: RegExp[] | undefined,
pathToTest: string = "",
hierarchy: Hierarchy,
onTest: IOnTest,
includes: RegExp[] | undefined,
pathToTest = ""
): void => {
const subPathToTest = joinPathToTest(pathToTest, hierarchy.groupName);
if (!hierarchy.containsTest) {
describe(hierarchy.groupName, (): void => {
for (const child of hierarchy.children) {
describeTests(child, onTest, includes, subPathToTest);
}
});
const subPathToTest = joinPathToTest(pathToTest, hierarchy.groupName);
if (!hierarchy.containsTest) {
describe(hierarchy.groupName, (): void => {
for (const child of hierarchy.children) {
describeTests(child, onTest, includes, subPathToTest);
}
});
return;
}
return;
}
const definer = isTestSkipped(includes, subPathToTest)
? it.skip
: it;
const definer = isTestSkipped(includes, subPathToTest) ? it.skip : it;
definer(hierarchy.groupName, async (): Promise<void> => {
await onTest(hierarchy);
});
definer(hierarchy.groupName, async (): Promise<void> => {
await onTest(hierarchy);
});
};

@@ -47,5 +45,8 @@

const isTestSkipped = (includes: RegExp[] | undefined, pathToTest: string): boolean =>
includes === undefined || includes.length === 0
? false
: !includes.some((include) => pathToTest.match(include) !== null);
const isTestSkipped = (
includes: RegExp[] | undefined,
pathToTest: string
): boolean =>
includes === undefined || includes.length === 0
? false
: !includes.some((include) => pathToTest.match(include) !== null);

@@ -8,64 +8,57 @@ import * as fs from "fs";

*/
export interface IHierarchy {
/**
* Child test hierarchies.
*/
children: IHierarchy[];
export interface Hierarchy {
/**
* Child test hierarchies.
*/
children: Hierarchy[];
/**
* Whether this contains its own test files.
*/
containsTest: boolean;
/**
* Whether this contains its own test files.
*/
containsTest: boolean;
/**
* Path to the hierarchy.
*/
directoryPath: string;
/**
* Path to the hierarchy.
*/
directoryPath: string;
/**
* Friendly name of the hierarchy.
*/
groupName: string;
/**
* Friendly name of the hierarchy.
*/
groupName: string;
}
/**
* Generates a directory-based test hierarchy from the file system.
* Crawls a directory to generate a test hierarchy.
*
* @param indicatingFileName File name that must exist in a test case.
* @param topGroupName Friendly name of the directory.
* @param topDirectoryPath Full path to the directory.
* @returns The directory's generated test hierarchy.
*/
export class HierarchyCrawler {
/**
* File name that must exist in a test case.
*/
private readonly indicatingFileName: string;
export const crawlHierarchy = (
indicatingFileName: string,
topGroupName: string,
topDirectoryPath: string
): Hierarchy => {
const crawl = (groupName: string, directoryPath: string): Hierarchy => {
const childDirectories = fs
.readdirSync(directoryPath)
.filter((fileName) =>
fs.statSync(path.join(directoryPath, fileName)).isDirectory()
);
/**
* Initialize a new instance of the HierarchyCrawler class.
*
* @param indicatingFileName File name that must exist in a test case.
*/
public constructor(indicatingFileName: string) {
this.indicatingFileName = indicatingFileName;
}
const matched = glob.sync(path.join(directoryPath, indicatingFileName));
/**
* Crawls a directory to generate a test hierarchy.
*
* @param groupName Friendly name of the directory.
* @param directoryPath Full path to the directory.
* @returns The directory's generated test hierarchy.
*/
public crawl(groupName: string, directoryPath: string): IHierarchy {
const childDirectories: string[] = fs.readdirSync(directoryPath)
.filter((fileName: string): boolean =>
fs.statSync(path.join(directoryPath, fileName)).isDirectory());
return {
children: childDirectories.map((childDirectory) =>
crawl(childDirectory, path.join(directoryPath, childDirectory))
),
containsTest: matched.length > 0,
directoryPath,
groupName,
};
};
const matched = glob.sync(path.join(directoryPath, this.indicatingFileName));
return {
children: childDirectories.map((childDirectory: string): IHierarchy =>
this.crawl(childDirectory, path.join(directoryPath, childDirectory))),
containsTest: matched.length > 0,
directoryPath,
groupName,
};
}
}
return crawl(topGroupName, topDirectoryPath);
};
export * from "./hierarchyCrawler";
export * from "./testCase";
export * from "./testsFactory";

@@ -1,2 +0,2 @@

import { IMutationsProvider } from "automutate";
import { MutationsProvider } from "automutate";

@@ -10,4 +10,4 @@ /**

*/
export interface IMutationsProviderFactory {
(fileName: string, settingsFileName?: string): IMutationsProvider;
export interface MutationsProviderFactory {
(fileName: string, settingsFileName?: string): MutationsProvider;
}

@@ -1,6 +0,6 @@

import { FileMutationsApplier, Logger, runMutations } from "automutate";
import { NoopLogger, runMutations } from "automutate";
import { expect } from "chai";
import * as fs from "mz/fs";
import { IMutationsProviderFactory } from "./mutationsProviderFactory";
import { MutationsProviderFactory } from "./mutationsProviderFactory";

@@ -10,32 +10,32 @@ /**

*/
export interface ITestCaseSettings {
/**
* Whether to override the expected file content's with the actual results, instead of checking equality.
*/
accept?: boolean;
export interface TestCaseSettings {
/**
* Whether to override the expected file content's with the actual results, instead of checking equality.
*/
accept?: boolean;
/**
* File name for the mutation result.
*/
actual: string;
/**
* File name for the mutation result.
*/
actual: string;
/**
* File name for what the mutation result should be.
*/
expected: string;
/**
* File name for what the mutation result should be.
*/
expected: string;
/**
* Endlines to normalize \r\n|\n to, if anything.
*/
normalizeEndlines?: string;
/**
* Endlines to normalize \r\n|\n to, if anything.
*/
normalizeEndlines?: string;
/**
* File name for the original file contents.
*/
original: string;
/**
* File name for the original file contents.
*/
original: string;
/**
* File name for the settings file.
*/
settings: string;
/**
* File name for the settings file.
*/
settings: string;
}

@@ -51,29 +51,36 @@

export const runTestCase = async (
settings: ITestCaseSettings,
mutationsProviderFactory: IMutationsProviderFactory,
settings: TestCaseSettings,
mutationsProviderFactory: MutationsProviderFactory
): Promise<void> => {
// Arrange
await arrangeFiles(settings.actual, settings.original);
const expectedContents: string = (await fs.readFile(settings.expected)).toString();
const logger = new Logger();
// Arrange
await arrangeFiles(settings.actual, settings.original);
const expectedContents: string = (
await fs.readFile(settings.expected)
).toString();
const logger = new NoopLogger();
// Act
await runMutations({
logger,
mutationsApplier: new FileMutationsApplier({ logger }),
mutationsProvider: mutationsProviderFactory(settings.actual, settings.settings),
});
// Act
await runMutations({
logger,
mutationsProvider: mutationsProviderFactory(
settings.actual,
settings.settings
),
});
// Assert
let actualContents: string = (await fs.readFile(settings.actual)).toString();
// Assert
let actualContents: string = (await fs.readFile(settings.actual)).toString();
if (settings.normalizeEndlines !== undefined) {
actualContents = actualContents.replace(/\r\n|\n/g, settings.normalizeEndlines);
}
if (settings.normalizeEndlines !== undefined) {
actualContents = actualContents.replace(
/\r\n|\n/g,
settings.normalizeEndlines
);
}
if (settings.accept) {
await fs.writeFile(settings.expected, actualContents);
} else {
expect(actualContents).to.be.equal(expectedContents);
}
if (settings.accept) {
await fs.writeFile(settings.expected, actualContents);
} else {
expect(actualContents).to.be.equal(expectedContents);
}
};

@@ -84,4 +91,7 @@

*/
const arrangeFiles = async (actual: string, original: string): Promise<void> => {
await fs.writeFile(actual, await fs.readFile(original));
const arrangeFiles = async (
actual: string,
original: string
): Promise<void> => {
await fs.writeFile(actual, await fs.readFile(original));
};

@@ -6,5 +6,5 @@ import chalk from "chalk";

import { describeTests } from "./describeTests";
import { HierarchyCrawler, IHierarchy } from "./hierarchyCrawler";
import { IMutationsProviderFactory } from "./mutationsProviderFactory";
import { ITestCaseSettings, runTestCase } from "./testCase";
import { crawlHierarchy, Hierarchy } from "./hierarchyCrawler";
import { MutationsProviderFactory } from "./mutationsProviderFactory";
import { TestCaseSettings, runTestCase } from "./testCase";

@@ -14,110 +14,40 @@ /**

*/
export interface ITestDescriptionSettings {
/**
* Whether to override the expected file content's with the actual results, instead of checking equality.
*/
accept?: boolean;
export interface TestDescriptionSettings {
/**
* Whether to override the expected file content's with the actual results, instead of checking equality.
*/
accept?: boolean;
/**
* File name or file name generator for the mutation result.
*/
actual: string | ((original: string) => string);
/**
* File name or file name generator for the mutation result.
*/
actual: string | ((original: string) => string);
/**
* File name or file name generator for what the mutation result should be.
*/
expected: string | ((original: string) => string);
/**
* File name or file name generator for what the mutation result should be.
*/
expected: string | ((original: string) => string);
/**
* Wildcard(s) of tests to run.
*/
includes?: RegExp[];
/**
* Wildcard(s) of tests to run.
*/
includes?: RegExp[];
/**
* Endlines to normalize \r\n|\n to, if anything.
*/
normalizeEndlines?: string;
/**
* Endlines to normalize \r\n|\n to, if anything.
*/
normalizeEndlines?: string;
/**
* File name for the original file contents.
*/
original: string;
/**
* File name for the original file contents.
*/
original: string;
/**
* File name for the settings file.
*/
settings: string;
/**
* File name for the settings file.
*/
settings: string;
}
/**
* Creates tests for provided cases.
*
* @deprecated Use {@link describeMutationTestCases} instead.
*/
export class TestsFactory {
/**
* Generates a directory-based test hierarchy from the file system.
*/
private readonly hierarchyCrawler: HierarchyCrawler;
/**
* Creates test cases from test case settings.
*/
private readonly mutationsProviderFactory: IMutationsProviderFactory;
/**
* Settings for the test cases.
*/
private readonly settings: ITestDescriptionSettings;
/**
* Initializes a new instance of the TestsFactory class.
*
* @param mutationsProviderFactory Creates test cases from test case settings.
* @param extension File extension of test case files.
*/
public constructor(mutationsProviderFactory: IMutationsProviderFactory, settings: ITestDescriptionSettings) {
this.mutationsProviderFactory = mutationsProviderFactory;
this.settings = settings;
this.hierarchyCrawler = new HierarchyCrawler(this.settings.original);
}
/**
* Describes tests for the cases directory.
*
* @param casesPath Path to the test cases.
*/
public describe(casesPath: string): void {
if (this.settings.includes !== undefined && this.settings.includes.length !== 0) {
console.log(
"Including only tests that match any of:\n - ",
chalk.cyan(this.settings.includes.join("\n - ")),
);
}
describeTests(
this.hierarchyCrawler.crawl("cases", casesPath),
async (hierarchy: IHierarchy): Promise<void> => this.runTest(hierarchy),
this.settings.includes,
);
}
/**
* Creates and runs a test case.
*
* @param hierarchy The case's hierarchy.
* @returns A Promise for running the test.
*/
private async runTest(hierarchy: IHierarchy): Promise<void> {
const caseSettings = createTestCaseSettings(this.settings, hierarchy.directoryPath);
if (caseSettings === undefined) {
throw new Error(`Could not find ${this.settings.original} under ${hierarchy.directoryPath}.`);
}
await runTestCase(caseSettings, this.mutationsProviderFactory);
}
}
/**
* Creates settings for a test case.

@@ -129,26 +59,35 @@ *

*/
const createTestCaseSettings = (settings: ITestDescriptionSettings, casePath: string): ITestCaseSettings | undefined => {
const matches = glob.sync(path.join(casePath, settings.original));
if (matches.length === 0) {
return undefined;
}
const createTestCaseSettings = (
settings: TestDescriptionSettings,
casePath: string
): TestCaseSettings | undefined => {
const matches = glob.sync(path.join(casePath, settings.original));
if (matches.length === 0) {
return undefined;
}
const original = matches[0];
const actual = path.join(casePath, getSettingsFile(settings.actual, original));
const expected = path.join(casePath, getSettingsFile(settings.expected, original));
const original = matches[0];
const actual = path.join(
casePath,
getSettingsFile(settings.actual, original)
);
const expected = path.join(
casePath,
getSettingsFile(settings.expected, original)
);
return {
accept: settings.accept,
actual,
expected,
normalizeEndlines: settings.normalizeEndlines,
original,
settings: path.join(casePath, settings.settings),
};
return {
accept: settings.accept,
actual,
expected,
normalizeEndlines: settings.normalizeEndlines,
original,
settings: path.join(casePath, settings.settings),
};
};
const getSettingsFile = (filePath: string | ((original: string) => string), original: string): string =>
typeof filePath === "string"
? filePath
: filePath(original);
const getSettingsFile = (
filePath: string | ((original: string) => string),
original: string
): string => (typeof filePath === "string" ? filePath : filePath(original));

@@ -161,10 +100,38 @@ /**

export const describeMutationTestCases = (
casesPath: string,
mutationsProviderFactory: IMutationsProviderFactory,
settings: ITestDescriptionSettings,
casesPath: string,
mutationsProviderFactory: MutationsProviderFactory,
settings: TestDescriptionSettings
): void => {
// tslint:disable-next-line:deprecation
const testsFactory = new TestsFactory(mutationsProviderFactory, settings);
/**
* Creates and runs a test case.
*
* @param hierarchy The case's hierarchy.
* @returns A Promise for running the test.
*/
const runTest = async (hierarchy: Hierarchy): Promise<void> => {
const caseSettings = createTestCaseSettings(
settings,
hierarchy.directoryPath
);
if (caseSettings === undefined) {
throw new Error(
`Could not find ${settings.original} under ${hierarchy.directoryPath}.`
);
}
testsFactory.describe(casesPath);
await runTestCase(caseSettings, mutationsProviderFactory);
};
if (settings.includes !== undefined && settings.includes.length !== 0) {
console.log(
"Including only tests that match any of:\n - ",
chalk.cyan(settings.includes.join("\n - "))
);
}
describeTests(
crawlHierarchy(settings.original, "cases", casesPath),
async (hierarchy) => runTest(hierarchy),
settings.includes
);
};
{
"compilerOptions": {
"declaration": true,
"lib": [
"es2015"
],
"module": "commonjs",
"moduleResolution": "node",
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "lib",
"pretty": true,
"sourceMap": true,
"strict": true,
"target": "es3"
},
"exclude": [
"node_modules",
"test/**/*"
],
"include": [
"src/**/*"
]
"compilerOptions": {
"declaration": true,
"lib": ["es2015"],
"module": "commonjs",
"moduleResolution": "node",
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "lib",
"pretty": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"target": "es2020"
},
"exclude": ["node_modules"],
"include": ["src/**/*"]
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc