Skip to content

Commit

Permalink
Merge pull request #337 from bitmovin/player-testing/add-more-documen…
Browse files Browse the repository at this point in the history
…tation

Extend documentation for integration tests
  • Loading branch information
rolandkakonyi authored Dec 13, 2023
2 parents 7ed5dbc + a416968 commit 812abf9
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 65 deletions.
7 changes: 7 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ yarn integration-test test:ios

See available API for testing [here](/integration_test/playertesting/PlayerTesting.ts).

### Adding new tests

To add new tests:

1. create a new file in the `specs/` folder.
1. import the new file to the `specs/index.ts` file and add it to the default exported array.

A Player Test has the following structure always:

```ts
Expand Down
82 changes: 17 additions & 65 deletions integration_test/README.md
Original file line number Diff line number Diff line change
@@ -1,79 +1,31 @@
This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli).
# Integration Tests

# Getting Started
This is the integration test suite for the Bitmovin Player React Native SDK. It is based on [Cavy](https://github.com/pixielabs/cavy).
This is intended for maintainers to test the SDK on different platforms and devices.

> **Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding.
## Setup

## Step 1: Start the Metro Server
To run the integration tests, you need to install depencencies first.

First, you will need to start **Metro**, the JavaScript _bundler_ that ships _with_ React Native.
Run the following command from the repository root:

To start Metro, run the following command from the _root_ of your React Native project:

```bash
# using npm
npm start

# OR using Yarn
yarn start
```sh
yarn bootstrap
```

## Step 2: Start your Application

Let Metro Bundler run in its _own_ terminal. Open a _new_ terminal from the _root_ of your React Native project. Run the following command to start your _Android_ or _iOS_ app:
## Running the tests

### For Android
To run the tests, run the following command from the repository root:

```bash
# using npm
npm run android

# OR using Yarn
yarn android
```sh
yarn integration-test test:ios # Run tests on iOS
yarn integration-test test:android # Run tests on Android
```

### For iOS

```bash
# using npm
npm run ios
Hint: You can provide a specific iOS simulator by name when using `--simulator` flag. `xcrun simctl list devices available` provides you with a list of available devices in your environment.

# OR using Yarn
yarn ios
```sh
yarn example ios --simulator="iPhone 14 Pro"
```

If everything is set up _correctly_, you should see your new app running in your _Android Emulator_ or _iOS Simulator_ shortly provided you have set up your emulator/simulator correctly.

This is one way to run your app — you can also run it directly from within Android Studio and Xcode respectively.

## Step 3: Modifying your App

Now that you have successfully run the app, let's modify it.

1. Open `App.tsx` in your text editor of choice and edit some lines.
2. For **Android**: Press the <kbd>R</kbd> key twice or select **"Reload"** from the **Developer Menu** (<kbd>Ctrl</kbd> + <kbd>M</kbd> (on Window and Linux) or <kbd>Cmd ⌘</kbd> + <kbd>M</kbd> (on macOS)) to see your changes!

For **iOS**: Hit <kbd>Cmd ⌘</kbd> + <kbd>R</kbd> in your iOS Simulator to reload the app and see your changes!

## Congratulations! :tada:

You've successfully run and modified your React Native App. :partying_face:

### Now what?

- If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps).
- If you're curious to learn more about React Native, check out the [Introduction to React Native](https://reactnative.dev/docs/getting-started).

# Troubleshooting

If you can't get this to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page.

# Learn More

To learn more about React Native, take a look at the following resources:

