Skip to content
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 package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions qase-playwright/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# playwright-qase-reporter@2.5.4

## Fixed

- Qase test case IDs that are `<= 0` passed via the runtime API (`qase(0, name)`, `qase.id(0)`, `qase.projects({ PROJ1: [0] })`) are now dropped with a warning instead of being written to the test metadata. Previously these calls bypassed the parser-level filter introduced in 2.5.3 and could still produce HTTP 400 from the API. Bumped `qase-javascript-commons` pin to `~2.7.4`.

# playwright-qase-reporter@2.5.3

## Fixed
Expand Down
4 changes: 2 additions & 2 deletions qase-playwright/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "playwright-qase-reporter",
"version": "2.5.3",
"version": "2.5.4",
"description": "Qase TMS Playwright Reporter",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
Expand Down Expand Up @@ -49,7 +49,7 @@
"license": "Apache-2.0",
"dependencies": {
"chalk": "^4.1.2",
"qase-javascript-commons": "~2.7.3",
"qase-javascript-commons": "~2.7.4",
"uuid": "11.1.1"
},
"peerDependencies": {
Expand Down
18 changes: 13 additions & 5 deletions qase-playwright/src/playwright.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { v4 as uuidv4 } from 'uuid';
import { PlaywrightQaseReporter } from './reporter';
import * as path from 'path';
import { getMimeTypes, formatTitleWithProjectMapping } from 'qase-javascript-commons';
import { filterPositiveIds } from 'qase-javascript-commons/internal';

export const ReporterContentType = 'application/qase.metadata+json';
const defaultContentType = 'application/octet-stream';
Expand Down Expand Up @@ -60,7 +61,7 @@ export const qase = (

const newName = `${name} (Qase ID: ${caseIds.join(',')})`;

PlaywrightQaseReporter.addIds(ids, newName);
PlaywrightQaseReporter.addIds(filterPositiveIds(ids), newName);

return newName;
};
Expand All @@ -79,9 +80,10 @@ export const qase = (
*
*/
qase.id = function(value: number | number[]) {
addMetadata({
ids: Array.isArray(value) ? value : [value],
});
const ids = filterPositiveIds(Array.isArray(value) ? value : [value]);
if (ids.length > 0) {
addMetadata({ ids });
}
return this;
};

Expand All @@ -98,7 +100,13 @@ qase.projects = function(mapping: ProjectMapping) {
const normalized: ProjectMapping = {};
for (const [code, ids] of Object.entries(mapping)) {
if (Array.isArray(ids) && ids.length > 0) {
normalized[code] = ids.map((id) => (typeof id === 'number' ? id : parseInt(String(id), 10))).filter((n) => !Number.isNaN(n));
const parsed = ids
.map((id) => (typeof id === 'number' ? id : parseInt(String(id), 10)))
.filter((n) => !Number.isNaN(n));
const filtered = filterPositiveIds(parsed);
if (filtered.length > 0) {
normalized[code] = filtered;
}
}
}
if (Object.keys(normalized).length > 0) {
Expand Down
62 changes: 61 additions & 1 deletion qase-playwright/test/playwright.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,4 +205,64 @@ describe('qase API', () => {
expect(result).toBe('Click button QaseExpRes:: Button should be clicked QaseData:: Button data');
});
});
});

describe('qase with non-positive ID (regression test)', () => {
it('drops zero before passing to PlaywrightQaseReporter.addIds, title is preserved for back-compat', () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
const title = qase(0, 'Test Name');
expect(title).toBe('Test Name (Qase ID: 0)'); // unchanged
expect(warn).toHaveBeenCalledWith(expect.stringContaining('0'));
warn.mockRestore();
});

it('keeps positive IDs and drops zero from a mixed list, title uses original IDs', () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
const title = qase([1, 0, 2], 'Test Name');
expect(title).toBe('Test Name (Qase ID: 1,0,2)');
expect(warn).toHaveBeenCalledWith(expect.stringContaining('0'));
warn.mockRestore();
});
});

describe('qase.id with non-positive ID (regression test)', () => {
it('does not attach metadata when ID is zero', () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
testInfoMock.attach.mockClear();
qase.id(0);
expect(testInfoMock.attach).not.toHaveBeenCalled();
warn.mockRestore();
});

it('drops zero from a mixed list and attaches only positive IDs', () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
testInfoMock.attach.mockClear();
qase.id([1, 0, 2]);
expect(testInfoMock.attach).toHaveBeenCalledWith('qase-metadata.json', {
contentType: 'application/qase.metadata+json',
body: Buffer.from(JSON.stringify({ ids: [1, 2] }), 'utf8'),
});
warn.mockRestore();
});
});

