> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qawolf.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Camera injection

> Inject images into your app's camera input to test camera features without real hardware.

<Info>
  Camera injection is only available for apps that QA Wolf resigns during installation. It is not available for system apps or Safari.
</Info>

## Example

**Inject an image into the camera feed:**

```javascript theme={null}
import { device } from "@qawolf/flows/ios";

const bundleId = process.env.BUNDLE_ID; // Bundle ID of app being tested
const storagePath = process.env.STORAGE_PATH; // QA Wolf remote storage
const imagePath = `${storagePath}/large.jpg`;

const cleanup = await device.injectCamera(driver, bundleId, {
  data: imagePath,
  type: "image", // optional — inferred from .jpg/.png/etc.
});

// ... run your assertions while the camera feed is mocked ...
await cleanup();
```

Once the config is pushed, the camera preview updates to the injected image and loops continuously.

## When to use

* Your app captures photos or displays a camera preview and you want to test that flow without a physical camera setup.
* You need to run the same scenario repeatedly with consistent inputs.

## Supported file types

**Images:** Any format supported by UIImage — JPG, PNG, HEIC, GIF, BMP, TIFF, WebP

## Full sample test

```js theme={null}
import { flow, device, expect } from "@qawolf/flows/ios";

export default flow(
  "iOS Media - Camera Photo Injection",
  {
    target: "iOS - iPhone 15 (iOS 26)",
    launch: {
      app: { env: "IOS_APP_STAGING" },
      respectSystemAlerts: true,
      autoAcceptAlerts: true,
    },
  },
  async ({ driver, test }) => {
    await test("iOS Media - Camera Photo Injection", async () => {
      //--------------------------------
      // Arrange:
      //--------------------------------
      // Install and Launch Trot app
      const imageName = "large.jpg";
      const baseDir = process.env.BASE_IMAGE_DIR
      const imagePath = `${baseDir}/${imageName}`;
      // Tap "Media"
      await driver
        .$(
          `-ios predicate string:name == 'Media' AND type == 'XCUIElementTypeButton'`,
        )
        .waitForDisplayed();
      await driver
        .$(
          `-ios predicate string:name == 'Media' AND type == 'XCUIElementTypeButton'`,
        )
        .click();

      // Tap Video Recording
      await driver
        .$(
          `-ios predicate string:name == 'Video Recording' AND type == 'XCUIElementTypeButton'`,
        )
        .waitForDisplayed();
      await driver
        .$(
          `-ios predicate string:name == 'Video Recording' AND type == 'XCUIElementTypeButton'`,
        )
        .click();

      // Tap AVCaptureMovieFileOutput
      await driver
        .$(
          `-ios predicate string:name == 'AVCaptureMovieFileOutput' AND type == 'XCUIElementTypeButton'`,
        )
        .waitForDisplayed();
      await driver
        .$(
          `-ios predicate string:name == 'AVCaptureMovieFileOutput' AND type == 'XCUIElementTypeButton'`,
        )
        .click();

      // Observe "Start Recording" button
      await driver
        .$(
          `-ios predicate string:name == 'Start Recording' AND type == 'XCUIElementTypeStaticText'`,
        )
        .waitForDisplayed({ timeout: 10000 });

      //--------------------------------
      // Act:
      //--------------------------------
      // Inject image as the camera feed
      await device.injectCamera(driver, process.env.APP_ID, {
        data: `${imagePath}`,
        type: "image",
      });
      await driver.pause(3000);

      //--------------------------------
      // Assert:
      //--------------------------------
      // Assert Screenshot of Image File Displaying in Live Preview
      const previewElement = driver.$(
        `-ios predicate string:name == 'livePreview' AND type == 'XCUIElementTypeOther'`,
      );
      await previewElement.waitForDisplayed({ timeout: 5000 });
      await expect(driver)
        .toHaveScreenshot(
          previewElement,
          "video_recording_image_preview",
          { maxMisMatchPercentage: 5 },
        );
    });
  },
);
```
