All Projects → RedMadRobot → catbird

RedMadRobot / catbird

Licence: MIT License
Mock server for UI tests

Programming Languages

swift
15916 projects
HTML
75241 projects
shell
77523 projects

Projects that are alternatives of or similar to catbird

Mongokitten
Native MongoDB driver for Swift, written in Swift
Stars: ✭ 605 (+1790.63%)
Mutual labels:  vapor, swift-package-manager
Lunch
Lunch is helper of UI Test with Swift.
Stars: ✭ 55 (+71.88%)
Mutual labels:  ui-testing, ui-tests
Telegrammer
Telegram Bot - written with Swift 5.2 / NIO, supports Linux, macOS
Stars: ✭ 248 (+675%)
Mutual labels:  vapor, swift-package-manager
apns
Helpful extensions and abstractions for using APNSwift
Stars: ✭ 75 (+134.38%)
Mutual labels:  vapor, swift-nio
sqlite-nio
Non-blocking wrapper for libsqlite3-dev using SwiftNIO
Stars: ✭ 33 (+3.13%)
Mutual labels:  vapor, swift-nio
mocka
Mocka — A Mock Server Made for Developers by Developers, made in Swift ❤️
Stars: ✭ 56 (+75%)
Mutual labels:  mock-server, vapor
leaf-markdown
Markdown renderer for Vapor
Stars: ✭ 51 (+59.38%)
Mutual labels:  vapor
mini-swift
Minimal Flux architecture written in Swift.
Stars: ✭ 40 (+25%)
Mutual labels:  swift-package-manager
Guardia-Swift-Playground
🐦To construct an online swift playground by server sandbox and vapor web server framework & toolbox.
Stars: ✭ 12 (-62.5%)
Mutual labels:  vapor
column-text-view-ui
📄 Column Text View is an adaptive UI component that renders text in columns, horizontally [iOS 12, UIKit, TextKit, SwiftUI].
Stars: ✭ 11 (-65.62%)
Mutual labels:  swift-package-manager
jsxmock
使用 JSX 来定义 Mock Server
Stars: ✭ 31 (-3.12%)
Mutual labels:  mock-server
jest-pact-typescript
A PACT consumer example written in TypeScript with Jest
Stars: ✭ 22 (-31.25%)
Mutual labels:  mock-server
tapit-app
App which lets two people share their social media details by simply putting one phone on top of the other ("tapping"). Currently in development by Nikita Mounier.
Stars: ✭ 18 (-43.75%)
Mutual labels:  swift-package-manager
pagination
Simple Vapor 3 Pagination
Stars: ✭ 64 (+100%)
Mutual labels:  vapor
awesome-vapor
A curated list of Vapor-related awesome projects.
Stars: ✭ 907 (+2734.38%)
Mutual labels:  vapor
Leonardo
Your mocking ninja - an add-on tool for centralizing your client side mocking
Stars: ✭ 91 (+184.38%)
Mutual labels:  ui-tests
CapoServer
GraphQL server for CapoMap application
Stars: ✭ 19 (-40.62%)
Mutual labels:  vapor
gmocker
Create a blazing fast mock server with just a JSON file
Stars: ✭ 49 (+53.13%)
Mutual labels:  mock-server
mocky
Mocky is a simple API mocking solution written in PHP.
Stars: ✭ 29 (-9.37%)
Mutual labels:  mock-server
SETabView
SETabView is a TabBar with simple yet beautiful animations that makes your apps look cool!
Stars: ✭ 53 (+65.63%)
Mutual labels:  swift-package-manager

Catbird

Test GitHub license CocoaPods Compatible Platform SPM compatible

Features

  • Dynamic mock server
  • Static file mock server
  • Proxy server with writing response files

Installation

To use Catbird in UI-tests you must have Catbird server and Catbird API code which allows you to communicate with the server.

Type Server API code
Manual
Homebrew 🚫
SPM 🚫
CocoaPods

Manual

Download catbird.zip archive from the latest release page.

Using Homebrew:

Run the following command:

brew install RedMadRobot/formulae/catbird

Using SPM:

If you have an Xcode project, open it and add Catbird Package using the following URL:

https://github.com/RedMadRobot/catbird.git

Using CocoaPods:

Add Catbird to UI tests target.

target 'App' do
  use_frameworks!

  target 'AppUITests' do
    inherit! :search_paths

    pod 'Catbird'
  end
end

Setup in Xcode project

  • Open Schema/Edit scheme...
  • Select Test action
  • Select Pre-Actions
    • Add New Run Script action
    • Provide build setting from <YOUR_APP_TARGET>
    • ${PODS_ROOT}/Catbird/start.sh
  • Select Post-Actions
    • Add New Run Script action
    • Provide build setting from <YOUR_APP_TARGET>
    • ${PODS_ROOT}/Catbird/stop.sh

Usage

import XCTest
import Catbird

enum LoginMock: CatbirdMockConvertible {
    case success
    case blockedUserError

    var pattern: RequestPattern {
        RequestPattern(method: .POST, url: URL(string: "/login")!)
    }

    var response: ResponseMock {
        switch self {
        case .success:
            let json: [String: Any] = [
                "data": [
                    "access_token": "abc",
                    "refresh_token": "xyz",
                    "expired_in": "123",
                ]
            ]
            return ResponseMock(
                status: 200,
                headers: ["Content-Type": "application/json"],
                body: try! JSONSerialization.data(withJSONObject: json))

        case .blockedUserError:
            let json: [String: Any] = [
                "error": [
                    "code": "user_blocked",
                    "message": "user blocked"
                ]
            ]
            return ResponseMock(
                status: 400,
                headers: ["Content-Type": "application/json"],
                body: try! JSONSerialization.data(withJSONObject: json))
        }
    }
}