- [React Native Website](https://reactnative.dev) - learn more about React Native.
- [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment.
- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**.
- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts.
- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native.
Note: The tests are currently only supported on iOS simulators and Android emulators. Running them on real devices is not supported at the moment.
145 changes: 145 additions & 0 deletions integration_test/playertesting/PlayerTesting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,60 @@ import {
MultipleEventsExpectation,
} from './expectations';

/**
* Starts a player test with the given configuration and test function.
* @param config The player configuration to use for the test. Pass `{}` to use the default configuration.
* @param fn The test function to run.
* @returns A promise that resolves when the test is finished.
* @throws An error if the test fails.
* @example
* ```typescript
* await startPlayerTest({}, async () => {
* // ...
* });
* ```
* @see {@link PlayerConfig}
*/
export const startPlayerTest = async (
config: PlayerConfig,
fn: () => Promise<void>
): Promise<void> => {
return await PlayerTestWorld.shared.startPlayerTest(config, fn);
};

/**
* Calls the given function with the player instance.
* @param fn The function to call.
* @returns A promise that resolves when the function is finished.
* @example
* ```typescript
* await callPlayer(async (player) => {
* // ...
* });
* ```
* @see {@link Player}
*/
export const callPlayer = async <T>(
fn: (player: Player) => Promise<T>
): Promise<T> => {
return await PlayerTestWorld.shared.callPlayer(fn);
};

/**
* Expects the given event to occur.
* @param expectationConvertible The event to expect.
* @param timeoutSeconds The number of seconds to wait for the event to occur.
* @returns A promise that resolves when the function is finished.
* @throws An error if the event does not occur.
* @example
* ```typescript
* await callPlayerAndExpectEvent(async (player) => {
* // ...
* }, EventType.Play);
* ```
* @see {@link Player}
* @see {@link EventType}
*/
export const expectEvent = async <T extends Event>(
expectationConvertible: SingleEventExpectation | EventType,
timeoutSeconds: number = 10
Expand All @@ -36,6 +77,27 @@ export const expectEvent = async <T extends Event>(
);
};

/**
* Expects the given events to occur.
* @param expectationsConvertible The events to expect.
* @param timeoutSeconds The number of seconds to wait for the events to occur.
* @returns A promise that resolves when the function is finished.
* @throws An error if the events do not occur.
* @example
* ```typescript
* await callPlayerAndExpectEvents(async (player) => {
* // ...
* }, [EventType.Play, EventType.Playing]);
* ```
*
* ```typescript
* await callPlayerAndExpectEvents(async (player) => {
* // ...
* }, EventSequence(EventType.Play, EventType.Playing));
* ```
* @see {@link Player}
* @see {@link EventType}
*/
export const expectEvents = async (
expectationsConvertible: MultipleEventsExpectation | EventType[],
timeoutSeconds: number = 10
Expand All @@ -46,6 +108,24 @@ export const expectEvents = async (
);
};

/**
* Starts listening for the specified `SingleEventExpectation` before executing the passed `fn` function.
* This is the race-condition-safe version of calling `callPlayer` and `expectEvent` after that.
* Useful when events are directly tied to calls in the `fn` function block and therefore synchronously emitted.
* @param fn The function to call.
* @param expectationConvertible The event to expect.
* @param timeoutSeconds The number of seconds to wait for the event to occur.
* @returns A promise that resolves when the function is finished.
* @throws An error if the event does not occur.
* @example
* ```typescript
* await callPlayerAndExpectEvent(async (player) => {
* // ...
* }, EventType.Play);
* ```
* @see {@link Player}
* @see {@link EventType}
*/
export const callPlayerAndExpectEvent = async <E extends Event, P>(
fn: (player: Player) => Promise<P>,
expectationConvertible: SingleEventExpectation | EventType,
Expand All @@ -58,6 +138,30 @@ export const callPlayerAndExpectEvent = async <E extends Event, P>(
);
};

/**
* Starts listening for the specified `MultipleEventExpectation` before executing the passed `fn` function.
* This is the race-condition-safe version of calling `callPlayer` and `expectEvents` after that.
* Useful when events are directly tied to calls in the `fn` function block and therefore synchronously emitted.
* @param fn The function to call.
* @param expectationsConvertible The events to expect.
* @param timeoutSeconds The number of seconds to wait for the events to occur.
* @returns A promise that resolves when the function is finished.
* @throws An error if the events do not occur.
* @example
* ```typescript
* await callPlayerAndExpectEvents(async (player) => {
* // ...
* }, [EventType.Play, EventType.Playing]);
* ```
*
* ```typescript
* await callPlayerAndExpectEvents(async (player) => {
* // ...
* }, EventSequence(EventType.Play, EventType.Playing));
* ```
* @see {@link Player}
* @see {@link EventType}
*/
export const callPlayerAndExpectEvents = async (
fn: (player: Player) => void,
expectationsConvertible: MultipleEventsExpectation | EventType[],
Expand All @@ -70,6 +174,23 @@ export const callPlayerAndExpectEvents = async (
);
};

/**
* Loads the given source configuration and expects `ReadyEvent` to occur.
* @param sourceConfig The source configuration to load.
* @param timeoutSeconds The number of seconds to wait for the event to occur.
* @returns A promise that resolves when the function is finished.
* @throws An error if the event does not occur.
* @example
* ```typescript
* await loadSourceConfig({
* url: 'https://bitmovin-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8',
* type: SourceType.HLS,
* });
* ```
* @see {@link SourceConfig}
* @see {@link EventType}
* @see {@link ReadyEvent}
*/
export const loadSourceConfig = async (
sourceConfig: SourceConfig,
timeoutSeconds: number = 10
Expand All @@ -80,13 +201,37 @@ export const loadSourceConfig = async (
);
};

/**
* Plays the player for the given time and expects `TimeChangedEvent` to occur.
* @param time The time to play for.
* @param timeoutSeconds The number of seconds to wait for the event to occur.
* @returns A promise that resolves when the function is finished.
* @throws An error if the event does not occur.
* @example
* ```typescript
* await playFor(5);
* ```
* @see {@link TimeChangedEvent}
*/
export const playFor = async (
time: number,
timeoutSeconds: number = 10
): Promise<TimeChangedEvent> => {
return await PlayerTestWorld.shared.playFor(time, timeoutSeconds);
};

/**
* Plays the player until the given time and expects `TimeChangedEvent` to occur.
* @param time The time to play until.
* @param timeoutSeconds The number of seconds to wait for the event to occur.
* @returns A promise that resolves when the function is finished.
* @throws An error if the event does not occur.
* @example
* ```typescript
* await playUntil(5);
* ```
* @see {@link TimeChangedEvent}
*/
export const playUntil = async (
time: number,
timeoutSeconds: number = 10
Expand Down

0 comments on commit 812abf9

Please sign in to comment.