test: Add skip reason to report (#16515)

* test: Add description, skip reason to Allure report.
* test: Adds reasons for skipped tests.
* test: Add more URL normalization test cases.
* ref: Move urlNormalization test to misc/.
This commit is contained in:
bgrozev
2025-10-07 12:28:39 -05:00
committed by GitHub
parent 38677dbe0a
commit 8a7ee9bae5
22 changed files with 130 additions and 83 deletions

View File

@@ -2,6 +2,10 @@
* An interface that tests can export (as a TEST_PROPERTIES property) to define what they require.
*/
export type ITestProperties = {
/**
* A more detailed description of what the test does, to be included in the Allure report.
*/
description?: string;
/** The test requires jaas, it should be skipped when the jaas configuration is not enabled. */
useJaas: boolean;
/** The test requires the webhook proxy. */

View File

@@ -18,8 +18,9 @@ export type IContext = {
roomName: string;
/**
* A flag that tests can set, which signals to the framework that the (rest of the) test suite should be skipped.
* A string value indicates the reason for the skipped (to be included in the Allure report).
*/
skipSuiteTests: boolean;
skipSuiteTests: boolean | string;
/**
* Test properties provided by the test file via TestProperties.setTestProperties. Used by the framework to
* set up the context appropriately.

View File

@@ -10,7 +10,7 @@ describe('Fake Dial-In', () => {
// check rest url is not configured
if (process.env.DIAL_IN_REST_URL) {
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'DIAL_IN_REST_URL is not set';
return;
}
@@ -25,8 +25,7 @@ describe('Fake Dial-In', () => {
// check dial-in is enabled, so skip
if (configEnabled) {
console.log('Dial in config is enabled, skipping fake dial in');
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'DIAL_IN_REST_URL is not set.';
}
});

View File

@@ -1,41 +0,0 @@
import { multiremotebrowser } from '@wdio/globals';
import { config } from '../../helpers/TestsConfig';
import { ensureTwoParticipants } from '../../helpers/participants';
describe('URL Normalisation', () => {
it('joining the meeting', async () => {
// if we are running with token this becomes ugly to match the URL
if (config.jwt.preconfiguredToken) {
ctx.skipSuiteTests = true;
return;
}
// a hack to extract the baseUrl that the test will use
const baseUrl = multiremotebrowser.getInstance('p1').options.baseUrl;
if (!baseUrl) {
throw new Error('baseUrl is not set');
}
await ensureTwoParticipants({
tenant: 'tenant@example.com',
roomName: `${ctx.roomName}@example.com`
});
});
it('check', async () => {
const currentUrlStr = await ctx.p1.driver.getUrl();
const currentUrl = new URL(currentUrlStr);
const path = currentUrl.pathname;
const parts = path.split('/');
expect(parts[1]).toBe('tenantexample.com');
// @ts-ignore
expect(parts[2]).toBe(`${ctx.roomName}example.com`);
});
});

View File

@@ -17,7 +17,8 @@ describe('AVModeration', () => {
if (!await p1.isModerator()
|| (await p1.isModerator() && await p2.isModerator() && await p3.isModerator())) {
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = `Unsupported moderator configuration: p1=${await p1.isModerator()},\
p2=${await p2.isModerator()}, p3=${await p3.isModerator()}`;
}
});

View File

@@ -17,7 +17,7 @@ describe('BreakoutRooms', () => {
await ensureTwoParticipants();
if (!await ctx.p1.isBreakoutRoomsSupported()) {
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'The environment does not support breakout rooms.';
}
});

View File

@@ -14,7 +14,7 @@ describe('Lobby', () => {
await ensureOneParticipant();
if (!await ctx.p1.execute(() => APP.conference._room.isLobbySupported())) {
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'The environment does not support lobby.';
}
});

View File

@@ -9,7 +9,7 @@ describe('Dial-In', () => {
it('join participant', async () => {
// check rest url is configured
if (!process.env.DIAL_IN_REST_URL) {
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'DIAL_IN_REST_URL is not set.';
return;
}
@@ -17,7 +17,7 @@ describe('Dial-In', () => {
// This is a temporary hack to avoid failing when running against a jaas env. The same cases are covered in
// jaas/dial/dialin.spec.ts.
if (testsConfig.jaas.enabled) {
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'JaaS is configured.';
return;
}
@@ -33,8 +33,7 @@ describe('Dial-In', () => {
}
if (!configEnabled) {
console.log('Dial in config is disabled, skipping dial-in tests');
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'The environment does not support dial-in, and no expectation has been set.';
}
});
@@ -45,13 +44,13 @@ describe('Dial-In', () => {
dialInPin = await ctx.p1.getDialInPin();
} catch (e) {
console.error('dial-in.test.no-pin');
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'No dial-in pin is available.';
throw e;
}
if (dialInPin.length === 0) {
console.error('dial-in.test.no-pin');
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'The dial-in pin is empty.';
throw new Error('no pin');
}

View File

@@ -11,7 +11,7 @@ describe('Invite', () => {
// This is a temporary hack to avoid failing when running against a jaas env. The same cases are covered in
// jaas/dial/dialin.spec.ts.
if (testsConfig.jaas.enabled) {
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'JaaS is configured.';
return;
}

View File

@@ -17,8 +17,7 @@ describe('iFrame API for Chat', () => {
p2 = await joinMuc({ name: 'p2', iFrameApi: true });
if (await p1.execute(() => config.disableIframeAPI)) {
// skip the test if iframeAPI is disabled
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'The environment has the iFrame API disabled.';
return;
}

View File

@@ -15,8 +15,7 @@ describe('Participants presence', () => {
const { p1, p2 } = ctx;
if (await p1.execute(() => config.disableIframeAPI)) {
// skip the test if iframeAPI is disabled
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'The environment has the iFrame API disabled.';
return;
}

View File

@@ -25,8 +25,7 @@ describe('Dial-in', () => {
const room = ctx.roomName;
if (!process.env.DIAL_IN_REST_URL) {
console.log('Dial-in test is disabled, set DIAL_IN_REST_URL to enable.');
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'DIAL_IN_REST_URL is not set.';
return;
}

View File

@@ -20,8 +20,7 @@ describe('Dial-out', () => {
const room = ctx.roomName;
if (!dialOutUrl) {
console.log('Dial-out test is disabled, set DIAL_OUT_URL to enable.');
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'DIAL_OUT_URL is not set.';
return;
}

View File

@@ -22,15 +22,13 @@ describe('SIP jibri invite', () => {
if (true) {
// This is temporary until we figure out how to fix it and configure it properly.
console.log('SIP jibri test is disabled.');
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'This test is disabled as the code doesn\'t work anymore.';
return;
}
if (!dialOutUrl) {
console.log('SIP jibri test is disabled, set SIP_JIBRI_DIAL_OUT_URL to enable.');
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'SIP_JIBRI_DIAL_OUT_URL is not set.';
return;
}

View File

@@ -31,8 +31,7 @@ describe('Recording and Live Streaming', () => {
// TODO: what should we do in this case? Add a config for this?
if (await p.execute(() => config.disableIframeAPI)) {
// skip the test if iframeAPI is disabled
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'The environment has the iFrame API disabled.';
return;
}

View File

@@ -27,7 +27,7 @@ describe('Transcriptions', () => {
if (await p1.execute(() => config.disableIframeAPI || !config.transcription?.enabled)) {
// skip the test if iframeAPI or transcriptions are disabled
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'The environment has the iFrame API or transcriptions disabled.';
return;
}

View File

@@ -28,8 +28,7 @@ describe('Visitors', () => {
await moderator.driver.waitUntil(() => moderator.execute(() => APP.conference._room.isVisitorsSupported()), {
timeout: 2000
}).catch(e => {
console.log(`Skipping test due to error: ${e}`);
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = `Because isVisitorsSupported() returned an error: ${e}.`;
});
visitor = await joinJaasMuc({

View File

@@ -0,0 +1,75 @@
import { setTestProperties } from '../../helpers/TestProperties';
import { config as testsConfig } from '../../helpers/TestsConfig';
import { joinMuc } from '../../helpers/joinMuc';
setTestProperties(__filename, {
usesBrowsers: [ 'p1' ]
});
describe('URL Normalisation', () => {
const tests = [
{
hint: '@ sign and .',
// Room as entered in the URL
room: '@example.com',
// Room as normalized in the URL
roomUrl: 'example.com',
// The room part of the MUC JID
roomJid: 'example.com',
// Tenant as entered in the URL
tenant: 'tenant@example.com',
// Tenant as normalized in the URL
tenantUrl: 'tenantexample.com',
// The tenant part of the MUC JID
tenantJid: 'tenantexample_com'
},
{
hint: 'Dashes',
room: 'foo-bar',
roomUrl: 'foo-bar',
roomJid: 'foo-bar',
tenant: 'tenant-example.com',
tenantUrl: 'tenant-example.com',
tenantJid: 'tenant-example_com'
},
{
hint: 'Cyrillic',
room: 'фоо-бар',
roomUrl: '%D1%84%D0%BE%D0%BE-%D0%B1%D0%B0%D1%80',
roomJid: '%d1%84%d0%be%d0%be-%d0%b1%d0%b0%d1%80',
tenant: 'обитател',
tenantUrl: '%D0%BE%D0%B1%D0%B8%D1%82%D0%B0%D1%82%D0%B5%D0%BB',
tenantJid: '%d0%be%d0%b1%d0%b8%d1%82%d0%b0%d1%82%d0%b5%d0%bb',
}
];
for (const test of tests) {
it(test.hint, async () => {
const fullRoom = `${test.room}${ctx.roomName}`;
const fullRoomUrl = `${test.roomUrl}${ctx.roomName}`;
const p = await joinMuc({
name: 'p1',
token: testsConfig.jwt.preconfiguredToken,
}, {
tenant: test.tenant,
roomName: fullRoom
});
const currentUrlStr = await p.driver.getUrl();
const currentUrl = new URL(currentUrlStr);
const path = currentUrl.pathname;
const parts = path.split('/');
expect(parts[1]).toBe(test.tenantUrl);
expect(parts[2]).toBe(fullRoomUrl);
const mucJid = (await p.execute(() => APP.conference._room.room.roomjid)).split('@');
const roomJid = mucJid[0];
const domain = mucJid[1];
expect(roomJid).toBe(`${test.roomJid}${ctx.roomName}`);
expect(domain.startsWith(`conference.${test.tenantJid}.`)).toBe(true);
});
}
});

View File

@@ -4,6 +4,8 @@ import { expectations } from '../../helpers/expectations';
import { ensureOneParticipant, ensureTwoParticipants } from '../../helpers/participants';
setTestProperties(__filename, {
description: 'This test checks the ability of a moderator to grant the "moderator" role to another participant. The\
test is skipped when the "allModerators" expectation is set.',
usesBrowsers: [ 'p1', 'p2' ]
});
@@ -12,8 +14,7 @@ describe('Grant moderator', () => {
it('setup', async () => {
if (expectations.moderation.allModerators) {
ctx.skipSuiteTests = true;
console.log('Skipping because allModerators is expected.');
ctx.skipSuiteTests = 'allModerators is expected';
return;
}
@@ -28,8 +29,7 @@ describe('Grant moderator', () => {
expect(functionAvailable).toBe(true);
} else {
if (!functionAvailable) {
ctx.skipSuiteTests = true;
console.log('Skipping because the grant moderator function is not available and not expected.');
ctx.skipSuiteTests = 'grantModerator is not available and not expected';
return;
}

View File

@@ -17,7 +17,7 @@ describe('Kick', () => {
// We verify elsewhere (moderation.spec.ts) that the first participant is a moderator.
if (!await p1.isModerator()) {
ctx.skipSuiteTests = true;
ctx.skipSuiteTests = 'the first participant is not a moderator';
}
});

View File

@@ -5,6 +5,8 @@ import { expectations } from '../../helpers/expectations';
import { joinMuc } from '../../helpers/joinMuc';
setTestProperties(__filename, {
description: 'This test asserts that participants have the expected role ("moderator" or not). Failures here\
most likely indicate that the environment or test framework is misconfigured.',
usesBrowsers: [ 'p1', 'p2' ]
});

View File

@@ -212,8 +212,7 @@ export const config: WebdriverIO.MultiremoteConfig = {
globalAny.ctx.testProperties = testProperties;
if (testProperties.useJaas && !testsConfig.jaas.enabled) {
console.warn(`JaaS is not configured, skipping ${testName}.`);
globalAny.ctx.skipSuiteTests = true;
globalAny.ctx.skipSuiteTests = 'JaaS is not configured';
return;
}
@@ -250,7 +249,7 @@ export const config: WebdriverIO.MultiremoteConfig = {
}
if (!tenant) {
console.log(`Can not configure WebhookProxy, missing tenant in config. Skipping ${testName}.`);
globalAny.ctx.skipSuiteTests = true;
globalAny.ctx.skipSuiteTests = 'WebHookProxy is required but not configured (missing tenant)';
return;
}
@@ -264,7 +263,7 @@ export const config: WebdriverIO.MultiremoteConfig = {
if (testProperties.useWebhookProxy && !globalAny.ctx.webhooksProxy) {
console.warn(`WebhookProxy is not available, skipping ${testName}`);
globalAny.ctx.skipSuiteTests = true;
globalAny.ctx.skipSuiteTests = 'WebhooksProxy is not required but not available';
}
},
@@ -313,14 +312,30 @@ export const config: WebdriverIO.MultiremoteConfig = {
*/
beforeTest(test, context) {
// Use the directory under 'tests/specs' as the parent suite
const match = test.file.match(/.*\/tests\/specs\/([^\/]+)\//);
const dir = match ? match[1] : false;
const dirMatch = test.file.match(/.*\/tests\/specs\/([^\/]+)\//);
const dir = dirMatch ? dirMatch[1] : false;
const fileMatch = test.file.match(/.*\/tests\/specs\/(.*)/);
const file = fileMatch ? fileMatch[1] : false;
if (ctx.testProperties.description) {
AllureReporter.addDescription(ctx.testProperties.description, 'text');
}
if (file) {
AllureReporter.addLink(`https://github.com/jitsi/jitsi-meet/blob/master/tests/specs/${file}`, 'Code');
}
if (dir) {
AllureReporter.addParentSuite(dir);
}
if (ctx.skipSuiteTests) {
if ((typeof ctx.skipSuiteTests) === 'string') {
AllureReporter.addDescription((ctx.testProperties.description || '')
+ '\n\nSkipped because: ' + ctx.skipSuiteTests, 'text');
}
console.log(`Skipping because: ${ctx.skipSuiteTests}`);
context.skip();
return;