Skip to content
Open
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
73 changes: 46 additions & 27 deletions src/pipe/testomatio.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class TestomatioPipe {
this.groupTitle = params.groupTitle || process.env.TESTOMATIO_RUNGROUP_TITLE;
this.env = process.env.TESTOMATIO_ENV;
this.label = process.env.TESTOMATIO_LABEL;
this.runConfiguration = {};

// Create a new instance of gaxios with a custom config
this.client = new Gaxios({
Expand Down Expand Up @@ -145,47 +146,56 @@ class TestomatioPipe {

/**
* Asynchronously prepares and retrieves the Testomat.io test grepList based on the provided options.
* @param {Object} opts - The options for preparing the test grepList.
* @param {string} opts - The options string for preparing the test grepList.
* @returns {Promise<string[]>} - An array containing the retrieved
* test grepList, or an empty array if no tests are found or the request is disabled.
* @throws {Error} - Throws an error if there was a problem while making the request.
*/
async prepareRun(opts) {
if (!this.isEnabled) return [];

const clearOptions = parseFilterParams(opts);
const filters = parseFilterParams(opts);

if (!clearOptions) {
if (!filters.length) {
return [];
}

const { type, id } = clearOptions;

try {
const q = generateFilterRequestParams({
type,
id,
apiKey: this?.apiKey?.trim(),
});
const promises = filters.map(async ({ type, id }) => {
const q = generateFilterRequestParams({
type,
id,
apiKey: this?.apiKey?.trim(),
});

if (!q) {
return [];
}
if (!q) return [];

const resp = await this.client.request({
method: 'GET',
url: '/api/test_grep',
...q,
const resp = await this.client.request({
method: 'GET',
url: '/api/test_grep',
...q,
});

return Array.isArray(resp.data?.tests) ? resp.data.tests : [];
});

if (Array.isArray(resp.data?.tests) && resp.data?.tests?.length > 0) {
foundedTestLog(APP_PREFIX, resp.data.tests);
return resp.data.tests;
const results = await Promise.all(promises);
const allIds = [...new Set(results.flat())];

if (allIds.length > 0) {
foundedTestLog(APP_PREFIX, allIds);

const tests = allIds.filter(id => !id.startsWith('S'));
const suites = allIds.filter(id => id.startsWith('S'));
this.store.filterConfiguration = { tests, suites };

return allIds;
}

console.log(APP_PREFIX, `⛔ No tests found for your --filter --> ${type}=${id}`);
console.log(APP_PREFIX, `⛔ No tests found for filters: ${opts}`);
return [];
} catch (err) {
console.error(APP_PREFIX, `🚩 Error getting Testomat.io test grepList: ${err}`);
return [];
}
}

Expand Down Expand Up @@ -224,14 +234,23 @@ class TestomatioPipe {
const accessEvent = process.env.TESTOMATIO_PUBLISH ? 'publish' : null;

const coverageConfiguration = this.store?.coverageConfiguration;
const filterConfiguration = this.store?.filterConfiguration;

let description = null;
let configuration = null;
if (coverageConfiguration && (coverageConfiguration.tests?.length || coverageConfiguration.suites?.length)) {

const tests = [
...(coverageConfiguration?.tests?.map(id => id.replace(/^T/, '')) || []),
...(filterConfiguration?.tests?.map(id => id.replace(/^@?T?/, '')) || []),
];
const suites = [
...(coverageConfiguration?.suites?.map(id => id.replace(/^S/, '')) || []),
...(filterConfiguration?.suites?.map(id => id.replace(/^S/, '')) || []),
];

if (tests.length || suites.length) {
description = this.store?.coverageDescription || null;
configuration = {
tests: coverageConfiguration.tests?.map(id => id.replace(/^T/, '')) || [],
suites: coverageConfiguration.suites?.map(id => id.replace(/^S/, '')) || [],
};
configuration = { tests: [...new Set(tests)], suites: [...new Set(suites)] };
}
const runParams = Object.fromEntries(
Object.entries({
Expand Down
70 changes: 20 additions & 50 deletions src/utils/pipe_utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,58 +54,29 @@ function generateFilterRequestParams(params) {
}

/**
* Parse filter parameters from a string in the format "type=id".
* @param {string} opts - The input string containing the filter parameters.
* @returns {Object} An object containing the parsed filter parameters.
* The object has properties "type" and "id".
* Parse multiple filter parameters from a string in format "type1=id1,type2=id2".
* @param {string} opts - The input string containing filter parameters.
* @returns {Array<{type: string, id: string}>} Array of parsed filter objects.
*/
function parseFilterParams(opts) {
const [type, ...idParts] = opts.split('=');
const id = idParts.join('=');

const validType = updateFilterType(type);
if (!opts || typeof opts !== 'string') return [];

if (!validType) return undefined;
const filters = [];
const pairs = opts.split(',');

return {
type: validType,
id,
};
}

/**
* Update and validate the filter type.
* @param {string} type - The original filter type.
* @returns {string|undefined} The updated and validated filter type.
* Returns undefined if the type is not valid.
*/
function updateFilterType(type) {
if (!type || typeof type !== 'string') return;

let typeLowerCase = type.toLowerCase();

const filterTypes = ['tag-name', 'plan', 'label', 'jira-ticket'];

if (typeLowerCase === 'plan-id') {
typeLowerCase = 'plan';
}
for (const pair of pairs) {
const trimmed = pair.trim();
if (!trimmed || !trimmed.includes('=')) continue;

const filterApi = [
'tag',
'plan',
'label',
'jira',
// "ims-issue", //TODO: WIP
];
const [type, ...idParts] = trimmed.split('=');
const id = idParts.join('=');

if (!filterTypes.includes(typeLowerCase)) {
console.log(APP_PREFIX, `❗❗❗ Invalid filter: "${type}" start settings! Available option list: ${filterTypes}`);
return;
if (type && id) {
filters.push({ type: type.toLowerCase(), id });
}
}

const index = filterTypes.indexOf(typeLowerCase);

return index !== -1 ? filterApi[index] : undefined;
return filters;
}

/**
Expand Down Expand Up @@ -161,12 +132,11 @@ function parsePipeOptions(optionsStr) {
return options;
}

export {
updateFilterType,
parseFilterParams,
generateFilterRequestParams,
setS3Credentials,
statusEmoji,
export {
parseFilterParams,
generateFilterRequestParams,
setS3Credentials,
statusEmoji,
fullName,
parsePipeOptions
};
16 changes: 14 additions & 2 deletions src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -462,9 +462,21 @@ const fileSystem = {
},
};

const foundedTestLog = (app, tests) => {
const n = tests.length;
const foundedTestLog = (app, ids) => {
const isStringArray = ids.length > 0 && typeof ids[0] === 'string';

if (isStringArray) {
const suites = ids.filter(id => id.startsWith('S'));
const tests = ids.filter(id => !id.startsWith('S'));

const parts = [];
if (tests.length) parts.push(tests.length === 1 ? '1 test' : `${tests.length} tests`);
if (suites.length) parts.push(suites.length === 1 ? '1 suite' : `${suites.length} suites`);

return console.log(app, `✅ We found ${parts.join(' and ')} in Testomat.io!`);
}

const n = ids.length;
return console.log(app, `✅ We found ${n === 1 ? 'one test' : `${n} tests`} in Testomat.io!`);
};

Expand Down
73 changes: 32 additions & 41 deletions tests/unit/pipes/misc_pipe_test.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,52 @@
import { expect } from 'chai';
import { parseFilterParams, updateFilterType, generateFilterRequestParams } from '../../../src/utils/pipe_utils.js';
import { parseFilterParams, generateFilterRequestParams } from '../../../src/utils/pipe_utils.js';

describe('testing utils/pipe_utils.js functions', () => {
describe('updateFilterType function', () => {
it('should return "tag" when input is "tag-name"', () => {
const result = updateFilterType('tag-name');
expect(result).to.equal('tag');
});

it('should return "plan" when input is "plan-id"', () => {
const result = updateFilterType('plan-id');
expect(result).to.equal('plan');
describe('parseFilterParams function', () => {
it('should parse single filter correctly', () => {
const input = 'tag=123';
const result = parseFilterParams(input);
expect(result).to.deep.equal([{ type: 'tag', id: '123' }]);
});

it('should return "label" when input is "label"', () => {
const result = updateFilterType('label');
expect(result).to.equal('label');
it('should parse multiple filters correctly', () => {
const input = 'tag=smoke,suite=login';
const result = parseFilterParams(input);
expect(result).to.deep.equal([
{ type: 'tag', id: 'smoke' },
{ type: 'suite', id: 'login' },
]);
});

it('should return undefined when input is an unsupported type', () => {
const result = updateFilterType('unsupported-type');
expect(result).to.be.undefined;
it('should handle filter with equals in value', () => {
const input = 'label=key=value';
const result = parseFilterParams(input);
expect(result).to.deep.equal([{ type: 'label', id: 'key=value' }]);
});

it('should return undefined when input is an empty string', () => {
const result = updateFilterType('');
expect(result).to.be.undefined;
it('should return empty array for empty input', () => {
const result = parseFilterParams('');
expect(result).to.deep.equal([]);
});
});

describe('parseFilterParams function', () => {
it('should parse "tag-name" input correctly', () => {
const input = 'tag-name=123';
const result = parseFilterParams(input);
expect(result).to.deep.equal({ type: 'tag', id: '123' });
});
it('should parse "plan-id" input correctly', () => {
const input = 'plan-id=456';
const result = parseFilterParams(input);
expect(result).to.deep.equal({ type: 'plan', id: '456' });
it('should return empty array for undefined input', () => {
const result = parseFilterParams(undefined);
expect(result).to.deep.equal([]);
});

it('should parse "label" input correctly', () => {
const input = 'label=789';
it('should skip invalid pairs without equals sign', () => {
const input = 'tag=123,invalid,suite=456';
const result = parseFilterParams(input);
expect(result).to.deep.equal({ type: 'label', id: '789' });
expect(result).to.deep.equal([
{ type: 'tag', id: '123' },
{ type: 'suite', id: '456' },
]);
});

it('should handle unsupported type correctly', () => {
const input = 'unsupported-type=abc';
it('should lowercase type', () => {
const input = 'TAG=123';
const result = parseFilterParams(input);
expect(result).to.be.undefined;
});

it('should handle undefined input correctly', () => {
const result = parseFilterParams('plan-id=');
expect(result).to.deep.equal({ type: 'plan', id: '' });
expect(result).to.deep.equal([{ type: 'tag', id: '123' }]);
});
});

Expand Down
Loading