-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #450 from THEOplayer/maintenance/e2e_extend
E2E tests
- Loading branch information
Showing
4 changed files
with
210 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,72 +1,65 @@ | ||
import { TestScope } from 'cavy'; | ||
import { Platform } from 'react-native'; | ||
import { PlayerEventType, SourceDescription } from 'react-native-theoplayer'; | ||
import dash from '../res/dash.json'; | ||
import hls from '../res/hls.json'; | ||
import mp4 from '../res/mp4.json'; | ||
import { PlayerEventType } from 'react-native-theoplayer'; | ||
import { expect, preparePlayerWithSource, waitForPlayerEventType, waitForPlayerEventTypes } from '../utils/Actions'; | ||
import { TestSourceDescription, TestSources } from '../utils/SourceUtils'; | ||
|
||
const SEEK_THRESHOLD = 250; | ||
|
||
function testBasicPlayout(spec: TestScope, title: string, source: SourceDescription) { | ||
spec.describe(title, function () { | ||
spec.it('dispatches sourcechange event on setting a source without autoplay', async function () { | ||
// Set source and wait for playback | ||
const player = await preparePlayerWithSource(source, false); | ||
export default function (spec: TestScope) { | ||
TestSources() | ||
.withPlain() | ||
.forEach((testSource: TestSourceDescription) => { | ||
spec.describe(`Set ${testSource.description} and auto-play`, function () { | ||
spec.it(`dispatches sourcechange event on setting the source without autoplay`, async function () { | ||
// Set source and wait for playback | ||
const player = await preparePlayerWithSource(testSource.source, false); | ||
|
||
// Still playing | ||
expect(player.paused).toBeTruthy(); | ||
}); | ||
// Still playing | ||
expect(player.paused).toBeTruthy(); | ||
}); | ||
|
||
spec.it('dispatches sourcechange, play and playing events in order on setting a source with autoplay', async function () { | ||
// Set source and wait for playback | ||
const player = await preparePlayerWithSource(source); | ||
spec.it(`dispatches sourcechange, play and playing events in order on setting the source with autoplay`, async function () { | ||
// Set source and wait for playback | ||
const player = await preparePlayerWithSource(testSource.source); | ||
|
||
// Still playing | ||
expect(player.paused).toBeFalsy(); | ||
}); | ||
// Still playing | ||
expect(player.paused).toBeFalsy(); | ||
}); | ||
|
||
spec.it('dispatches a seeked event after seeking', async function () { | ||
// Set source and wait for playback | ||
const player = await preparePlayerWithSource(source); | ||
spec.it('dispatches a seeked event after seeking', async function () { | ||
// Set source and wait for playback | ||
const player = await preparePlayerWithSource(testSource.source); | ||
|
||
// Seek | ||
const seekPromise = waitForPlayerEventType(player, PlayerEventType.SEEKED); | ||
const seekTime = 10e3; | ||
player.currentTime = seekTime; | ||
// Seek | ||
const seekPromise = waitForPlayerEventType(player, PlayerEventType.SEEKED); | ||
const seekTime = 10e3; | ||
player.currentTime = seekTime; | ||
|
||
// Wait for `seeked` event. | ||
await seekPromise; | ||
// Wait for `seeked` event. | ||
await seekPromise; | ||
|
||
// Expect currentTime to be updated. | ||
expect(player.currentTime).toBeSmallerThanOrEqual(seekTime + SEEK_THRESHOLD); | ||
}); | ||
// Expect currentTime to be updated. | ||
expect(player.currentTime).toBeSmallerThanOrEqual(seekTime + SEEK_THRESHOLD); | ||
}); | ||
|
||
spec.it('dispatches paused, play and playing events after pausing & resuming playback', async function () { | ||
// Set source and wait for playback | ||
const player = await preparePlayerWithSource(source); | ||
spec.it(`dispatches paused, play and playing events after pausing & resuming playback of the source`, async function () { | ||
// Set source and wait for playback | ||
const player = await preparePlayerWithSource(testSource.source); | ||
|
||
// Pause play-out. | ||
const pausePromise = waitForPlayerEventType(player, PlayerEventType.PAUSE); | ||
player.pause(); | ||
// Pause play-out. | ||
const pausePromise = waitForPlayerEventType(player, PlayerEventType.PAUSE); | ||
player.pause(); | ||
|
||
// Wait for 'paused' event. | ||
await pausePromise; | ||
// Wait for 'paused' event. | ||
await pausePromise; | ||
|
||
// Resume play-out. | ||
const playPromises = waitForPlayerEventTypes(player, [PlayerEventType.PLAY, PlayerEventType.PLAYING]); | ||
player.play(); | ||
// Resume play-out. | ||
const playPromises = waitForPlayerEventTypes(player, [PlayerEventType.PLAY, PlayerEventType.PLAYING]); | ||
player.play(); | ||
|
||
// Wait for 'play' and 'playing' events. | ||
await playPromises; | ||
// Wait for 'play' and 'playing' events. | ||
await playPromises; | ||
}); | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
export default function (spec: TestScope) { | ||
if (Platform.OS === 'android' || Platform.OS === 'web') { | ||
testBasicPlayout(spec, 'Set DASH source and auto-play', dash[0]); | ||
} | ||
testBasicPlayout(spec, 'Set HLS source and auto-play', hls[0]); | ||
testBasicPlayout(spec, 'Set mp4 source and auto-play', mp4[0]); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,66 @@ | ||
import { TestScope } from 'cavy'; | ||
import { PlayerEventType, PresentationMode, PresentationModeChangeEvent } from 'react-native-theoplayer'; | ||
import hls from '../res/hls.json'; | ||
import { expect, preparePlayerWithSource, waitForPlayerEvent } from '../utils/Actions'; | ||
import { PlayerEventType, PresentationMode, PresentationModeChangeEvent, RenderingTarget, THEOplayer } from 'react-native-theoplayer'; | ||
import { expect, preparePlayerWithSource, waitForPlayerEvent, waitForPlayerEventType } from '../utils/Actions'; | ||
import { sleep } from '../utils/TimeUtils'; | ||
import { Platform } from 'react-native'; | ||
import { TestSourceDescription, TestSources } from '../utils/SourceUtils'; | ||
|
||
export default function (spec: TestScope) { | ||
spec.describe('Switch between presentation modes', function () { | ||
spec.it('dispatches presentationmodechange events between inline and fullscreen.', async function () { | ||
const player = await preparePlayerWithSource(hls[0]); | ||
|
||
// Switch to fullscreen. | ||
const fullscreenPromise = waitForPlayerEvent(player, { | ||
type: PlayerEventType.PRESENTATIONMODE_CHANGE, | ||
presentationMode: PresentationMode.fullscreen, | ||
previousPresentationMode: PresentationMode.inline, | ||
} as PresentationModeChangeEvent); | ||
player.presentationMode = PresentationMode.fullscreen; | ||
|
||
// Wait for 'presentationmodechange' event. | ||
await fullscreenPromise; | ||
|
||
// Play-out should not pause. | ||
await sleep(500); | ||
expect(player.paused).toBeFalsy(); | ||
|
||
// Switch back to inline. | ||
const inlinePromise = waitForPlayerEvent(player, { | ||
type: PlayerEventType.PRESENTATIONMODE_CHANGE, | ||
presentationMode: PresentationMode.inline, | ||
previousPresentationMode: PresentationMode.inline, | ||
} as PresentationModeChangeEvent); | ||
player.presentationMode = PresentationMode.inline; | ||
|
||
// Wait for 'presentationmodechange' event. | ||
await inlinePromise; | ||
|
||
// Play-out should not pause. | ||
expect(player.paused).toBeFalsy(); | ||
TestSources() | ||
.withPlain() | ||
.withAds() | ||
.forEach((testSource: TestSourceDescription) => { | ||
spec.describe(`Switch between presentation modes during play-out of a ${testSource.description}`, function () { | ||
spec.it('dispatches presentationmodechange events between inline and fullscreen.', async function () { | ||
const player = await preparePlayerWithSource(testSource.source); | ||
|
||
// Switch to fullscreen. | ||
const fullscreenPromise = waitForPlayerEvent(player, { | ||
type: PlayerEventType.PRESENTATIONMODE_CHANGE, | ||
presentationMode: PresentationMode.fullscreen, | ||
previousPresentationMode: PresentationMode.inline, | ||
} as PresentationModeChangeEvent); | ||
player.presentationMode = PresentationMode.fullscreen; | ||
|
||
// Wait for 'presentationmodechange' event. | ||
await fullscreenPromise; | ||
|
||
// Play-out should not pause. | ||
await sleep(500); | ||
expect(player.paused).toBeFalsy(); | ||
|
||
// Switch back to inline. | ||
const inlinePromise = waitForPlayerEvent(player, { | ||
type: PlayerEventType.PRESENTATIONMODE_CHANGE, | ||
presentationMode: PresentationMode.inline, | ||
previousPresentationMode: PresentationMode.inline, | ||
} as PresentationModeChangeEvent); | ||
player.presentationMode = PresentationMode.inline; | ||
|
||
// Wait for 'presentationmodechange' event. | ||
await inlinePromise; | ||
|
||
// Play-out should not pause. | ||
expect(player.paused).toBeFalsy(); | ||
}); | ||
}); | ||
|
||
if (Platform.OS === 'android') { | ||
spec.describe(`Switch between rendering targets during play-out of a ${testSource.description}`, function () { | ||
spec.it('continues play-out.', async function () { | ||
const player = await preparePlayerWithSource(testSource.source); | ||
|
||
await switchRenderingTarget(player, RenderingTarget.TEXTURE_VIEW); | ||
await switchRenderingTarget(player, RenderingTarget.SURFACE_VIEW); | ||
}); | ||
}); | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
async function switchRenderingTarget(player: THEOplayer, renderingTarget: RenderingTarget, sleepTime: number = 500) { | ||
console.debug(`Switching to ${renderingTarget}`); | ||
await sleep(sleepTime); | ||
player.renderingTarget = renderingTarget; | ||
await waitForPlayerEventType(player, PlayerEventType.TIME_UPDATE); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { AdDescription, SourceDescription } from 'react-native-theoplayer'; | ||
import dash from '../res/dash.json'; | ||
import hls from '../res/hls.json'; | ||
import mp4 from '../res/mp4.json'; | ||
import ads from '../res/ads.json'; | ||
import { Platform } from 'react-native'; | ||
|
||
export enum SourceType { | ||
DASH, | ||
HLS, | ||
MP4, | ||
} | ||
|
||
export enum AdType { | ||
IMA_PRE_ROLL, | ||
} | ||
|
||
export interface TestSourceDescription { | ||
source: SourceDescription; | ||
description: string; | ||
} | ||
|
||
type EnhancedSourceList = TestSourceDescription[] & SourceListMethods; | ||
|
||
interface SourceListMethods { | ||
withPlain: () => EnhancedSourceList; | ||
withAds: () => EnhancedSourceList; | ||
} | ||
|
||
export function TestSources(): EnhancedSourceList { | ||
const testSources: TestSourceDescription[] = []; | ||
|
||
return Object.assign(testSources, { | ||
withPlain() { | ||
if (Platform.OS === 'android' || Platform.OS === 'web') { | ||
testSources.push(getTestSource(SourceType.DASH)); | ||
} | ||
testSources.push(getTestSource(SourceType.HLS)); | ||
testSources.push(getTestSource(SourceType.MP4)); | ||
return testSources as EnhancedSourceList; | ||
}, | ||
withAds() { | ||
if (Platform.OS === 'android' || Platform.OS === 'web') { | ||
testSources.push(getTestSource(SourceType.DASH, AdType.IMA_PRE_ROLL)); | ||
} | ||
testSources.push(getTestSource(SourceType.HLS, AdType.IMA_PRE_ROLL)); | ||
testSources.push(getTestSource(SourceType.MP4, AdType.IMA_PRE_ROLL)); | ||
return testSources as EnhancedSourceList; | ||
}, | ||
}); | ||
} | ||
|
||
export function getTestSource(sourceType: SourceType, adType?: AdType): TestSourceDescription { | ||
let source: SourceDescription; | ||
let description: string; | ||
switch (sourceType) { | ||
case SourceType.DASH: | ||
source = dash[0]; | ||
description = 'DASH'; | ||
break; | ||
case SourceType.HLS: | ||
source = hls[0]; | ||
description = 'HLS'; | ||
break; | ||
case SourceType.MP4: | ||
source = mp4[0]; | ||
description = 'mp4'; | ||
break; | ||
} | ||
switch (adType) { | ||
case AdType.IMA_PRE_ROLL: | ||
source = extendSourceWithAds(source, ads[0] as AdDescription); | ||
description += ' with IMA pre-roll'; | ||
break; | ||
} | ||
return { | ||
source, | ||
description, | ||
}; | ||
} | ||
|
||
function extendSourceWithAds(source: SourceDescription, ad: AdDescription): SourceDescription { | ||
return { ...source, ads: [ad] }; | ||
} |