{"id":1755,"url":"https://github.com/phimage/Erik","last_synced_at":"2025-08-06T14:31:36.598Z","repository":{"id":37548426,"uuid":"46288061","full_name":"phimage/Erik","owner":"phimage","description":"Erik is an headless browser based on WebKit. An headless browser allow to run functional tests, to access and manipulate webpages using javascript.","archived":false,"fork":false,"pushed_at":"2022-08-05T13:02:22.000Z","size":269,"stargazers_count":599,"open_issues_count":8,"forks_count":48,"subscribers_count":17,"default_branch":"master","last_synced_at":"2024-12-03T19:04:00.736Z","etag":null,"topics":["erik","headless-browsers","swift","test","webkit"],"latest_commit_sha":null,"homepage":"http://phimage.github.io/Erik/","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phimage.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"phimage","patreon":"phimage","custom":"https://www.paypal.com/paypalme2/ericphimage"}},"created_at":"2015-11-16T16:41:41.000Z","updated_at":"2024-11-30T03:56:32.000Z","dependencies_parsed_at":"2022-08-02T02:20:07.137Z","dependency_job_id":null,"html_url":"https://github.com/phimage/Erik","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phimage%2FErik","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phimage%2FErik/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phimage%2FErik/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phimage%2FErik/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phimage","download_url":"https://codeload.github.com/phimage/Erik/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228905553,"owners_count":17989782,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["erik","headless-browsers","swift","test","webkit"],"created_at":"2024-01-05T20:15:55.029Z","updated_at":"2024-12-09T14:31:20.351Z","avatar_url":"https://github.com/phimage.png","language":"Swift","readme":"# Erik\n\n[![Join the chat at https://gitter.im/phimage/Erik](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/phimage/Erik?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat\n            )](http://mit-license.org) [![Platform](http://img.shields.io/badge/platform-ios_osx-lightgrey.svg?style=flat\n             )](https://developer.apple.com/resources/) [![Language](http://img.shields.io/badge/language-swift-orange.svg?style=flat\n             )](https://developer.apple.com/swift) [![Issues](https://img.shields.io/github/issues/phimage/Erik.svg?style=flat\n           )](https://github.com/phimage/Erik/issues) [![Cocoapod](http://img.shields.io/cocoapods/v/Erik.svg?style=flat)](http://cocoadocs.org/docsets/Erik/)[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n\n\u003ca href=\"https://www.patreon.com/phimage\"\u003e\n\u003cimg src=\"https://c5.patreon.com/external/logo/become_a_patron_button.png\" alt=\"Become a Patron!\" height=\"35\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://paypal.me/ericphimage\"\u003e\n\u003cimg src=\"https://buymecoffee.intm.org/img/button-paypal-white.png\" alt=\"Buy me a coffee\" height=\"35\"\u003e\n\u003c/a\u003e\n\n[\u003cimg align=\"left\" src=\"logo.png\" hspace=\"20\"\u003e](#logo) Erik is a [headless browser](https://en.wikipedia.org/wiki/Headless_browser) based on [WebKit](https://fr.wikipedia.org/wiki/WebKit) and HTML parser [Kanna](https://github.com/tid-kijyun/Kanna).\n\nAn headless browser allow to run functional tests, to access and manipulate webpages using javascript.\n\n```swift\nlet browser = Erik.visit(url: url) { document, error in\n    // browse HTML element, click, submit form and more\n}\n```\n\n\n\n## Navigation\nGo to an url\n```swift\nErik.visit(url: url) { object, error in\n    if let e = error {\n\n    } else if let doc = object {\n        // HTML Inspection\n    }\n}\n```\nHow to get current url?\n```swift\nif let url = Erik.currentURL {..}\n```\n\nFor multiple browsing you can create an instance of headless browser and use same functions\n```swift\nlet browser = Erik()\nbrowser.visitURL...\n```\n\n## HTML Inspection\n### Search for nodes by [CSS selector](http://www.w3schools.com/cssref/css_selectors.asp)\n```swift\nfor link in doc.querySelectorAll(\"a, link\") {\n    print(link.text)\n    print(link[\"href\"])\n}\n```\n### Edit first input field with name \"user\"\n```swift\nif let input = doc.querySelectorAll(\"input[name=\\\"user\\\"]\").first {\n    input[\"value\"] = \"Eric\"\n}\n```\n\n### Submit a form\n```swift\nif let form = doc.querySelector(\"form[id='search']\") as? Form {\n    form.submit()\n}\n```\n\n### Evaluate some JavaScript\n```swift\nlet javaScriptSource = \"console.log(\"test\");\"\nErik.evaluate(javaScript:javaScriptSource) { (obj, err) -\u003e Void in\n    if let error = err {\n        switch error {\n            case ErikError.javaScriptError(let message):\n            print(message)\n            default :\n            print(\"\\(error)\")\n        }\n    }\n    else if let capturedValue = obj {\n        // do something according to result\n    }\n}\n```\n`capturedValue` is the content of JavaScript variable `resultErik`\nAffect this variable in your JavaScript code.\n```swift\nlet javaScriptSource = \"console.log('test'); var resultErik = 1 + 1;\"\n```\n\n### Warning about DOM change\n:warning: All action on Dom use JavaScript and do not modify the actual\n`Document` object and its children `Element`.\n\nYou must use `currentContent` to get a refreshed `Document` object\n\n### Get current content\n```swift\nErik.currentContent { (obj, err) -\u003e Void in\n    if let error = err {\n    }\n    else if let document = obj {\n       // HTML Inspection\n    }\n}\n```\n### Using Future\nAs an optional feature, you can use [Future/Promise](https://en.wikipedia.org/wiki/Futures_and_promises) ( Erik use frameworks [BrightFutures](https://github.com/Thomvis/BrightFutures) \u0026 [Result](https://github.com/antitypical/Result))\n\nExample to submit a google search\n```swift\nlet url = NSURL(string:\"https://www.google.com\")!\nlet value = \"Erik The Phantom of Opera\"\n// visit\nvar future: Future\u003cDocument, NSError\u003e = Erik.visitFuture(url: url)\n// fill input field\nfuture = future.flatMap { document -\u003e Future\u003cDocument, NSError\u003e in\n    if let input = document.querySelector(\"input[name='q']\") {\n        input[\"value\"] = value\n    }\n    if let form = document.querySelector(\"form[name=\\\"f\\\"]\") as? Form {\n        form.submit()\n    }\n    return Erik.currentContentFuture()\n}\n// finally get final result as success or error\nfuture.onSuccess { document in\n    // parse result\n}\nfuture.onFailure { error in\n    print(\"\\(error)\")\n}\n```\n\n## Limitation\nOn iOS 9 and macOS 10.11, you need to ensure you use https://, because iOS 9 and macOS 10.11 do not like apps sending or receiving data insecurely. If this something you want to override, click here to read about [App Transport Security](https://github.com/OAuthSwift/OAuthSwift/wiki/App-Transport-Security).\n\n## Links\n- [A list of (almost) all headless web browsers in existence](https://github.com/dhamaniasad/HeadlessBrowsers)\n- [Wikipedia Headless browser](https://en.wikipedia.org/wiki/Headless_browser)\n\n## Setup\n\n### Using [cocoapods](http://cocoapods.org/) ##\n[CocoaPods](https://cocoapods.org/) is a centralized dependency manager for\nObjective-C and Swift. Go [here](https://guides.cocoapods.org/using/index.html)\nto learn more.\n\n1. Add the project to your [Podfile](https://guides.cocoapods.org/using/the-podfile.html).\n\n    ```ruby\n    use_frameworks!\n\n    pod 'Erik'\n    // or specific target\n    target :test do\n       pod 'Erik'\n    end\n    ```\n\n2. Run `pod install` and open the `.xcworkspace` file to launch Xcode.\n\n\n#### Optional Future\nAdd `pod 'Erik/Future'` to your `Podfile` and run `pod install`.\n\n## Using carthage ##\n[Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager for Objective-C and Swift.\n\n1. Add the project to your [Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile).\n\n    ```\n    github \"phimage/Erik\"\n    ```\n\n## Roadmap\n\n- [ ] (WIP) WKWebView screenshot (webkit view privates api?)\n\n## Why Erik?\n\nA well known headless browser is named [PhantomJS](http://phantomjs.org/) and a very well known browser is [Opera](http://www.opera.com).\n\nAs a tribute I use [Erik](https://en.wikipedia.org/wiki/Erik_(The_Phantom_of_the_Opera)), firstname of the title character from Gaston Leroux's novel *Le Fantôme de l'Opéra* best known to English speakers as [The Phantom of Opera](https://en.wikipedia.org/wiki/The_Phantom_of_the_Opera). \n\nMy name is also Erik. So egotistical to call a project using its firstname isn't it.\n\nMy only justification is that I was playing Metal Gear Solid *V* and the creator Hideo Kojima name appears over 100 times in the game. Coincidentally the full name of the game is Metal Gear Solid *V* : The  **Phantom** Pain.\n\n## License\nThe MIT License. See the LICENSE file for more information.\n","funding_links":["https://github.com/sponsors/phimage","https://patreon.com/phimage","https://www.paypal.com/paypalme2/ericphimage","https://www.patreon.com/phimage","https://paypal.me/ericphimage"],"categories":["Parsing","Libs","Swift","Testing [🔝](#readme)","Tools"],"sub_categories":["Other Parsing","Testing","Other free courses"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphimage%2FErik","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphimage%2FErik","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphimage%2FErik/lists"}