describe('qase.projects with non-positive ID (regression test)', () => {
it('omits a project entirely when all of its IDs are non-positive', () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
testInfoMock.attach.mockClear();
qase.projects({ PROJ1: [0], PROJ2: [5] });
expect(testInfoMock.attach).toHaveBeenCalledWith('qase-metadata.json', {
contentType: 'application/qase.metadata+json',
body: Buffer.from(JSON.stringify({ projectMapping: { PROJ2: [5] } }), 'utf8'),
});
warn.mockRestore();
});

it('does not attach metadata when every project is empty after filtering', () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
testInfoMock.attach.mockClear();
qase.projects({ PROJ1: [0], PROJ2: [-1] });
expect(testInfoMock.attach).not.toHaveBeenCalled();
warn.mockRestore();
});
});
});
6 changes: 6 additions & 0 deletions qase-wdio/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# wdio-qase-reporter@1.5.4

## Fixed

- Qase test case IDs that are `<= 0` passed to `qase.id(0)` are now dropped with a warning instead of being emitted as a metadata event. Previously this call bypassed the parser-level filter introduced in 1.5.3 and could still produce HTTP 400 from the API. Bumped `qase-javascript-commons` pin to `~2.7.4`.

# wdio-qase-reporter@1.5.3

## Fixed
Expand Down
4 changes: 2 additions & 2 deletions qase-wdio/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wdio-qase-reporter",
"version": "1.5.3",
"version": "1.5.4",
"description": "Qase WebDriverIO Reporter",
"homepage": "https://github.com/qase-tms/qase-javascript",
"sideEffects": false,
Expand Down Expand Up @@ -36,7 +36,7 @@
"@wdio/reporter": "^8.43.0",
"@wdio/types": "^8.41.0",
"csv-stringify": "^6.6.0",
"qase-javascript-commons": "~2.7.3",
"qase-javascript-commons": "~2.7.4",
"strip-ansi": "^7.1.2",
"uuid": "11.1.1"
}
Expand Down
6 changes: 5 additions & 1 deletion qase-wdio/src/wdio.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { events } from './events';
import { QaseStep, StepFunction, formatTitleWithProjectMapping } from 'qase-javascript-commons';
import { filterPositiveIds } from 'qase-javascript-commons/internal';

/**
* Send event to reporter
Expand Down Expand Up @@ -82,7 +83,10 @@ qase.projects = (mapping: ProjectMapping, name: string): string => {
* });
*/
qase.id = (value: number | number[]) => {
sendEvent(events.addQaseID, { ids: Array.isArray(value) ? value : [value] });
const ids = filterPositiveIds(Array.isArray(value) ? value : [value]);
if (ids.length > 0) {
sendEvent(events.addQaseID, { ids });
}
return this;
};

Expand Down
50 changes: 50 additions & 0 deletions qase-wdio/test/wdio.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* eslint-disable */
import { describe, expect, it, jest } from '@jest/globals';

describe('qase.id (wdio runtime API)', () => {
beforeEach(() => {
jest.resetModules();
});

it('drops zero and does not emit an event', () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
const emit = jest.spyOn(process, 'emit').mockImplementation(() => true);
const { qase } = require('../src/wdio');
qase.id(0);
// events.addQaseID = 'qase:id'
expect(emit).not.toHaveBeenCalledWith('qase:id', expect.anything());
expect(warn).toHaveBeenCalledWith(expect.stringContaining('0'));
warn.mockRestore();
emit.mockRestore();
});

it('emits only the positive IDs from a mixed list', () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
const emit = jest.spyOn(process, 'emit').mockImplementation(() => true);
const { qase } = require('../src/wdio');
qase.id([1, 0, 2]);
expect(emit).toHaveBeenCalledWith('qase:id', { ids: [1, 2] });
warn.mockRestore();
emit.mockRestore();
});

it('does not emit when all IDs are non-positive', () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
const emit = jest.spyOn(process, 'emit').mockImplementation(() => true);
const { qase } = require('../src/wdio');
qase.id([-1, 0]);
expect(emit).not.toHaveBeenCalledWith('qase:id', expect.anything());
warn.mockRestore();
emit.mockRestore();
});

it('emits positive ID without filtering', () => {
const warn = jest.spyOn(console, 'warn').mockImplementation(() => undefined);
const emit = jest.spyOn(process, 'emit').mockImplementation(() => true);
const { qase } = require('../src/wdio');
qase.id(42);
expect(emit).toHaveBeenCalledWith('qase:id', { ids: [42] });
warn.mockRestore();
emit.mockRestore();
});
});
Loading