Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Automation Framework for Testing (AFT) package supporting JavaScript unit, integration and functional testing
the base Automated Functional Testing (AFT) library providing support for Plugins, configuration, and helper classes and functions
> npm i aft-core
the aft-core
package contains the aftConfig
constant class (instance of new AftConfig()
) for reading in configuration an aftconfig.json
file at the project root. this configuration can be read as a top-level field using aftConfig.get('field_name')
or aftConfig.get('field_name', defaultVal)
and can also be set without actually modifying the values in your aftconfig.json
using aftConfig.set('field_name', val)
. additionally, configuration classes can be read using AftConfig
with the aftConfig.getSection(ConfigClass)
which will read from your aftconfig.json
file for a field named ConfigClass
Ex: with an aftconfig.json
containing:
{
"SomeCustomClassConfig": {
"configField1": "%your_env_var%",
"configField2": "some-value",
"configField3": ["foo", true, 10]
}
}
and with the following environment variables set:
export your_env_var="an important value"
and a config class of:
export class SomeCustomClassConfig {
configField1: string = 'default_value_here';
configField2: string = 'another_default_value';
configField3: Array<string | boolean | number> = ['default_val'];
configField4: string = 'last_default_value';
}
can be accessed using an AftConfig
instance as follows:
const config = aftConfig.getSection(SomeCustomClassConfig); // or new AftConfig().getSection(SomeCustomClassConfig);
config.configField1; // returns "an important value"
config.configField2; // returns "some-value"
config.configField3; // returns ["foo", true, 10] as an array
config.configField4; // returns "last_default_value"
and if you wish to entirely disregard the configuration specified in your aftconfig.json
file you can use the following (still based on the above example):
const config = new AftConfig({
SomeCustomClassConfig: {
configField1: 'custom_value_here'
}
});
config.configField1; // returns "custom_value_here"
config.configField2; // returns "another_default_value"
config.configField3; // returns ["default_val"] as an array
config.configField4; // returns "last_default_value"
the aft-core
package contains several helper and utility classes, interfaces and functions to make functional testing and test development easier. These include:
module
that can run functions in a try-catch
with optional logging as well as provide formatted string outputs from Error
objectsdispose
function of a class that implements the Disposable
interface when doneMap
implementation that stores values with expirations where expired items will not be returned and are pruned from the Map
automatically. The CacheMap
can also optionally store its data on the filesystem allowing for other running node processes to read from the same cache data (e.g. sharded parallel testing)Map
implementation that stores its values in a file on the filesystem allowing multiple node processes to share the map data or to persist the data over multiple iterationswrite
and readAs<T>
functions to simplify file operationswait.forResult<T>(...): Promise<T>
, wait.forDuration(number)
, and wait.until(number | Date): Promise<void>
functions to allow for non-thread-locking waitsretry(retryable): Promise<T>
async function that will retry a given retryable
function until it succeeds or some condition such as number of attempts or elapsed time is exceededaft-core
also comes with some helpful types that can make building automated tests a bit easier such as:
T
and returning void
T
and returning a specified type Tr
T
accepting 0 or more arguments on the constructorto create your own simple reporting plugin that stores all logs until the finalise
function is called you would implement the code below.
NOTE: configuration for the below can be added in a object in the
aftconfig.json
namedOnDisposeConsoleReportingPluginConfig
and optionally containing values for the supported properties of theOnDisposeConsoleReportingPluginConfig
class
export class OnDisposeConsoleReportingPluginConfig {
maxLogLines: number = Infinity;
logLevel: LogLevel = 'warn';
};
export class OnDisposeConsoleReportingPlugin extends ReportingPlugin {
public override get logLevel(): LogLevel { return this._lvl; }
private readonly _lvl: LogLevel;
private readonly _logs: Map<string, Array<LogMessageData>>;
private readonly _maxLines: number;
constructor(aftCfg?: AftConfig) {
super(aftCfg);
const cfg = this.aftCfg.getSection(OnDisposeConsoleReportingPluginConfig);
this._lvl = cfg.logLevel ?? 'warn';
if (this.enabled) {
this._logs = new Map<string, Array<LogMessageData>>();
}
}
override initialise = async (name: string): Promise<void> => {
if (!this._logs.has(name)) {
this._logs.set(name, new Array<LogMessageData>());
}
}
override log = async (name: string, level: LogLevel, message: string, ...data: Array<any>): Promise<void> => {
if (this.enabled) {
if (LogLevel.toValue(level) >= LogLevel.toValue(this.logLevel) && level != 'none') {
const namedLogs: Array<LogMessageData> = this._logs.get(name);
namedLogs.push({name, level, message, args: data});
while (namedLogs.length > this.maxLogLines) {
namedLogs.shift();
}
}
}
}
override submitResult = async (name: string, result: TestResult): Promise<void> => {
/* ignore */
}
override finalise = async (name: string): Promise<void> => {
if (this.enabled) {
const namedLogs = this._logs.get(name);
while (namedLogs?.length > 0) {
let data = namedLogs.shift();
aftLogger.log({name: data.name, level: data.level, message: data.message, args: data.args});
});
aftLogger.log({name: this.constructor.name, level: 'debug', message: `finalised '${name}'`});
}
}
}
export class TestRailConfig {
username: string;
password: string;
url: string = 'https://you.testrail.io';
projectId: number;
suiteIds: Array<number> = new Array<number>();
planId: number;
enabled: boolean = false;
}
export class TestRailTestExecutionPolicyPlugin extends TestExecutionPolicyPlugin {
public override get enabled(): boolean { return this._enabled; }
private readonly _client: TestRailClient;
private readonly _enabled: boolean;
constructor(aftCfg?: AftConfig) {
super(aftCfg);
const cfg = this.aftCfg.getSection(TestRailConfig);
this._enabled = cfg.enabled ?? false;
if (this.enabled) {
this._client = new TestRailClient(this.aftCfg);
}
}
override shouldRun = async (testId: string): Promise<ProcessingResult> => {
const result = await this._client.getLastTestResult(testId);
if (result.status === 'Passed') {
return false; // test alraedy has passing result so don't run
}
return true;
}
}
the Verifier
class and verify
functions of aft-core
enable testing with pre-execution filtering based on integration with external test execution policy managers via plugin packages extending the TestExecutionPolicyPlugin
class (see examples above).
describe('Sample Test', () => {
it('can perform a demonstration of AFT', async () => {
let feature: FeatureObj = new FeatureObj();
/**
* the `verify(assertion).returns(expectation)` function
* checks any specified `TestExecutionPolicyPlugin` implementations
* to ensure the test should be run. It will then
* report to any `ReportingPlugin` implementations
* with an `TestResult` indicating the success,
* failure or skipped status
*/
await verify(async () => await feature.performAction())
.withTestId('C1234')
.and.withDescription("expect that performAction will return 'result of action'")
.returns('result of action');
});
});
NOTE: if using the
aft-jasmine-reporter
oraft-mocha-reporter
it is even easier to set the test IDs. see examples at jasmine and mocha
in the above example, the await feature.performAction()
call will only be run if a TestExecutionPolicyPlugin
is loaded and returns true
from it's shouldRun(testId: string)
function (or no TestExecutionPolicyPlugin
is loaded). additionally, any logs associated with the above verify
call will use a logName
of "expect_that_performAction_will_return_result_of_action"
resulting in log lines like the following:
09:14:01 - [expect that performAction will return 'result of action'] - TRACE - no TestExecutionPolicyPlugin in use so run all tests
FAQs
Automation Framework for Testing (AFT) package supporting JavaScript unit, integration and functional testing
The npm package aft-core receives a total of 348 weekly downloads. As such, aft-core popularity was classified as not popular.
We found that aft-core demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.