Skip to content

Commit

Permalink
added simulcast scenario with required steps and functions
Browse files Browse the repository at this point in the history
  • Loading branch information
jwrobdolby committed Oct 29, 2024
1 parent 5c47928 commit 78363b4
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

Feature: Simulcast Feature
@only
Scenario: Viewer selects each layer and verifies video resolution
Given the "publisher1" opens "Publisher" app
When the "publisher1" starts the stream with the specified options
| codec | h264 |
| simulcast | true |
And the "publisher1" stream should be LIVE

When the "viewer1" opens "Viewer" app
Then the "viewer1" connected stream should be LIVE
When the "viewer1" disconnects from the published stream
Then the "viewer1" connected stream should be NOT LIVE
And the "viewer1" connects to the published stream with the specified options
| events | layers,active |
Then the "viewer1" connected stream should be LIVE

When the "viewer1" selects simulcast layer with encodingId "0"
Then the "viewer1" should receive video with resolution "320"x"180"

When the "viewer1" selects simulcast layer with encodingId "1"
Then the "viewer1" should receive video with resolution "640"x"360"

When the "viewer1" selects simulcast layer with encodingId "2"
Then the "viewer1" should receive video with resolution "1280"x"720"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { When } from "@cucumber/cucumber";
import { ScenarioWorld } from "cucumber-playwright-framework";
import {
viewerSelectLayer,
} from "../stepsImpl/viewerSelect.step.impl";

When(
/^the "([^"]*)" selects simulcast layer with encodingId "([^"]*)"$/,
async function (this: ScenarioWorld, actor: string, encodingId: string) {
await viewerSelectLayer(this, actor, encodingId);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
verifyViewerIsLive,
verifyViewerIsNotLive,
verifyMediaTracksEnabled,
verifyViewerMediaTracksDisabled
verifyViewerMediaTracksDisabled,
verifyViwerVideoResolution
} from "../stepsImpl/viewerVerification.step.impl";


Expand Down Expand Up @@ -35,3 +36,10 @@ Then(
await verifyViewerMediaTracksDisabled(this, actor, dataTable);
},
);

Then(
/^the "([^"]*)" should receive video with resolution "([^"]*)"x"([^"]*)"$/,
async function (this: ScenarioWorld, actor: string, width: string, height: string) {
await verifyViwerVideoResolution(this, actor, width, height);
},
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { ScenarioWorld, logger, runStep } from "cucumber-playwright-framework";


export async function viewerSelectLayer(
scenarioWorld: ScenarioWorld,
actor: string,
encodingId: string,
) {
logger.debug(`viewerSelectLayer function was called`);

await runStep([
`the ${actor} switch to the "Viewer" app`,
`the ${actor} executes the "window.millicastView.select({encodingId:"${encodingId}"})" JavaScript function on the page`,
], scenarioWorld);
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ async function verifyAudioPresent(scenarioWorld: ScenarioWorld, actor: string, p
}
const isAudioPresent = await retryUntilTrue(verifyMethod)
if (!isAudioPresent) {
throw Error(`Stream does not has a audio - for ${playerId} playerID and isAudioPresent is ${isAudioPresent}`)
throw Error(`Stream does not have an audio - for ${playerId} playerID and isAudioPresent is ${isAudioPresent}`)
}
}

Expand All @@ -98,7 +98,7 @@ async function verifyAudioNotPresent(scenarioWorld: ScenarioWorld, actor: string
}
const isAudioPresent = await retryUntilFalse(verifyMethod)
if (isAudioPresent) {
throw Error(`Stream has a audio - for ${playerId} playerID and isAudioPresent is ${isAudioPresent}`)
throw Error(`Stream has an audio - for ${playerId} playerID and isAudioPresent is ${isAudioPresent}`)
}
}

Expand Down Expand Up @@ -166,4 +166,20 @@ export async function verifyViewerMediaTracksDisabled(
], scenarioWorld);
await verifyAudioPresent(scenarioWorld, actor, playerId)
}
}

export async function verifyViwerVideoResolution(
scenarioWorld: ScenarioWorld,
actor: string,
width: string,
height: string,
) {
const videoElement = 'document.getElementsByTagName("video")[0]';
const playerId = await scenarioWorld.page.evaluate(`${videoElement}.id`);

await runStep([
`the ${actor} switch to the "Viewer" app`,
`the "TestUtil.getResolution('${playerId}')[0]" JavaScript function result should be ${height}`,
`the "TestUtil.getResolution('${playerId}')[1]" JavaScript function result should be ${width}`,
], scenarioWorld);
}
Original file line number Diff line number Diff line change
@@ -1,29 +1,20 @@
export async function retryUntilTrue(func: () => Promise<boolean>, timeoutSeconds = 10): Promise<boolean> {
const timeout = timeoutSeconds * 1000
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
const startTime = new Date().getTime()
let result = false
return retryUntil(func, timeoutSeconds, true);
}

while (new Date().getTime() - startTime < timeout) {
try {
result = await func()
if (result) return result
} catch {}
await sleep(500)
}
return result
export async function retryUntilFalse(func: () => Promise<boolean>, timeoutSeconds = 10): Promise<boolean> {
return retryUntil(func, timeoutSeconds, false);
}

export async function retryUntilFalse(func: () => Promise<boolean>, timeoutSeconds = 10): Promise<boolean> {
async function retryUntil(func: () => Promise<boolean>, timeoutSeconds = 10, condition = false): Promise<boolean> {
const timeout = timeoutSeconds * 1000
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
const startTime = new Date().getTime()
let result = true

while (new Date().getTime() - startTime < timeout) {
try {
result = await func()
if (result === false) return result
if (condition === result) return result
} catch {}
await sleep(500)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
export function parseData(data: Record<string, any>) {
const optionsDict: Record<string, any> = {};
//convert strings into boolean if true/false encountered
//convert string,string into array
Object.entries(data).forEach(([key, value]) => {
if (value.toLowerCase() === "true" || value.toLowerCase() === "false") {
if (value === "true" || value === "false") {
const myBool: boolean = value === "true";
optionsDict[key] = myBool;
} else {
}
else if (isNumeric(value)) {
optionsDict[key] = Number(value);
}
else if (value.split(",").length > 1) {
optionsDict[key] = value.split(",");
}
else {
optionsDict[key] = value;
}
});

return optionsDict;
}

function isNumeric(str: string) {
const regex = /^\d+$/;
return regex.test(str);
}

0 comments on commit 78363b4

Please sign in to comment.