Skip to content

Generating Reports

Tyler Thompson edited this page Jun 2, 2021 · 1 revision

Automatic Reports

Reports are an important part of what Cucumber does, it allows us to see the specification in Gherkin executed. CucumberSwift has a JSON reporter that writes in real-time while your code is executing. Unfortunately because the simulator is sandboxed it can be a tad tricky to get at that report.

To help you get started here's a script you can add as a post-action after running your tests in your Xcode scheme. It uses some XCode build variables to find the device you ran on, and get the Cucumber json file from it. This particular command can also pull reports off a physical device using the ios-deploy utility.

#!/bin/bash -x
# set -x
# exec > /tmp/my_log_file.txt 2>&1
rm -f $SRCROOT/CucumberReports/ERROR.txt
mkdir -p $SRCROOT/CucumberReports
if [ "$TARGET_DEVICE_PLATFORM_NAME" == "iphonesimulator" ]; then
    find ~/Library/Developer/CoreSimulator/Devices/$TARGET_DEVICE_IDENTIFIER -name "CucumberTestResultsFor$TARGETNAME.json" -print0 | xargs -r -0 ls -1 -t | head -1 | xargs -I '{}' mv '{}' $SRCROOT/CucumberReports
elif [ -x "$(command -v ios-deploy)" ]; then
    ios-deploy --download=/Documents --bundle_id $PRODUCT_BUNDLE_IDENTIFIER.xctrunner --to "$SRCROOT/CucumberReports"
    cp "$SRCROOT/CucumberReports/Documents/CucumberTestResultsFor$TARGETNAME.json" "$SRCROOT/CucumberReports/CucumberTestResultsFor$TARGETNAME.json"
    rm -rf "$SRCROOT/CucumberReports/Documents/"
else
    echo "error: Unable to download CucumberSwift report from actual device, you need the ios-deploy tool installed! Install with 'brew install ios-deploy'" > $SRCROOT/CucumberReports/ERROR.txt
    exit 1
fi

Custom Reporters

If you'd like to be notified about what the Cucumber runner saw during execution there are 2 steps needed.

The Test Observer

Start by creating a test observer, something like this:

class MyTestObserver: CucumberTestObserver {
    func testSuiteStarted(at date: Date) { }

    func testSuiteFinished(at date: Date) { }

    func didStart(feature: Feature, at date: Date) { }

    func didStart(scenario: Scenario, at date: Date) { }

    func didStart(step: Step, at date: Date) { }

    func didFinish(feature: Feature, result: Reporter.Result, duration: Measurement<UnitDuration>) { }

    func didFinish(scenario: Scenario, result: Reporter.Result, duration: Measurement<UnitDuration>) { }

    func didFinish(step: Step, result: Reporter.Result, duration: Measurement<UnitDuration>) { }
}

Note the duration is a Measurement type, by default its value is in nanoseconds but you can convert that to whatever makes sense, like this:

duration.converted(to: .seconds).value // value in seconds

Next you'll want to add your reporter to a list of reporters Cucumber knows about by extending it, like this:

extension Cucumber: CucumberTestObservable {
    public var observers: [CucumberTestObserver] {
        [ MyTestObserver() ]
    }
}