### Provide Examples for a Scenario Outline Source: https://github.com/ahmed-ali/cucumberish/wiki/Scenario Provide data for a Scenario Outline using an Examples table directly following the outline. Each row represents a separate execution of the scenario. ```Gherkin Examples: | FriendName | FriendEmail | | Friend 1 | Email 1 | | Friend 2 | Email 2 | | Friend 3 | Email 3 | ``` -------------------------------- ### Complete Scenario Outline with Examples Source: https://github.com/ahmed-ali/cucumberish/wiki/Scenario Combine a Scenario Outline with its corresponding Examples table to create a fully defined parameterized test. The examples must immediately follow the outline. ```Gherkin Scenario Outline: Invite a friend Given I am logged in as "Ahmed" And I am on "home" screen When I tap "invite" button Then I write "" into the "Email" field And I write "" into the "Name" field And I tap "Invite Friend" button Then I should see " Invited" message Examples: | FriendName | FriendEmail | | Friend 1 | Email 1 | | Friend 2 | Email 2 | | Friend 3 | Email 3 | ``` -------------------------------- ### Define Before Start Hook Source: https://github.com/ahmed-ali/cucumberish/wiki/Hooks Executes once before any scenario runs. ```Objectiev-C beforeStart(^{ //Code that runs only once before running any scenario }); ``` -------------------------------- ### Implement a parameterized step Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Example of a step definition using regex patterns for arguments. ```Objective-C When(@"I write \"(.*)\" into the \"(.*)\" field", ^void(NSArray *args, id userInfo) { //Implementation body goes here }); ``` -------------------------------- ### Implement 'Given' Step Definition (Text Matching) Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Implement a 'Given' step definition using simple text matching for preconditions. This example verifies a login state by tapping a 'Login' button and asserting the 'Logout' button's existence. ```Objective-C // Simple text matching Given(@"the user is logged in", ^(NSArray *args, NSDictionary *userInfo) { XCUIApplication *app = [[XCUIApplication alloc] init]; [app.buttons[@"Login"] tap]; XCTAssertTrue(app.buttons[@"Logout"].exists); }); ``` -------------------------------- ### Implement 'When' Step Definition (Flexible Regex) Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Implement a 'When' step definition using flexible regular expressions to match multiple sentence variations for user actions. This example handles tapping various UI elements like buttons, views, or labels. ```Objective-C // Flexible regex matching multiple sentence variations When(@"^I tap (?:the )?\"([^"]*)\" (?:button|view|label)$", ^(NSArray *args, NSDictionary *userInfo) { NSString *elementName = args[0]; XCUIApplication *app = [[XCUIApplication alloc] init]; // Try button first, then other element types XCUIElement *element = app.buttons[elementName]; if (!element.exists) { element = app.staticTexts[elementName]; } [element tap]; }); // Matches: "When I tap the "Submit" button", "When I tap "Header" view", etc. ``` -------------------------------- ### Registering a beforeTagged hook Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Runs setup logic specifically for scenarios tagged with the provided identifiers. ```objective-c // Run setup only for scenarios tagged with @login or @authentication beforeTagged(@[@"login", @"authentication"], ^(CCIScenarioDefinition *scenario) { NSLog(@"Setting up authentication test: %@", scenario.name); // Clear keychain before auth tests [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"authToken"]; [[NSUserDefaults standardUserDefaults] synchronize]; }); ``` -------------------------------- ### Registering an around hook Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Wraps the execution of all scenarios to perform setup and teardown or timing logic. ```objective-c around(^(CCIScenarioDefinition *scenario, void(^executeScenario)(void)) { NSLog(@"Before scenario execution"); NSDate *startTime = [NSDate date]; // Execute the scenario executeScenario(); NSTimeInterval duration = [[NSDate date] timeIntervalSinceDate:startTime]; NSLog(@"Scenario '%@' took %.2f seconds", scenario.name, duration); }); ``` -------------------------------- ### Define Login Step Implementations Source: https://github.com/ahmed-ali/cucumberish/blob/master/INSTRUCTIONS.md Implement Gherkin steps in Swift, matching them with regular expressions. This example shows how to define 'Given', 'When', and 'Then' steps for login functionality. ```swift import Foundation import Cucumberish class LoginSteps: LoginScreen { func LoginStepsImplementation() { Given("I'm a new user that is registering for the first time") { args, dataTable in // call your unit test implementations XCTAssertTrue(...) } When("the user submits the registration form with the following details") { args, dataTable in // call your unit test implementations XCTAssertTrue(...) } Then("the user is successfully registered") { args, dataTable in // call your unit test implementations XCTAssertTrue(...) } ``` -------------------------------- ### Execute Features with Convenience Method Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Use the `executeFeatures` convenience method for a concise way to parse and execute all features within a specified directory. This is useful for quick setup in Swift files. ```Swift // Swift setup in CucumberishInitializer.swift import Foundation import Cucumberish @objc public class CucumberishInitializer: NSObject { @objc public class func CucumberishSwiftInit() { // Define step implementations before execution Given("the app is running") { args, userInfo in let app = XCUIApplication() app.launch() } let bundle = Bundle(for: CucumberishInitializer.self) Cucumberish.executeFeatures(inDirectory: "Features", from: bundle, includeTags: nil, excludeTags: ["skip"]) } } ``` -------------------------------- ### Define a Gherkin Feature and Scenario Source: https://github.com/ahmed-ali/cucumberish/wiki/Gherkin Example of a feature file structure including a scenario with various step definitions. ```Gherkin Feature: Profile As a user I want to be able to create profile and update my details Scenario: Create profile Given it is home screen When I tap the "Profile" button And I write "example@example.com" into the "Email" field Then I write "Ahmed Ali" into the "Name" field And I set the "Birthdate" picker date to "25-12-1990" And I tap "Save Profile" button Then I should see the text "Ahmed Ali" in the "Header" view ``` -------------------------------- ### Implement 'Given' Step Definition (Regex with Capture) Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Implement a 'Given' step definition using regular expressions to capture arguments from the Gherkin step. This example captures a username and an item count for setting up test state. ```Objective-C // Regex matching with captured arguments Given(@"^the user \"([^"]*)\" has (\\d+) items in cart$", ^(NSArray *args, NSDictionary *userInfo) { NSString *username = args[0]; // Captured from first group NSInteger itemCount = [args[1] integerValue]; // Captured from second group // Setup test state NSLog(@"Setting up %@ with %ld items", username, (long)itemCount); }); ``` -------------------------------- ### Swift Cucumberish Initializer Source: https://github.com/ahmed-ali/cucumberish/blob/master/INSTRUCTIONS.md Set up the main initializer in Swift to define test hooks, instantiate your step definition classes, and execute Cucumberish features. This file orchestrates the test setup. ```swift import Foundation import Cucumberish @objc public class CucumberishInitializer: NSObject { @objc public class func CucumberishSwiftInit() { var application: XCUIApplication! beforeStart { application = XCUIApplication() LoginSteps().LoginStepsImplementation() SignUpSteps().SignUpStepsImplementation() CommonStepDefinitions().CommonStepDefinitionsImplementation() } let bundle = Bundle(for: CucumberishInitializer.self) Cucumberish.executeFeatures(inDirectory: "Features", from: bundle, includeTags: nil, excludeTags: nil) } } ``` -------------------------------- ### Define a Gherkin step Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Example of a Gherkin step that matches the simple string implementation. ```Gherkin Give the app is running ``` -------------------------------- ### Defining Scenario Outlines in Gherkin Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Use Scenario Outline and Examples tables to run the same test logic with multiple sets of input data. ```gherkin # login.feature @authentication Feature: User Login As a registered user I want to login to my account So that I can access my personalized content Background: Given the app is running And the login screen is displayed @smoke Scenario Outline: Successful login with valid credentials When I enter "" into the "Email" field And I enter "" into the "Password" field And I tap the "Login" button Then I should see "Welcome, " message And I should be on the "Home" screen Examples: | email | password | name | | admin@test.com | admin123 | Admin | | user@test.com | user456 | User | @negative Scenario: Login with invalid credentials When I enter "invalid@test.com" into the "Email" field And I enter "wrongpassword" into the "Password" field And I tap the "Login" button Then I should see "Invalid credentials" message But I should not see the "Home" screen ``` -------------------------------- ### Data Table Structure Example Source: https://github.com/ahmed-ali/cucumberish/wiki/Data-Tables The structure of the rows array provided to the step definition. ```JSON [ ["name", "email"], ["ahmed", "ahmed@cucumberish.com"], ["maikel", "maikel@cucumberish.com"] ] ``` -------------------------------- ### Define a Feature in Cucumberish Source: https://github.com/ahmed-ali/cucumberish/wiki/Feature Example of a .feature file structure including a background, scenario outline with examples, and a standard scenario. ```gherkin @booking Feature: Booking As I user I want to be able to book one or more ticket and manage my bookings Background: Given there are tickets available And user is logged in as "Ahmed" Then I added EUR 50 into my balance @create Scenario Outline: Book a ticket Given it is the tickets screen When I tap "Book" button Then I enter into the "Amount" Field And I tap "Add" button Examples: | NumberOfTikets | | 2 | | 1 | | 1 | @delete Scenario: Delete an order of tickets Given it is the tickets screen When I tap "My Bookings" button And I tap "Delete" button in row 0 in the "Bookings" table And I confirm the "Delete" action Then the "Bookings" table should have 2 rows ``` -------------------------------- ### Install Cucumberish with CocoaPods Source: https://github.com/ahmed-ali/cucumberish/wiki/Home Add this to your Podfile to include Cucumberish in your project. Ensure 'use_frameworks!' is present for Swift projects. ```Ruby use_frameworks! target 'YourAppTestTarget' do pod 'Cucumberish' end ``` -------------------------------- ### Register beforeStart Hook Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Executes code once before any scenarios begin. ```objective-c beforeStart(^{ // Global initialization - runs only once before all tests XCUIApplication *app = [[XCUIApplication alloc] init]; app.launchArguments = @[@"--uitesting", @"--reset-state"]; [app launch]; NSLog(@"Test suite starting..."); }); ``` -------------------------------- ### Use MatchAll for multiple prepositions Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Matches the definition against When, Then, And, and But steps. ```Objective-C MatchAll(@"I write \"(.*)\" into the \"(.*)\" field", ^void(NSArray *args, id userInfo) { //Implementation body goes here //And this implementation will be invoked with any of the following steps //When I write "blah blah" into the "Fancy" field //Then I write "blah blah" into the "Fancy" field //And I write "blah blah" into the "Fancy" field //But I write "blah blah" into the "Fancy" field }); ``` -------------------------------- ### Handling Doc Strings in steps Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Accesses multiline text content from feature files using the kDocStringKey. ```gherkin # Feature file example Then I should see the following error message: """ Your session has expired. Please login again to continue. """ ``` ```objective-c Then(@"I should see the following error message", ^(NSArray *args, NSDictionary *userInfo) { NSString *expectedMessage = userInfo[kDocStringKey]; XCUIApplication *app = [[XCUIApplication alloc] init]; XCUIElement *errorLabel = app.staticTexts[@"errorMessage"]; CCIAssert([errorLabel.label containsString:expectedMessage], @"Expected error message not found. Got: %@", errorLabel.label); }); ``` -------------------------------- ### Define standard step functions Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Use these functions to define steps that match specific prepositions. ```Objective-C void Given(NSString * definitionString, CCIStepBody body); void When(NSString * definitionString, CCIStepBody body); void Then(NSString * definitionString, CCIStepBody body); void And(NSString * definitionString, CCIStepBody body); void But(NSString * definitionString, CCIStepBody body); ``` -------------------------------- ### Define Before Hook Source: https://github.com/ahmed-ali/cucumberish/wiki/Hooks Executes before each scenario in FIFO order. ```Objective-C before(^(CCIScenarioDefinition *scenario) { //Code that runs before each scenario }); ``` -------------------------------- ### Initialize Cucumberish in Objective-C Source: https://github.com/ahmed-ali/cucumberish/wiki/Install-manually-for-Swift Create an Objective-C file to trigger the Swift initialization method. ```Objective-C //Replace CucumberishExampleUITests with the name of your swift test target #import "CucumberishExampleUITests-Swift.h" __attribute__((constructor)) void CucumberishInit() { [CucumberishInitializer CucumberishSwiftInit]; } ``` -------------------------------- ### Register MatchAll Step Implementation Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Registers a single implementation that triggers for When, Then, And, and But prepositions. ```objective-c // Single implementation matching multiple prepositions MatchAll(@"^I (?:wait|pause) for (\\d+) seconds?$", ^(NSArray *args, NSDictionary *userInfo) { NSInteger seconds = [args[0] integerValue]; [NSThread sleepForTimeInterval:seconds]; }); // Matches all of these: // When I wait for 5 seconds // Then I pause for 1 second // And I wait for 3 seconds // But I pause for 2 seconds ``` -------------------------------- ### Define Then Step Implementations Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Use Then to verify expected outcomes. Access the XCTestCase via userInfo for advanced XCTest assertions. ```objective-c Then(@"^I should see \"([^\"]*)\" (?:message|text|label)$", ^(NSArray *args, NSDictionary *userInfo) { NSString *expectedText = args[0]; XCUIApplication *app = [[XCUIApplication alloc] init]; XCUIElement *label = app.staticTexts[expectedText]; CCIAssert(label.exists, @"Expected to find text: %@", expectedText); }); // Access XCTestCase for additional assertions Then(@"^the screen title should be \"([^\"]*)\"$", ^(NSArray *args, NSDictionary *userInfo) { XCTestCase *testCase = userInfo[kXCTestCaseKey]; XCUIApplication *app = [[XCUIApplication alloc] init]; XCUIElement *title = app.navigationBars.staticTexts[args[0]]; [testCase expectationForPredicate:[NSPredicate predicateWithFormat:@"exists == YES"] evaluatedWithObject:title handler:nil]; [testCase waitForExpectationsWithTimeout:5 handler:nil]; }); ``` -------------------------------- ### Step Definitions Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Methods for defining Given and When steps using string or regex matching to implement test logic. ```APIDOC ## Given ### Description Defines implementation for Given steps that establish preconditions or initial state. ### Parameters - **pattern** (NSString) - Required - The string or regex pattern to match. - **block** (Block) - Required - The implementation block receiving arguments and userInfo. ## When ### Description Defines implementation for When steps that describe actions or events. ### Parameters - **pattern** (NSString) - Required - The string or regex pattern to match. - **block** (Block) - Required - The implementation block receiving arguments and userInfo. ``` -------------------------------- ### Define After Hook Source: https://github.com/ahmed-ali/cucumberish/wiki/Hooks Executes after each scenario in LIFO order. ```Objective-C after(^(CCIScenarioDefinition *scenario) { //Code that runs after each scenario //You can now check the scenario's success and failureReason properties }); ``` -------------------------------- ### Define flexible matching functions Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Functions for matching steps across multiple prepositions. ```Objective-C void MatchAll(NSString * definitionString, CCIStepBody body); void Match(NSArray *prepositions, NSString * definitionString, CCIStepBody body); ``` -------------------------------- ### Use Match for specific prepositions Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Matches the definition against a provided array of prepositions. ```Objective-C Match(@[@"Given", @"When"], @"I write \"(.*)\" into the \"(.*)\" field", ^void(NSArray *args, id userInfo) { //Implementation body goes here //And this implementation will be invoked with any of the following steps //When I write "blah blah" into the "Fancy" field //Given I write "blah blah" into the "Fancy" field }); ``` -------------------------------- ### Register before Hook Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Executes code before each individual scenario. ```objective-c before(^(CCIScenarioDefinition *scenario) { NSLog(@"Starting scenario: %@", scenario.name); // Reset app state before each scenario XCUIApplication *app = [[XCUIApplication alloc] init]; [app launch]; }); ``` -------------------------------- ### Handling Data Tables in steps Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Accesses tabular data from feature files using the kDataTableKey. ```gherkin # Feature file example Given the following users exist: | name | email | role | | Ahmed | ahmed@example.com | admin | | Sarah | sarah@example.com | user | | Mike | mike@example.com | guest | ``` ```objective-c Given(@"the following users exist", ^(NSArray *args, NSDictionary *userInfo) { NSArray *rows = userInfo[kDataTableKey]; // First row contains headers: ["name", "email", "role"] NSArray *headers = rows[0]; // Iterate through data rows (skip header) for (NSInteger i = 1; i < rows.count; i++) { NSArray *row = rows[i]; NSString *name = row[0]; NSString *email = row[1]; NSString *role = row[2]; NSLog(@"Creating user: %@ (%@) - %@", name, email, role); // Create user in test database } }); ``` -------------------------------- ### Initialize Cucumberish in Swift Source: https://github.com/ahmed-ali/cucumberish/wiki/Install-manually-for-Swift Replace the auto-created test case file content with this initializer to define steps and execute feature files. ```Swift import Foundation class CucumberishInitializer: NSObject { class func CucumberishSwiftInit() { //Using XCUIApplication only available in XCUI test targets not the normal Unit test targets. var application : XCUIApplication! //A closure that will be executed only before executing any of your features beforeStart { () -> Void in //Any global initialization can go here } //A Given step definition Given("the app is running") { (args, userInfo) -> Void in } //Another step definition And("all data cleared") { (args, userInfo) -> Void in //Assume you defined an "I tap on \"(.*)\" button" step previousely, you can call it from your code as well. let testCase = userInfo?[kXCTestCaseKey] as? XCTestCase SStep(testCase, "I tap the \"Clear All Data\" button") } //Create a bundle for the folder that contains your "Features" folder. In this example, the CucumberishInitializer.swift file is in the same directory as the "Features" folder. let bundle = Bundle(for: CucumberishInitializer.self) Cucumberish.executeFeatures(inDirectory: "Features", from: bundle, includeTags: nil, excludeTags: nil) } } ``` -------------------------------- ### Add Preprocessor Macro Source: https://github.com/ahmed-ali/cucumberish/wiki/Install-with-Carthage-for-Swift Configure the preprocessor macro in your test target's build settings. This macro is used to define the root of your source files. ```text SRC_ROOT=@"$(SRCROOT)" ``` -------------------------------- ### Define a simple step implementation Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Matches a Gherkin step using exact string comparison. ```Objective-C Given(@"the app is running", ^void(NSArray *args, id userInfo) { //Implementation body goes here }); ``` -------------------------------- ### Initialize Cucumberish in Swift Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Configures global hooks, step definitions, and feature execution within an XCTest environment. ```swift // CucumberishInitializer.swift import Foundation import Cucumberish import XCTest @objc public class CucumberishInitializer: NSObject { static var app: XCUIApplication! @objc public class func CucumberishSwiftInit() { // Global setup - runs once before all scenarios beforeStart { app = XCUIApplication() app.launchArguments = ["--uitesting"] } // Setup before each scenario before { scenario in app.launch() } // Cleanup after each scenario after { scenario in if !scenario.success { print("FAILED: \(scenario.name ?? "Unknown") - \(scenario.failureReason ?? "No reason")") } app.terminate() } // Special setup for @login tagged scenarios beforeTagged(["login"]) { scenario in // Clear stored credentials UserDefaults.standard.removeObject(forKey: "authToken") } // Step Definitions Given("the app is running") { args, userInfo in XCTAssertTrue(app.exists) } Given("I am logged in as \"(.*)\"") { args, userInfo in guard let username = args?.first else { return } let testCase = userInfo?[kXCTestCaseKey] as? XCTestCase SStep(testCase, "I enter \"\(username)\" into the \"Username\" field") SStep(testCase, "I enter \"password123\" into the \"Password\" field") SStep(testCase, "I tap the \"Login\" button") } When("I enter \"(.*)\" into the \"(.*)\" field") { args, userInfo in guard let text = args?[0], let fieldName = args?[1] else { return } let textField = app.textFields[fieldName] textField.tap() textField.typeText(text) } When("I tap the \"(.*)\" button") { args, userInfo in guard let buttonName = args?.first else { return } app.buttons[buttonName].tap() } Then("I should see \"(.*)\" message") { args, userInfo in guard let message = args?.first else { return } let label = app.staticTexts[message] CCISAssert(label.waitForExistence(timeout: 5), "Message '\(message)' not found") } Then("I should be on the \"(.*)\" screen") { args, userInfo in guard let screenName = args?.first else { return } let screen = app.otherElements[screenName] CCISAssert(screen.exists, "Screen '\(screenName)' not displayed") } // Execute features let bundle = Bundle(for: CucumberishInitializer.self) // Configure Cucumberish let cucumberish = Cucumberish.instance() cucumberish.prettyNamesAllowed = true cucumberish.fixMissingLastScenario = true Cucumberish.executeFeatures(inDirectory: "Features", from: bundle, includeTags: ["smoke", "regression"], excludeTags: ["wip", "skip"]) } } ``` -------------------------------- ### Initialize Cucumberish in Swift Source: https://github.com/ahmed-ali/cucumberish/wiki/Setup-Cucumberish-with-Cocoapods-(Swift) This Swift code initializes Cucumberish, defines step implementations, and executes features. It's designed for XCUI test targets and requires the 'Features' folder to be set up correctly. ```Swift import Foundation import Cucumberish public class CucumberishInitializer: NSObject { public class func CucumberishSwiftInit() { //Using XCUIApplication only available in XCUI test targets not the normal Unit test targets. var application : XCUIApplication! //A closure that will be executed only before executing any of your features beforeStart { //Any global initialization can go here } //A Given step definition Given("the app is running") { (args, userInfo) -> Void in } //Another step definition And("all data cleared") { (args, userInfo) -> Void in //Assume you defined an "I tap on \"(.*)\" button" step previousely, you can call it from your code as well. let testCase = userInfo?[kXCTestCaseKey] as? XCTestCase SStep(testCase, "I tap the \"Clear All Data\" button") } //Create a bundle for the folder that contains your "Features" folder. In this example, the CucumberishInitializer.swift file is in the same directory as the "Features" folder. let bundle = Bundle(for: CucumberishInitializer.self) Cucumberish.executeFeatures(inDirectory: "Features", from: bundle, includeTags: nil, excludeTags: nil) } } ``` -------------------------------- ### Define Cucumberish Feature Scenario Source: https://github.com/ahmed-ali/cucumberish/blob/master/README.md A sample feature file structure using Given, When, and Then steps. ```gherkin Scenario: First scenario # This is the first step in the scenario # Also noteworthy; a "Given" step should be treated as the step that defines the app state before going into the rest of the scenario # Or consider it as a precondition for the scenario; # For example if the user must be logged in to post a comment, then you should say something like "Given the user is logged in" as your Given step. Given I have a very cool app # The grammar being used is completely defined by you and your team; it is up to you to find the best way to define your functionality. # Only keep in mind that every step must start with "Given", "When", "Then", "And", or "But". When I automate it with "Cucumberish" Then I will be more confident about the quality of the project and its releases ``` -------------------------------- ### Define But Step Implementations Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Use But to specify negative conditions or exceptions. ```objective-c But(@"^I should not see (?:the )?\"([^\"]*)\" (?:button|element)$", ^(NSArray *args, NSDictionary *userInfo) { NSString *elementName = args[0]; XCUIApplication *app = [[XCUIApplication alloc] init]; XCUIElement *element = app.buttons[elementName]; CCIAssert(!element.exists, @"Element '%@' should not be visible", elementName); }); ``` -------------------------------- ### Define a flexible step using Regex Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Uses regular expressions to match multiple variations of a step sentence. ```Objective-C When(@"^I write \"([^\"]*)\" (?:into|in) (?:the )?\"([^\"]*)\" field$" , ^void(NSArray *args, id userInfo) { //This will match several sentence like: //When I write "Ahmed" in "Name" field //When I write "Ahmed" into "Name" field //When I write "Ahmed" into the "Name" field //When I write "Ahmed" in the "Name" field //etc }); ``` -------------------------------- ### Initialize Cucumberish in Swift Source: https://github.com/ahmed-ali/cucumberish/wiki/Install-with-Carthage-for-Swift This Swift code initializes Cucumberish and executes your feature files. Ensure all step definitions are defined before this method is called. The bundle is created for the directory containing the 'Features' folder. ```swift import Foundation import Cucumberish class CucumberishInitializer: NSObject { class func CucumberishSwiftInit() { //Create a bundle for the folder that contains your "Features" folder. In this example, the CucumberishInitializer.swift file is in the same directory as the "Features" folder. let bundle = Bundle(for: CucumberishInitializer.self) //All step definitions should be done before calling the following method Cucumberish.executeFeatures(inDirectory: "Features", from: bundle, includeTags: nil, excludeTags: nil) } } ``` -------------------------------- ### Implement Cucumberish Steps in Objective-C Source: https://github.com/ahmed-ali/cucumberish/blob/master/README.md Implementation of step definitions using Objective-C blocks, supporting literal strings and regular expressions for matching. ```objective-c Given(@"I have a very cool app", ^(NSArray *args, NSDictionary *userInfo) { //Now it is expected that you will do whatever necessary to make sure "I have a very cool app" condition is satisfied :) NSLog(@"\"Given I have a very cool app\" step is implemented"); }); // The step implementation matching text can be any valid regular expression text // Your regex capturing groups will be added to the args array in the same order they have been captured by your regex string When(@"^I automate it with \"(.*)\"$", ^(NSArray *args, NSDictionary *userInfo) { NSLog(@"I am gonna automate my test cases with \"%@\"", args[0]); }); Then(@"I will be more confident about the quality of the project and its releases", ^(NSArray *args, NSDictionary *userInfo) { NSLog(@"Implemented step for the sake of the example"); }); ``` -------------------------------- ### Initialize Cucumberish Source: https://github.com/ahmed-ali/cucumberish/wiki/Install-manually-for-Objective-C Replace the test case file content with this constructor to define step implementations and execute feature files. ```Objective-C #import "Cucumberish.h" __attribute__((constructor)) void CucumberishInit() { //Define your step implememntations (the example project contains set of basic implementations using KIF) Given(@"it is home screen", ^void(NSArray *args, id userInfo) { //Step implementation code goes here }); And(@"all data cleared", ^void(NSArray *args, id userInfo) { //Step implementation code goes here }); //Optional step, see the comment on this property for more information [Cucumberish instance].fixMissingLastScenario = YES; //Tell Cucumberish the name of your features folder, and which bundle contains this directory. And Cucumberish will handle the rest... //The ClassThatLocatedInTheRootTestTargetFolder could be any class that exist side by side with your Features folder. //So if ClassThatLocatedInTheRootTestTargetFolder exist in the directory YourProject/YourTestTarget //Then in our example your .feature files are expected to be in the directory YourProject/YourTestTarget/Features NSBundle * bundle = [NSBundle bundleForClass:[ClassThatLocatedInTheRootTestTargetFolder class]]; [Cucumberish executeFeaturesInDirectory:@"Features" fromBundle:bundle includeTags:nil excludeTags:nil]; } ``` -------------------------------- ### Define a Scenario Outline with Placeholders Source: https://github.com/ahmed-ali/cucumberish/wiki/Scenario Use a Scenario Outline to define a template for scenarios that will be executed multiple times with different data. Placeholders are indicated by angle brackets. ```Gherkin Scenario Outline: Invite a friend Given I am logged in as "Ahmed" And I am on "home" screen When I tap "invite" button Then I write "" into the "Email" field And I write "" into the "Name" field And I tap "Invite Friend" button Then I should see " Invited" message ``` -------------------------------- ### Set Bridging Header Path Source: https://github.com/ahmed-ali/cucumberish/wiki/Install-manually-for-Swift Configure the Objective-C Bridging Header build setting to point to the correct file location. ```text ${SRCROOT}/${TARGET_NAME}/bridging-header.h ``` -------------------------------- ### Access regex capturing groups in implementation Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Demonstrates how to retrieve captured parameters from the args array. ```Objective-C When(@"^I write \"([^\"]*)\" (?:into|in) (?:the )?\"([^\"]*)\" field$" , ^void(NSArray *args, id userInfo) { //When this implementation is called because it matched the following step //When I write "Ahmed" in "FieldName" field //Then args[0] will be equal to Ahmed and args[1] will be equal to FieldName }); ``` -------------------------------- ### Initialize Cucumberish in Objective-C Source: https://github.com/ahmed-ali/cucumberish/wiki/Install-with-Carthage-for-Swift This Objective-C code sets the test target source root and calls the Swift initializer for Cucumberish. Replace 'CucumberishExampleUITests' with your actual Swift test target name. ```objectivec //Replace CucumberishExampleUITests with the name of your swift test target #import "CucumberishExampleUITests-Swift.h" __attribute__((constructor)) void CucumberishInit() { [Cucumberish instance].testTargetSrcRoot = SRC_ROOT; [CucumberishInitializer CucumberishSwiftInit]; } ``` -------------------------------- ### Flexible Matching Functions Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Functions to allow a single step implementation to match multiple prepositions. ```APIDOC ## MatchAll and Match ### Description MatchAll allows a definition to be used for When, Then, And, and But. Match allows specifying an array of allowed prepositions. ### Parameters - **prepositions** (NSArray) - Required (for Match) - List of prepositions to match. - **definitionString** (NSString) - Required - The regex pattern to match. - **body** (CCIStepBody) - Required - The block to execute. ### Request Example Match(@[@"Given", @"When"], @"I write \"(.*)\" into the \"(.*)\" field", ^void(NSArray *args, id userInfo) { // Implementation }); ``` -------------------------------- ### Registering an after hook Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Executes code after each scenario in LIFO order, regardless of the scenario's success status. ```objective-c after(^(CCIScenarioDefinition *scenario) { NSLog(@"Completed scenario: %@", scenario.name); NSLog(@"Success: %@", scenario.success ? @"YES" : @"NO"); if (!scenario.success) { NSLog(@"Failure reason: %@", scenario.failureReason); // Take screenshot on failure XCUIApplication *app = [[XCUIApplication alloc] init]; XCUIScreenshot *screenshot = [app screenshot]; // Save screenshot for debugging } }); ``` -------------------------------- ### Initialize Cucumberish in Objective-C Source: https://github.com/ahmed-ali/cucumberish/wiki/Setup-Cucumberish-with-Cocoapods-(Swift) This Objective-C code serves as the entry point for Cucumberish initialization, calling the Swift initialization method. Ensure the import statement matches your Swift test target name. ```Objective-C //Replace CucumberishExampleUITests with the name of your swift test target #import "CucumberishExampleUITests-Swift.h" __attribute__((constructor)) void CucumberishInit() { [CucumberishInitializer CucumberishSwiftInit]; } ``` -------------------------------- ### Reuse steps within implementations Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Call one step from another using the Step function, ignoring the preposition. ```Objective-C When(@"I tap the \"(.*)\" button", ^void(NSArray *args, id userInfo) { //Code to tap the button goes here }); Given(@"I logged in with the user \"(.*)\", ^void(NSArray *args, id userInfo) { //Fill the user data //Then tap the Login button, which will require re-using the previous step; and note how we completely ignored the preposition in our call to the Step function. Step(@"I tap the \"%@\" button, @"Login"); }); ``` -------------------------------- ### Configure Cucumberish Singleton Options Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Configure global options for the Cucumberish singleton instance, such as enabling pretty names for the Test Navigator or fixing issues with the last scenario. Use this to customize framework behavior. ```Objective-C // Get the singleton instance and configure options Cucumberish *cucumberish = [Cucumberish instance]; // Enable pretty names for Test Navigator (allows spaces and special characters) cucumberish.prettyNamesAllowed = YES; // Fix disappearing last scenario issue in Xcode cucumberish.fixMissingLastScenario = YES; // Set custom prefix for generated test classes (default: "CCI") cucumberish.featureNamesPrefix = @"MyApp"; // Enable dry run mode to scan features without executing cucumberish.dryRun = YES; cucumberish.dryRunLanguage = CCILanguageSwift; // Parse and execute features from bundle NSBundle *bundle = [NSBundle bundleForClass:[self class]]; [[cucumberish parserFeaturesInDirectory:@"Features" fromBundle:bundle includeTags:@[@"smoke", @"regression"] excludeTags:@[@"wip", @"skip"]] beginExecution]; ``` -------------------------------- ### Initialize Cucumberish in Test Target Source: https://github.com/ahmed-ali/cucumberish/wiki/Install-with-Carthage-for-Objective-C Replace the content of your auto-created test case file with this Objective-C code. It initializes Cucumberish, defines basic steps, and configures it to find feature files. ```objective-c #import __attribute__((constructor)) void CucumberishInit() { //Define your step implememntations (the example project contains set of basic implementations using KIF) Given(@"it is home screen", ^void(NSArray *args, id userInfo) { //Step implementation code goes here }); And(@"all data cleared", ^void(NSArray *args, id userInfo) { //Step implementation code goes here }); //Optional step, see the comment on this property for more information [Cucumberish instance].fixMissingLastScenario = YES; //This step is important to help Cucumberish locate your feature files correctly when reporting test failures. [Cucumberish instance].testTargetSrcRoot = SRC_ROOT; //Tell Cucumberish the name of your features folder, and which bundle contains this directory. And Cucumberish will handle the rest... //The ClassThatLocatedInTheRootTestTargetFolder could be any class that exist side by side with your Features folder. //So if ClassThatLocatedInTheRootTestTargetFolder exist in the directory YourProject/YourTestTarget //Then in our example your .feature files are expected to be in the directory YourProject/YourTestTarget/Features NSBundle * bundle = [NSBundle bundleForClass:[ClassThatLocatedInTheRootTestTargetFolder class]]; //Finally, let the magic begin! [Cucumberish executeFeaturesInDirectory:@"Features" fromBundle:bundle includeTags:nil excludeTags:nil]; } ``` -------------------------------- ### Reuse Step Implementations Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Call existing step definitions from within other steps using step() in Objective-C or SStep() in Swift. ```objective-c // Objective-C: Reuse steps with step() function When(@"^I login as \"([^\"]*)\" with password \"([^\"]*)\"$", ^(NSArray *args, NSDictionary *userInfo) { NSString *username = args[0]; NSString *password = args[1]; id testCase = userInfo[kXCTestCaseKey]; // Reuse previously defined steps step(testCase, @"I tap the \"Login\" button"); step(testCase, @"I enter \"%@\" into the \"Username\" field", username); step(testCase, @"I enter \"%@\" into the \"Password\" field", password); step(testCase, @"I tap the \"Submit\" button"); }); // Swift: Use SStep() function When("I complete checkout") { args, userInfo in let testCase = userInfo?[kXCTestCaseKey] as? XCTestCase SStep(testCase, "I tap the \"Checkout\" button") SStep(testCase, "I confirm the payment") SStep(testCase, "I should see \"Order Confirmed\" message") } ``` -------------------------------- ### Register Match Step for Specific Prepositions Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Restricts step execution to a specific subset of prepositions. ```objective-c // Match only specific prepositions Match(@[@"Given", @"When"], @"^I am on the \"([^\"]*)\" screen$", ^(NSArray *args, NSDictionary *userInfo) { NSString *screenName = args[0]; XCUIApplication *app = [[XCUIApplication alloc] init]; XCUIElement *screen = app.otherElements[screenName]; CCIAssert(screen.exists, @"Screen '%@' not found", screenName); }); // Matches: "Given I am on the "Home" screen", "When I am on the "Settings" screen" // Does NOT match: "Then I am on the "Home" screen" ``` -------------------------------- ### Execute features by tags in Objective-C Source: https://github.com/ahmed-ali/cucumberish/wiki/Tags Filters and executes features located in a specific directory that match the provided tags. ```Objective-C [[[Cucumberish instance] parserFeaturesInDirectory:@"ExampleFeatures" featureTags:@[@"accounts", @"booking"]] beginExecution]; ``` -------------------------------- ### Step Definition Functions Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Functions used to define step implementations based on specific Gherkin prepositions. ```APIDOC ## Given, When, Then, And, But ### Description Defines a step implementation that matches a specific Gherkin preposition and definition string. ### Parameters - **definitionString** (NSString) - Required - The regex pattern to match the step text. - **body** (CCIStepBody) - Required - The block to execute when the step is matched. ### Request Example Given(@"the app is running", ^void(NSArray *args, id userInfo) { // Implementation }); ``` -------------------------------- ### Cucumberish Configuration Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Configures the Cucumberish singleton instance to manage test execution settings, pretty names, and feature parsing options. ```APIDOC ## Cucumberish Configuration ### Description Configures the singleton instance of the Cucumberish framework to control how features are parsed and executed within the Xcode test environment. ### Method Configuration via Properties ### Parameters - **prettyNamesAllowed** (BOOL) - Optional - Enables spaces and special characters in Test Navigator. - **fixMissingLastScenario** (BOOL) - Optional - Fixes an issue where the last scenario might not appear in Xcode. - **featureNamesPrefix** (NSString) - Optional - Sets a custom prefix for generated test classes. - **dryRun** (BOOL) - Optional - Enables dry run mode to scan features without execution. - **dryRunLanguage** (CCILanguage) - Optional - Sets the language for dry run scanning. ``` -------------------------------- ### Define a Basic Scenario in Gherkin Source: https://github.com/ahmed-ali/cucumberish/wiki/Scenario Use a Scenario to define a specific sequence of steps for a test case. Failures in any step will mark the entire scenario as failed. ```Gherkin Scenario: Eat pizza Given there is enough slices for 1 person When I eat 2 slices Then I should have 1 slice remaining ``` -------------------------------- ### Feature Execution Source: https://context7.com/ahmed-ali/cucumberish/llms.txt Methods for parsing and executing Gherkin feature files from an application bundle. ```APIDOC ## parserFeaturesInDirectory ### Description Parses feature files from a specific directory within a bundle and prepares them for execution with optional tag filtering. ### Parameters - **directory** (NSString) - Required - The directory path containing .feature files. - **bundle** (NSBundle) - Required - The bundle containing the features. - **includeTags** (NSArray) - Optional - List of tags to include. - **excludeTags** (NSArray) - Optional - List of tags to exclude. ## executeFeaturesInDirectory ### Description Convenience method to parse and immediately execute all features in a directory. ### Parameters - **inDirectory** (String) - Required - The directory path. - **from** (Bundle) - Required - The bundle containing the features. - **includeTags** (Array) - Optional - Tags to include. - **excludeTags** (Array) - Optional - Tags to exclude. ``` -------------------------------- ### Define Around Hook Source: https://github.com/ahmed-ali/cucumberish/wiki/Hooks Wraps scenario execution; the scenarioExecutionBlock must be called to trigger the scenario. ```Objective-C around(@[@"booking"], ^(CCIScenarioDefinition *scenario, void(^scenarioExecutionBlock)(void)) { //Here you do whatever you want; //Then you must call scenarioExecutionBlock(); //Then you can continue doing whatever you want again :) }); ``` -------------------------------- ### Initialize Cucumberish in Objective-C Source: https://github.com/ahmed-ali/cucumberish/blob/master/INSTRUCTIONS.md Implement the `CucumberishInit` constructor in an Objective-C file to initialize Cucumberish and its Swift counterpart. This function is called automatically upon test execution. ```objective-c #import "AppNameUITests-Swift.h" void CucumberishInit(void); __attribute__((constructor)) void CucumberishInit() { [CucumberishInitializer CucumberishSwiftInit]; } ``` -------------------------------- ### Define a Feature in Gherkin Source: https://github.com/ahmed-ali/cucumberish/blob/master/README.md Create a .feature file to define your test scenarios using the Gherkin language. Features can include an optional free-text description. ```Gherkin Feature: Example # This is a free text description as an inline documentation for your features, you can omit it if you want. # However, it is advisable to describe your features well. As someone who plans to automate the iOS project test cases, I will use Cucumberish. ``` -------------------------------- ### Step Reusability Source: https://github.com/ahmed-ali/cucumberish/wiki/Step-Definitions Function to trigger one step implementation from within another. ```APIDOC ## Step / SStep ### Description Allows calling a step implementation from within another step implementation, ignoring the preposition. ### Parameters - **stepString** (NSString) - Required - The step text to trigger. ### Request Example Step(@"I tap the \"%@\" button", @"Login"); ``` -------------------------------- ### Define Before Tagged Hook Source: https://github.com/ahmed-ali/cucumberish/wiki/Hooks Executes before scenarios matching the specified tags. ```Objective-C beforeTagged(@[@"booking"], ^(CCIScenarioDefinition *scenario) { //Code that will run before any scenario that has the tag @booking }); ``` -------------------------------- ### Configure Bridging Header for Cucumberish Source: https://github.com/ahmed-ali/cucumberish/blob/master/INSTRUCTIONS.md Create an Objective-C bridging header file in your UITests folder and import the Cucumberish header. This is necessary for Swift to interact with Objective-C code. ```objective-c #import ``` -------------------------------- ### Define After Finish Hook Source: https://github.com/ahmed-ali/cucumberish/wiki/Hooks Executes once after all scenarios have finished. ```Objectiev-C afterFinish(^{ //Code that runs only after finish executing all the scenarios }); ```