final class LoginUITests: XCTestCase {

    private let catbird = Catbird()
    private var app: XCUIApplication!

    override func setUp() {
        super.setUp()
        continueAfterFailure = false
        app = XCUIApplication()

        // Base URL in app `UserDefaults.standard.url(forKey: "url_key")`
        app.launchArguments = ["-url_key", catbird.url.absoluteString]
        app.launch()
    }

    override func tearDown() {
        XCTAssertNoThrow(try catbird.send(.removeAll), "Remove all requests")
        super.tearDown()
    }

    func testLogin() {
        XCTAssertNoThrow(try catbird.send(.add(LoginMock.success)))

        app.textFields["login"].tap()
        app.textFields["login"].typeText("[email protected]")
        app.secureTextFields["password"].tap()
        app.secureTextFields["password"].typeText("qwerty")
        app.buttons["Done"].tap()

        XCTAssert(app.staticTexts["Main Screen"].waitForExistence(timeout: 3))
    }

    func testBlockedUserError() {
        XCTAssertNoThrow(try catbird.send(.add(LoginMock.blockedUserError)))

        app.textFields["login"].tap()
        app.textFields["login"].typeText("[email protected]")
        app.secureTextFields["password"].tap()
        app.secureTextFields["password"].typeText("burger")
        app.buttons["Done"].tap()

        XCTAssert(app.alerts["Error"].waitForExistence(timeout: 3))
    }
}

Request patterns

You can specify a pattern for catch http requests and make a response with mock data. Pattern matching applied for URL and http headers in the request. See RequestPattern struct.

Three types of patterns can be used:

  • equal - the request value must be exactly the same as the pattern value,
  • wildcard - the request value match with the wildcard pattern (see below),
  • regexp - the request value match with the regular expression pattern.
Note:

If you want to apply a wildcard pattern for the url query parameters, don't forget escape ? symbol after domain or path.

Pattern.wildcard("http://example.com\?query=*")

Wildcard pattern

"Wildcards" are the patterns you type when you do stuff like ls *.js on the command line, or put build/* in a .gitignore file.

In our implementation any wildcard pattern translates to regular expression and applies matching with URL or header string.

The following characters have special magic meaning when used in a pattern:

  • * matches 0 or more characters
  • ? matches 1 character
  • [a-z] matches a range of characters, similar to a RegExp range.
  • {bar,baz} matches one of the substitution listed in braces. For example pattern foo{bar,baz} matches strings foobar or foobaz

You can escape special characters with backslash \.

Negation in groups is not supported.

Example project

$ cd Example/CatbirdX
$ bundle exec pod install
$ xed .

Environment variables

  • CATBIRD_MOCKS_DIR — Directory where static mocks are located.
  • CATBIRD_RECORD_MODE — set this variable to 1 so that the application starts recording HTTP responses along the path set in CATBIRD_MOCKS_DIR. Default 0.
  • CATBIRD_REDIRECT_URL — set this url to forward direct requests to catbird. By default, nil. If the recording mode is not enabled, then first the responses will be searched in the mocks and only if nothing is found, the request will be forwarded.
  • CATBIRD_PROXY_ENABLED — set this variable to 1 to forward proxy requests to catbird. By default, 0. If the recording mode is not enabled, then first the responses will be searched in the mocks and only if nothing is found, the request will be proxied.

Catbird supports proxying only HTTP requests. HTTPS requests are not supported!

Redirect example

Run catbird with CATBIRD_REDIRECT_URL.

CATBIRD_REDIRECT_URL=https://api.github.com ./catbird

All direct requests will be forwarded to CATBIRD_REDIRECT_URL.

curl http://127.0.0.1:8080/zen

The response will be returned as to the request https://api.github.com/zen

Proxy example

Run catbird with CATBIRD_PROXY_ENABLED=1.

CATBIRD_PROXY_ENABLED=1 ./catbird

By enabling this mode, the catbird will be running as a local http proxy server. You can configure your http client to use this proxy, and all requests will be proxied thought the catbird and redirected to the real host. It might be helpful if you don't want to change the base url of your requests.

curl http://api.github.com/zen --proxy http://127.0.0.1:8080

Logs

Logs can be viewed in the Console.app with subsystem com.redmadrobot.catbird

Don't forget to include the message in the action menu

  • Include Info Messages
  • Include Debug Messages

Without this, only error messages will be visible

Web

You can view a list of all intercepted requests on the page http://127.0.0.1:8080/catbird

Parallel testing

For parallel testing you need to fulfill several conditions.

  • Create a Catbird instance for each test case or test method with a unique parallelId identifier.
  • Pass parallelId to the application.
  • Add parallelId as X-Catbird-Parallel-Id to each request header in application.
final class LoginUITests: XCTestCase {

    private let catbird = Catbird(parallelId: UUID().uuidString)
    private var app: XCUIApplication!

    override func setUp() {
        super.setUp()
        continueAfterFailure = false
        app = XCUIApplication()

        app.launchArguments = [
            // Base URL in app `UserDefaults.standard.url(forKey: "url_key")`
            "-url_key", catbird.url.absoluteString,

            // `parallelId` in app `UserDefaults.standard.url(forKey: "parallelId")`
            "-parallelId", catbird.parallelId!
        ]
        app.launch()
    }
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].