An application that connects to a server websocket application, which we can send and receive data over Websockets using Starscream.
https://github.com/JPrendy/websocket-client-server-javascript-application We need the following project to be started locally to see it working live, the tests will still work, if the corresponding project is not started locally.
In the project, you want to add Starscream
by using Swift Package Manager by adding the following url https://github.com/daltoniam/Starscream, you should see something like the following
In the ViewController.swift
, you want the following websocket url to be ws://localhost:8082
as that is the port we use in https://github.com/JPrendy/websocket-client-server-javascript-application.
private var socket: WebSocket?
override func viewDidLoad() {
var request = URLRequest(url: URL(string: "ws://localhost:8082")!)
if ProcessInfo.processInfo.arguments.contains("TESTING") {
request = URLRequest(url: URL(string: "http://localhost:8080")!)
}
super.viewDidLoad()
// Do any additional setup after loading the view.
request.timeoutInterval = 5
socket = WebSocket(request: request)
socket?.delegate = self
socket?.connect()
}
In the ViewController.swift
, the below code is important to get Websockets sending and receiving data working correctly. when we press the sendData
button in our app we are calling socket?.write(string: "Hi Server!")
which calls the function didReceive
and will call the specific case .text
and in this case whenever we socket?.write
or another application that uses the same Websocket port of ws://localhost:8082
uses the equivalent of socket?.write
it updates the text of the app with websocketData.text = string
, so we can easily see all the websocket data that is being sent and received. We can also see the data being sent and received in the logs.
@IBAction func sendData(_ sender: Any) {
socket?.write(string: "Hi Server!")
}
@IBAction func sendData2(_ sender: Any) {
socket?.write(string: "2nd Send Websocket data")
}
func didReceive(event: WebSocketEvent, client: WebSocket) {
switch event {
case .connected(let headers):
print("websocket is connected: \(headers)")
case .disconnected(let reason, let code):
print("websocket is disconnected: \(reason) with code: \(code)")
case .text(let string):
// this is the data we receive from other users sending data to specific port we use for websockets
print("Received text: \(string)")
websocketData.text = string
case .binary(let data):
print("Received data: \(data.count)")
case .ping(_):
break
case .pong(_):
break
case .viabilityChanged(_):
break
case .reconnectSuggested(_):
break
case .cancelled:
print("error")
case .error(_):
break
}
}
The important part of testing the websocket data we send, we need to use Swifter
to set up a mocked Websocket server, go to websocket_starscreams_ios_applicationUITests
and add the following
let server = HttpServer()
let MessagingRobot = MessagesRobot()
override func setUp() {
continueAfterFailure = false
try! server.start()
server["/"] = websocket(text: { session, text in
if text.contains("Hi Server!") {
session.writeText("Sent data via mocked Websocket")
}
else if text.contains("2nd Send Websocket data") {
session.writeText("Sent data two via mocked Websocket")
}
else {
session.writeText("Could not find the text we were looking for")
}
}, binary: { session, binary in
session.writeBinary(binary)
})
app.launchArguments += ["TESTING"]
}
The app.launchArguments += ["TESTING"]
switches us to use a localhost instead of a real websocket, so when we set up the mocked Websocket server we will using http://localhost:8080/
instead of ws://localhost:8082/
.
if ProcessInfo.processInfo.arguments.contains("TESTING") {
request = URLRequest(url: URL(string: "http://localhost:8080")!)
}
Whenever we send data via websockets we want look for specific strings to return mocked data, so in the app we have a button that sends Hi Server!
via websockets and when we send that string we want to return a mocked response we would expect, in this case we are returning session.writeText("Sent data via mocked Websocket")
.
server["/"] = websocket(text: { session, text in
if text.contains("Hi Server!") {
session.writeText("Sent data via mocked Websocket")
}
else if text.contains("2nd Send Websocket data") {
session.writeText("Sent data two via mocked Websocket")
}
An important thing to note when using websockets with our tests we need to use app.restart()
for every test or any tests after the first one will fail, so we need something like the following for every test in websocket_starscreams_ios_applicationUITests
.
func testSendingMockedWebsocketData() {
app.restart()
MessagingRobot
.tapWebsocketButton()
.assertSentWebsocketText(text: "Sent data via mocked Websocket")
}
To set up fastlane, type the following in the terminal and follow the steps
fastlane init
To get this working on CI, we need to add the following gem "xcode-install"
to our Gemfile
, as we can sometimes have issues selecting Xcode from CI.
source "https://rubygems.org"
gem "fastlane"
gem "xcode-install"
Then update our Fastfile
to have the following
default_platform(:ios)
xcversion(version: "~> 12.2.0")
platform :ios do
desc "Runs iOS tests"
lane :tests do
run_tests(scheme: "websocket-starscreams-ios-application", devices: "iPhone 11")
end
end
To run the tests locally, run the following.
bundle exec fastlane tests
Linter: we use the following linter link.
Uploading Artifacts: we use the following way to upload Artifacts, they allow you to persist data like test results after a job has completed, see the following documentation link.
Creating images/icons: we use Figma to create images and icon. Figma makes it very easy to create designs in many different formats.
Creating a Mock Server: we use a mock server with Postman to quickly test apis, to see how to create a mock server, see the following video link.
Fastlane: Fastlane allows us to automate our development and release process link.
App Center: App Center is used to distribute an app, making it very easy to test on a physical device by using a fastlane plugin link.
Proxyman: we use Proxyman to view HTTP/HTTPS requests as they happen, it is easier to debug network connections on mobile on Proxyman where we can test and mock specific network responses, see the following documentation link.
Npm: How to update a npm package.
- link.
Gemfile: How to update a Gemfile package.
- link.
How to manage releases in a repository link.
The following link brings you to the Starscream
repo which we use for Websocket connections on iOS.
- link.
The following link is a good tutorial on how use Websockets on iOS with Starscream
- link.