Camera injection is only available for apps that QA Wolf resigns during installation. It is not available for system apps or Safari.
Example
Inject an image into the camera feed:
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
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 },
);
});
},
);