kraken-mobile 1.0.5 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a62f2fa104aef33dbd29eeb781a1af75ebeac4306038023d6fc1abd51235a5c
4
- data.tar.gz: 9d3b50a9fa14ccb8e411ff760733be78f91b856e0f99805b24f67c837b0e03c4
3
+ metadata.gz: 1b00ad0b9cbfa1874a61ff9285fddf9616901c2e99db685b9fcfa05099bba3d6
4
+ data.tar.gz: 9370f8c54723f070282457dfca37a51bd4e4522fcc94ba14bb38f401b2db7fb2
5
5
  SHA512:
6
- metadata.gz: 0ef9c9887cdd96ea1fd702c93c1ca7ebaf98a889328927f8834e76a0f47a6f36a40d6d46617e765db1b7f51f1a38792db8d2796d6dd4a1157539236dbe7e38f9
7
- data.tar.gz: 0a91cd009596a0adc065b72eafaff018e65797ad79bcdcadf03ba41bc530e871a7de736b00c4572d1cd0f776386e3be1b00a245c44773122d4dfc5a795c8e020
6
+ metadata.gz: 7f9f6c735b8cfc759b6f9b8dec02bf833b4abe3fe8f450647af3303e4e9c7e3d9634e49b524b9931d6f6ecba31b00e64453b6b1d0b0a9a97ce3057433225d567
7
+ data.tar.gz: cf4c0fc443b23308a2c226e9523c39a178144cae805a5751ef0256a31840002f15521361e930ff02d4144e0e5345b0b6139b2dbf1added31ec1bf61eb25d8731
data/README.md CHANGED
@@ -1,10 +1,8 @@
1
1
  <p align="center">
2
2
  <img src="./reporter/assets/images/kraken.png" alt="kraken logo" width="140" height="193">
3
+ <h1 align="center">Kraken</h1>
3
4
 
4
-
5
- <h1 align="center">Kraken Mobile</h1>
6
-
7
- Kraken is an open source automated android E2E testing tool that supports and validates scenarios that involve the inter-communication between two or more users. It works in a Black Box manner meaning that it is not required to have access to the source code of the application but instead it can be run with the APK (Android package file format). Kraken uses signaling for coordinating the communication between the devices using a file based protocol.
5
+ Kraken is an open source automated android and web E2E testing tool that supports and validates scenarios that involve the inter-communication between two or more users. It works in a Black Box manner meaning that it is not required to have access to the source code of the application but instead it can be run with the APK (Android package file format) and web page URL. Kraken uses signaling for coordinating the communication between the devices using a file based protocol.
8
6
 
9
7
  **Kraken is partially supported by a Google Latin America Research Award (LARA) 2018**
10
8
 
@@ -13,26 +11,36 @@ Kraken is an open source automated android E2E testing tool that supports and va
13
11
 
14
12
  # Publications
15
13
 
16
- - _"Kraken-Mobile: Cross-Device Interaction-based Testing of Android Apps"_, [William Ravelo-Méndez](https://ravelinx22.github.io/), [Camilo Escobar-Velásquez](https://caev03.github.io), and [Mario Linares-Vásquez](https://profesores.virtual.uniandes.edu.co/mlinaresv/en/inicio-en/), _Proceedings of the 35th IEEE International Conference on Software Maintenance and Evolution ([ICSME'19](https://icsme2019.github.io/))_, Tool Demo Track, Cleveland, OH, USA, September 30th - October 4th, 2019, to appear 4 pages (52% Acceptance Rate) [[pdf](https://thesoftwaredesignlab.github.io/KrakenMobile/assets/pdfs/icsme19.pdf)][[bibtex](https://thesoftwaredesignlab.github.io/KrakenMobile/assets/pdfs/icsme19.bib)]
14
+ - *“Kraken-Mobile: Cross-Device Interaction-based Testing of Android Apps”*, [William Ravelo-Méndez](https://ravelinx22.github.io/), [Camilo Escobar-Velásquez](https://caev03.github.io/), and [Mario Linares-Vásquez](https://profesores.virtual.uniandes.edu.co/mlinaresv/en/inicio-en/), *Proceedings of the 35th IEEE International Conference on Software Maintenance and Evolution ([ICSME19](https://icsme2019.github.io/))*, Tool Demo Track, Cleveland, OH, USA, September 30th - October 4th, 2019, to appear 4 pages (52% Acceptance Rate) [[pdf](https://thesoftwaredesignlab.github.io/KrakenMobile/assets/pdfs/icsme19.pdf)][[bibtex](https://thesoftwaredesignlab.github.io/KrakenMobile/assets/pdfs/icsme19.bib)]
17
15
 
18
16
  # Technologies
19
17
 
20
- Kraken uses [calabash-android](https://github.com/calabash/calabash-android) for running automated E2E tests in each device or emulator and [cucumber](https://github.com/cucumber/cucumber-ruby) for running your feature files written with Gherkin sintax.
21
-
18
+ Kraken uses [calabash-android](https://github.com/calabash/calabash-android) and [selenium-webdriver](https://github.com/SeleniumHQ/selenium) for running automated E2E tests in each device or emulator and [cucumber](https://github.com/cucumber/cucumber-ruby) for running your feature files written with Gherkin sintax.
22
19
 
23
- # Installation
20
+ # 🔨 Installation
24
21
 
25
22
  ### Prerequisites
26
23
 
27
- Kraken requires Ruby 2.20 or higher but we recommend using ~2.3 version. We use calabash-android as runner, you can check their prerequisites at this [link](https://github.com/calabash/calabash-android/blob/master/documentation/installation.md). Installing and managing a Gem is done through the gem command. To install Kraken's gem run the following command.
24
+ Kraken requires Ruby 2.20 or higher but we recommend using ~2.3 version. We use calabash-android for mobile testing, you can check their prerequisites at this [link](https://github.com/calabash/calabash-android/blob/master/documentation/installation.md). For web testing we use selenium-webdriver, you can check their prerequisites as well at this [link](https://www.selenium.dev/selenium/docs/api/rb/).
25
+
26
+ - Ruby at least version 2.3.1
27
+ - Java JDK
28
+ - Android SDK
29
+ - Chromedriver (Version ~83 recommended) or Geckodriver (Only if you use Kraken web)
30
+
31
+ You need to have configured ANDROID_HOME, ANDROID_HOME/platform_tools and JAVA_HOME in your environment variables.
28
32
 
29
- ```shell
33
+ Installing and managing Kraken Gem is done through the gem command. To install Kraken’s gem run the following command.
34
+
35
+ ```
30
36
  $ gem install kraken-mobile
31
37
  ```
32
38
 
39
+ NOTE: If you are having trouble running Kraken in your Windows operating system refer to the this [guide](https://github.com/TheSoftwareDesignLab/KrakenMobile/blob/master/docs/WINDOWS_GUIDE.md) specifying steps to solve this issues.
40
+
33
41
  # Signaling
34
42
 
35
- Signaling is a protocol used for the communication of two or more devices running in parallel. It is based in the idea that each emulator or real device has a communication channel where he can receive signals sent from other devices which contain information or actions that are supposed to be executed. This type of protocol is commonly used in automated mobile E2E testing tools that validate scenarios involving the inter-communication and collaboration of two or more applications.
43
+ Signaling is a protocol used for the communication of two or more devices running in parallel. It is based in the idea that each browser, emulator or real device has a communication channel where he can receive signals sent from other devices which contain information or actions that are supposed to be executed. This type of protocol is commonly used in automated mobile E2E testing tools that validate scenarios involving the inter-communication and collaboration of two or more applications.
36
44
 
37
45
  # Writing your first test
38
46
 
@@ -47,19 +55,24 @@ features
47
55
  | |_app_life_cycle_hooks.rb
48
56
  | |_env.rb
49
57
  |_step_definitions
50
- | |_kraken_steps.rb
58
+ | |_mobile_steps.rb
59
+ |_web
60
+ | |_step_definitions
61
+ | | |_web_steps.rb
62
+ | |_support
63
+ | | |_app_life_cycle_hooks.rb
51
64
  |_my_first.feature
52
65
  ```
53
66
 
54
67
  ### Write a test
55
68
 
56
- The features goes in the features foler and should have the ".feature" extension. You can start out by looking at `features/my_first.feature`. You should also check calabash [predefined steps](https://github.com/calabash/calabash-android/blob/master/ruby-gem/lib/calabash-android/canned_steps.md).
69
+ The features goes in the features foler and should have the “.feature extension. You can start out by looking at `features/my_first.feature`. You should also check calabash [predefined steps](https://github.com/calabash/calabash-android/blob/master/ruby-gem/lib/calabash-android/canned_steps.md).
57
70
 
58
71
  ### Syntax
59
72
 
60
73
  In Kraken each feature is a test and each scenario within a feature is a test case that is run in a device. Each device is identified as an user and numbered from 1 to N. Ex: @user1, @user2, @user3. To check what is the number of a given device you should run `kraken-mobile devices`.
61
74
 
62
- ```shell
75
+ ```
63
76
  List of devices attached
64
77
  user1 - emulator-5554 - Android_SDK_built_for_x86
65
78
  user2 - emulator-5556 - Android_SDK_built_for_x86
@@ -67,9 +80,9 @@ user2 - emulator-5556 - Android_SDK_built_for_x86
67
80
 
68
81
  After identifying what number each device has, you can write your test case giving each scenario the tag of a given device like so:
69
82
 
70
- ```Gherkin
83
+ ```
71
84
  Feature: Example feature
72
-
85
+
73
86
  @user1
74
87
  Scenario: As a first user I say hi to a second user
75
88
  Given I wait
@@ -88,9 +101,11 @@ Kraken offers two main steps to help synchronizing your devices.
88
101
  ### Signaling steps
89
102
 
90
103
  To wait for a signal coming from another device for 10 seconds that is Kraken default timeout use the following step.
104
+
91
105
  ```
92
106
  Then /^I wait for a signal containing "([^\"]*)"$/
93
107
  ```
108
+
94
109
  To wait for a signal coming from another device for an specified number of seconds use the following step
95
110
 
96
111
  ```
@@ -105,34 +120,120 @@ Then /^I send a signal to user (\d+) containing "([^\"]*)"$/
105
120
 
106
121
  ### Signaling functions
107
122
 
108
- Kraken internal implementation of the signaling steps use the following functions.
123
+ Each device has an internal Kraken implementation of the signaling steps using the following functions.
109
124
 
110
- ```ruby
111
- readSignal(channel, content, timeout)
125
+ ```
126
+ read_signal(content, time_out)
112
127
  ```
113
128
 
114
- Waits for a signal with the specified content in the channel passed by parameter. This functions waits for the specified number of seconds in the timeout parameter before throwing an exception.
115
-
116
- **Note: The channel parameter has to be the number of a device such as @user1, @user2, @userN**
129
+ Waits for a signal with the specified content. This functions waits for the specified number of seconds in the timeout parameter before throwing an exception if specified.
117
130
 
118
- ```ruby
119
- writeSignal(channel, content)
131
+ ```
132
+ write_signal(signal)
120
133
  ```
121
134
 
122
- Writes content to a channel passed by parameter.
135
+ Writes signal content to a device inbox.
123
136
 
124
- **Note: The channel parameter has to be the number of a device such as @user1, @user2, @userN**
137
+ # 📱Kraken Mobile
125
138
 
126
- # Running your tests
139
+ ## Running your tests
127
140
 
128
141
  To run your test:
129
142
 
130
- ```shell
143
+ ```
131
144
  $ kraken-mobile run <apk>
132
145
  ```
133
146
 
134
147
  Kraken with the help of Calabash-Android will install an instrumentation along with your app and will start your tests in all devices connected (Check Kraken Settings section in order to learn how to specify in what devices your tests should be run).
135
148
 
149
+ ## 🦍 Mobile Monkey execution
150
+
151
+ Kraken offers the possibility of generating random GUI events by using Android ADB monkey as well as its own implementation based in the idea of sending and reading random signals.
152
+
153
+ ### Android’s ADB Monkey
154
+
155
+ To execute ADB monkey Kraken offers the following command specifying the number of events to be executed:
156
+
157
+ ```
158
+ Then I start a monkey with (\d+) events
159
+ ```
160
+
161
+ ### Kraken’s own monkey
162
+
163
+ Kraken extended the ADB monkey behavior by executing GUI events only in buttons and clickable views or inputs by offering the following command:
164
+
165
+ ```
166
+ Then I start kraken monkey with (\d+) events
167
+ ```
168
+
169
+ ## XML snapshot
170
+
171
+ Kraken makes it possible to save the XML presented by the current view in a specific device, this is convenient to identify view ids, asserting the correct XML is presented after an action has being completed or running static analyzing tools.
172
+
173
+ ### Saving the snapshot
174
+
175
+ To save the snapshot of the current view, Kraken offers the following step specifying where the file is going to be saved:
176
+
177
+ ```
178
+ Then I save device snapshot in file with path "([^\"]*)"
179
+ ```
180
+
181
+ # 🌎 Kraken Web
182
+
183
+ Kraken is extended to run also in web browsers and orchestrate the communication with other browsers running different websites or mobile applications that are being executed on physical devices or emulators. With the help of ChromeDriver/Geckodriver, selenium-webdriver and Cucumber we run test scenarios using Gherkin syntax as well as Kraken predefined signaling steps described before.
184
+
185
+ ## Specifying a web user in a test
186
+
187
+ To specify that user is going to be run in a web browser instead of a mobile device you need to tag the scenario with @web. If a scenario is not tagged with @web Kraken will assume that is a mobile user and will attempt to run all steps in a mobile manner.
188
+
189
+ ```bash
190
+ Feature: Example feature
191
+
192
+ @user1 @web
193
+ Scenario: As a first user I say hi to a second user
194
+ Given I navigate to page "https://www.gmail.com/"
195
+ Then I send a signal to user 2 containing "hi"
196
+
197
+ @user2 @web
198
+ Scenario: As a second user I wait for user 1 to say hi
199
+ Given I wait for a signal containing "hi"
200
+ Then I navigate to page "https://www.gmail.com/"
201
+ ```
202
+
203
+ This scenario will open two web browsers and execute the signaling between them.
204
+
205
+ ## Web steps
206
+
207
+ To see a list of all web steps available in Kraken, visit the following [link.](https://github.com/TheSoftwareDesignLab/KrakenMobile/blob/master/docs/WEB_STEPS.md)
208
+
209
+ ## Executing web only scenarios
210
+
211
+ To run a test that only contains web users and as a result does not require an APK file, run the following command:
212
+
213
+ ```
214
+ $ kraken-mobile run
215
+ ```
216
+
217
+ Kraken with the help of selenium-webdriver will start all required browsers and run your test scenario.
218
+
219
+ ## Specifying in what browser Kraken will run
220
+
221
+ Kraken uses ChromeDriver and Chrome as default web browser but provides support for Firefox and Geckodriver. To specify that your test is going to be run in Firefox, specify the environment variable BROWSER when running your tests as follows:
222
+
223
+ ```bash
224
+ $ BROWSER=firefox kraken-mobile run
225
+ ```
226
+
227
+ **Note: Make sure that you have Geckodriver and Firefox installed previously.**
228
+
229
+ ## 🦍 Web Monkey execution
230
+
231
+ Kraken has implemented it's own monkey behavior by executing random GUI events in buttons, clickable views and inputs by offering the following command:
232
+
233
+ ```
234
+ Then I start kraken monkey with (\d+) events
235
+ ```
236
+
136
237
  # Kraken Settings
137
238
 
138
239
  Kraken uses kraken_mobile_settings.json to specify in what devices the tests should be run.
@@ -141,16 +242,20 @@ Kraken uses kraken_mobile_settings.json to specify in what devices the tests sho
141
242
 
142
243
  The following command will show you the available connected devices or emulators and let you choose which ones you want to use.
143
244
 
144
- ```shell
245
+ ```
145
246
  $ kraken-mobile setup
146
247
  ```
147
248
 
148
249
  ### Run tests with settings file
149
250
 
150
- ``` shell
251
+ ```
151
252
  $ kraken-mobile run <apk> --configuration=<kraken_mobile_settings_path>
152
253
  ```
153
254
 
255
+ # 🗯 Extended Kraken functionalities
256
+
257
+ In the following sections we provide specification for shared functionality between Kraken mobile and web as well as some examples of Kraken in action.
258
+
154
259
  # Properties file
155
260
 
156
261
  Kraken uses properties files to store sensitive data such as passwords or api keys that should be used in your test cases.
@@ -159,22 +264,22 @@ Kraken uses properties files to store sensitive data such as passwords or api ke
159
264
 
160
265
  The properties files should be a manually created JSON file with the following structure.
161
266
 
162
- ```json
267
+ ```
163
268
  {
164
- "@user1": {
165
- "PASSWORD": "test"
166
- },
167
- "@user2": {
168
- "PASSWORD": "test2"
169
- }
269
+ "@user1": {
270
+ "PASSWORD": "test"
271
+ },
272
+ "@user2": {
273
+ "PASSWORD": "test2"
274
+ }
170
275
  }
171
276
  ```
172
-
277
+
173
278
  ### Use properties file in your test
174
279
 
175
280
  You can use the specified properties using the following sintax.
176
281
 
177
- ```Gherkin
282
+ ```
178
283
  @user1
179
284
  Scenario: As a user
180
285
  Given I wait
@@ -191,17 +296,17 @@ kraken-mobile run <apk> --properties=<kraken_mobile_properties_path>
191
296
 
192
297
  Kraken offers a Fake string generator thanks to the Ruby gem [Faker](https://github.com/faker-ruby/faker), the list of supported faker types are listed as follows:
193
298
 
194
- * Name
195
- * Number
196
- * Email
197
- * String
198
- * String Date
299
+ - Name
300
+ - Number
301
+ - Email
302
+ - String
303
+ - String Date
199
304
 
200
305
  ### Use a faker in a test
201
306
 
202
- Kraken keeps a record of every Fake string generated, thats why each string will have an id associated. To generate a Faker string you need to follow the structure "$FAKERNAME_ID".
307
+ Kraken keeps a record of every Fake string generated, thats why each string will have an id associated. To generate a Faker string you need to follow the structure “$FAKERNAME_ID”.
203
308
 
204
- ```Gherkin
309
+ ```
205
310
  @user1
206
311
  Scenario: As a user
207
312
  Given I wait
@@ -212,7 +317,7 @@ Scenario: As a user
212
317
 
213
318
  As mentioned before, Kraken keeps record of every string generated with an id given to each string, this gives you the possibility of reusing this string later in your scenario. To reuse a string you can you need to append a $ character to the fake string as follows:
214
319
 
215
- ```Gherkin
320
+ ```
216
321
  @user1
217
322
  Scenario: As a user
218
323
  Given I wait
@@ -223,15 +328,16 @@ Scenario: As a user
223
328
 
224
329
  # Examples
225
330
 
226
- | Application | Video | Feature File | Properties file | Settings File | Report Link |
227
- |:-------------|:-------------|:------------------|:-------|:-------|:-------|
228
- | Infinite Words | [video](https://www.youtube.com/watch?v=4lX7mO80w-4&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=3&t=0s)|[.feature](../gh-pages/examples/infinite-words/infinite_words.feature) | --- | --- | [report](../gh-pages/examples/infinite-words/report/index.html) |
229
- | QuizUp | [video](https://www.youtube.com/watch?v=2mhZVTK0r6k&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=4&t=1s) | [.feature](../gh-pages/examples/quizup/quizup.feature) | --- | --- | [report](../gh-pages/examples/quizup/report/index.html) |
230
- | Spotify/Shazam | [video](https://www.youtube.com/watch?v=7AKsfY1KFX0&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=5&t=0s) | [.feature](../gh-pages/examples/shazam/shazam.feature) | [.json](../gh-pages/examples/shazam/kraken_properties.json) | [.json](../gh-pages/examples/shazam/kraken_mobile_settings.json) | [report](../gh-pages/examples/shazam/report/index.html) |
231
- | Spunky | [video](https://www.youtube.com/watch?v=WOhRWkdFaVk&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=6&t=25s) | [.feature](../gh-pages/examples/spunky/spunky.feature) | --- | --- | [report](../gh-pages/examples/spunky/report/index.html) |
232
- | Picap | [video](https://www.youtube.com/watch?v=RozQrmH_Z5k&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=7&t=3s) | [.feature](../gh-pages/examples/picap/picap.feature) | [.json](../gh-pages/examples/picap/kraken_properties.json) | --- | [report](../gh-pages/examples/picap/report/index.html) |
233
- | AskFM | [video](https://www.youtube.com/watch?v=d9Gbdx8kFX8&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=8&t=0s) | [.feature](../gh-pages/examples/askfm/askfm.feature) | --- | --- | [report](../gh-pages/examples/askfm/report/index.html) |
234
- | Stick Men Fight | [video](https://www.youtube.com/watch?v=36OJKNj0nSo&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=9&t=4s) | [.feature](../gh-pages/examples/stick/stick.feature) | --- | --- | [report](../gh-pages/examples/stick/report/index.html) |
235
- | Tic Tac Toe | [video](https://www.youtube.com/watch?v=F9pDJDYsL_w&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=10&t=2s) | [.feature](../gh-pages/examples/tictactoe/tictactoe.feature) | --- | --- | [report](../gh-pages/examples/tictactoe/report/index.html) |
236
- | Tumblr | [video](https://www.youtube.com/watch?v=eqFej2uJz4k&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=11&t=3s) | [.feature](../gh-pages/examples/tumblr/tumblr.feature) | [.json](../gh-pages/examples/tumblr/kraken_properties.json) | --- | [report](../gh-pages/examples/tumblr/report/index.html) |
237
- | F3 | [video](https://www.youtube.com/watch?v=vESh6Jyp-so&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=12&t=0s) | [.feature](../gh-pages/examples/f3/f3.feature) | [.json](../gh-pages/examples/f3/kraken_properties.json) | --- | [report](../gh-pages/examples/f3/report/index.html) |
331
+
332
+ | Application | Video | Feature File | Steps Definition | Properties file | Settings File | Report Link |
333
+ |:-------------|:-------------|:-------------|:------------------|:-------|:-------|:-------|
334
+ | Infinite Words | [video](https://www.youtube.com/watch?v=4lX7mO80w-4&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=3&t=0s)|[.feature](/examples/infinite-words/infinite_words.feature)|--- | --- | --- | [report](/examples/infinite-words/report/index.html) |
335
+ | QuizUp | [video](https://www.youtube.com/watch?v=2mhZVTK0r6k&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=4&t=1s) | [.feature](/examples/quizup/quizup.feature)|[stepsDef](../gh-pages/examples/quizup/step_definitions/kraken_steps.rb) | --- | --- | [report](/examples/quizup/report/index.html) |
336
+ | Spotify/Shazam | [video](https://www.youtube.com/watch?v=7AKsfY1KFX0&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=5&t=0s) | [.feature](/examples/shazam/shazam.feature)|[stepsDef](../gh-pages/examples/shazam/step_definitions/kraken_steps.rb) | [.json](/examples/shazam/kraken_properties.json) | [.json](/examples/shazam/kraken_mobile_settings.json) | [report](/examples/shazam/report/index.html) |
337
+ | Spunky | [video](https://www.youtube.com/watch?v=WOhRWkdFaVk&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=6&t=25s) | [.feature](/examples/spunky/spunky.feature)|[stepsDef](../gh-pages/examples/spunky/step_definitions/kraken_steps.rb) | --- | --- | [report](/examples/spunky/report/index.html) |
338
+ | Picap | [video](https://www.youtube.com/watch?v=RozQrmH_Z5k&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=7&t=3s) | [.feature](/examples/picap/picap.feature)|[stepsDef](../gh-pages/examples/picap/step_definitions/kraken_steps.rb) | [.json](/examples/picap/kraken_properties.json) | --- | [report](/examples/picap/report/index.html) |
339
+ | AskFM | [video](https://www.youtube.com/watch?v=d9Gbdx8kFX8&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=8&t=0s) | [.feature](/examples/askfm/askfm.feature)|[stepsDef](../gh-pages/examples/askfm/step_definitions/kraken_steps.rb) | --- | --- | [report](/examples/askfm/report/index.html) |
340
+ | Stick Men Fight | [video](https://www.youtube.com/watch?v=36OJKNj0nSo&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=9&t=4s) | [.feature](/examples/stick/stick.feature)|--- | --- | --- | [report](/examples/stick/report/index.html) |
341
+ | Tic Tac Toe | [video](https://www.youtube.com/watch?v=F9pDJDYsL_w&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=10&t=2s) | [.feature](/examples/tictactoe/tictactoe.feature)|[stepsDef](../gh-pages/examples/tictactoe/step_definitions/kraken_steps.rb) | --- | --- | [report](/examples/tictactoe/report/index.html) |
342
+ | Tumblr | [video](https://www.youtube.com/watch?v=eqFej2uJz4k&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=11&t=3s) | [.feature](/examples/tumblr/tumblr.feature)|[stepsDef](../gh-pages/examples/tumblr/step_definitions/kraken_steps.rb) | [.json](/examples/tumblr/kraken_properties.json) | --- | [report](/examples/tumblr/report/index.html) |
343
+ | F3 | [video](https://www.youtube.com/watch?v=vESh6Jyp-so&list=PLF5U8kfVgRcJ3RCHt7cWmwlqN93brbVW-&index=12&t=0s) | [.feature](/examples/f3/f3.feature)|[stepsDef](../gh-pages/examples/f3/step_definitions/kraken_steps.rb) | [.json](/examples/f3/kraken_properties.json) | --- | [report](/examples/f3/report/index.html) |
data/bin/kraken-mobile CHANGED
@@ -62,13 +62,22 @@ else
62
62
  when 'setup'
63
63
  KrakenSetup.new.run
64
64
  when 'gen'
65
+ ensure_java_installed
66
+ ensure_android_sdk_installed
67
+
65
68
  scaffold_folder_structure
66
69
  when 'resign'
70
+ ensure_java_installed
71
+ ensure_android_sdk_installed
72
+
67
73
  require 'calabash-android/helpers'
68
74
  puts 'Resigning APK with Calabash-Android'
69
75
  ensure_apk_is_specified
70
76
  resign_apk(user_entered_apk_path)
71
77
  when 'run'
78
+ ensure_java_installed
79
+ ensure_android_sdk_installed
80
+
72
81
  require File.join(File.dirname(__FILE__), 'kraken_mobile_calabash_android')
73
82
  configuration = read_configuration
74
83
  user_entered_properties_path = read_user_entered_properties_path
@@ -89,3 +89,19 @@ def ensure_properties_is_valid(properties)
89
89
  puts 'The path of the properties file is not valid.'
90
90
  exit 1
91
91
  end
92
+
93
+ def ensure_android_sdk_installed
94
+ return unless ENV['ANDROID_HOME'].nil?
95
+
96
+ puts 'To use Kraken you need to have installed Android SDK first. '\
97
+ 'Make sure you have the environment variable ANDROID_HOME configured'
98
+ exit 1
99
+ end
100
+
101
+ def ensure_java_installed
102
+ return unless ENV['ANDROID_HOME'].nil?
103
+
104
+ puts 'To use Kraken you need to have installed Java first.'\
105
+ 'Make sure you have the environment variable JAVA_HOME configured'
106
+ exit 1
107
+ end
@@ -1,9 +1,11 @@
1
1
  require 'io/console'
2
2
  require 'tty-prompt'
3
+ $LOAD_PATH << File.expand_path('../lib', __dir__)
4
+ require 'kraken-mobile/utils/k.rb'
3
5
 
4
6
  class KrakenSetup
5
7
  WEB_IDENTIFIER = 'Web'.freeze
6
- IS_WEB_AVAILABLE_FOR_SELECTION = false
8
+ IS_WEB_AVAILABLE_FOR_SELECTION = true
7
9
 
8
10
  attr_accessor :prompt
9
11
  attr_accessor :devices_connected_id
@@ -85,6 +87,7 @@ class KrakenSetup
85
87
  @settings[user_id] = {
86
88
  id: device_id,
87
89
  model: device.model,
90
+ type: K::ANDROID_DEVICE,
88
91
  config: {
89
92
  apk_path: apk
90
93
  }
@@ -96,6 +99,7 @@ class KrakenSetup
96
99
  @settings[user_id] = {
97
100
  id: device.id,
98
101
  model: device.model,
102
+ type: K::WEB_DEVICE,
99
103
  config: {}
100
104
  }
101
105
  end
@@ -1,3 +1,5 @@
1
+ require 'fileutils'
2
+
1
3
  # Abstract class
2
4
  class DeviceProcess
3
5
  attr_accessor :id
@@ -43,12 +45,40 @@ class DeviceProcess
43
45
  end
44
46
  end
45
47
 
48
+ def unregister_process_from_directory
49
+ File.open(K::DIRECTORY_PATH, 'r') do |f|
50
+ File.open("#{K::DIRECTORY_PATH}.tmp", 'w') do |f2|
51
+ f.each_line do |line|
52
+ f2.write(line) unless line.start_with?(
53
+ "#{id}#{K::SEPARATOR}#{device}"
54
+ )
55
+ end
56
+ end
57
+ end
58
+ FileUtils.mv("#{K::DIRECTORY_PATH}.tmp", K::DIRECTORY_PATH)
59
+ end
60
+
46
61
  def notify_ready_to_start
47
62
  File.open(K::DIRECTORY_PATH, 'a') do |file|
48
63
  file.puts("#{id}#{K::SEPARATOR}#{device}")
49
64
  end
50
65
  end
51
66
 
67
+ def running_on_windows?
68
+ RbConfig::CONFIG['host_os'] =~ /cygwin|mswin|mingw|bccwin|wince|emx/
69
+ end
70
+
71
+ def exporting_command_for_environment_variables(variables = {})
72
+ commands = variables.map do |key, value|
73
+ if running_on_windows?
74
+ "(SET \"#{key}=#{value}\")"
75
+ else
76
+ "#{key}=#{value};export #{key}"
77
+ end
78
+ end
79
+ commands.join(terminal_command_separator)
80
+ end
81
+
52
82
  def self.directory
53
83
  return [] unless File.exist?(K::DIRECTORY_PATH)
54
84
 
@@ -91,4 +121,10 @@ class DeviceProcess
91
121
 
92
122
  devices_ready || []
93
123
  end
124
+
125
+ def terminal_command_separator
126
+ return ' & ' if running_on_windows?
127
+
128
+ ';'
129
+ end
94
130
  end
@@ -1,5 +1,5 @@
1
1
  require 'faker'
2
- require 'kraken-mobile/utils/k'
2
+ require 'kraken-mobile/utils/k.rb'
3
3
  require 'json'
4
4
 
5
5
  class KrakenFaker
@@ -56,6 +56,7 @@ class KrakenFaker
56
56
  absolute_dictionary_path = File.expand_path(K::DICTIONARY_PATH)
57
57
  file = open(absolute_dictionary_path)
58
58
  content = file.read
59
+ file.close
59
60
  JSON.parse(content)
60
61
  end
61
62
 
@@ -26,6 +26,7 @@ module KrakenMobile
26
26
  # Variables
27
27
  report_file = open("#{KrakenMobile::Constants::REPORT_PATH}/#{@execution_id}/#{KrakenMobile::Constants::REPORT_DEVICES_FILE_NAME}.json")
28
28
  content = report_file.read
29
+ report_file.close
29
30
  @devices = JSON.parse(content)
30
31
  devices_report = report_by_devices(@devices)
31
32
  @features_report = fetures_from_report_by_devices devices_report
@@ -45,6 +46,7 @@ module KrakenMobile
45
46
  @apk_path = device.config["apk_path"] ? device.config["apk_path"] : @options[:apk_path]
46
47
  report_file = open("#{KrakenMobile::Constants::REPORT_PATH}/#{@execution_id}/#{device.id}/#{KrakenMobile::Constants::REPORT_FILE_NAME}.json")
47
48
  content = report_file.read
49
+ report_file.close
48
50
  @features = JSON.parse(content)
49
51
  @total_scenarios = total_scenarios @features
50
52
  @device = device
@@ -70,6 +72,7 @@ module KrakenMobile
70
72
  next if !File.exists?("#{KrakenMobile::Constants::REPORT_PATH}/#{@execution_id}/#{device['id']}/#{KrakenMobile::Constants::REPORT_FILE_NAME}.json")
71
73
  report_file = open("#{KrakenMobile::Constants::REPORT_PATH}/#{@execution_id}/#{device['id']}/#{KrakenMobile::Constants::REPORT_FILE_NAME}.json")
72
74
  content = report_file.read
75
+ report_file.close
73
76
  devices_report[device['user']] = JSON.parse(content)
74
77
  devices_report[device['user']].each do |d| d["device_model"] = device["model"] if !d["device_model"] end
75
78
  devices_report[device['user']].each do |d| d["device_id"] = device["id"] if !d["device_id"] end
@@ -1,5 +1,5 @@
1
1
  require 'kraken-mobile/device_process.rb'
2
- require 'kraken-mobile/utils/k'
2
+ require 'kraken-mobile/utils/k.rb'
3
3
 
4
4
  class MobileProcess < DeviceProcess
5
5
  #-------------------------------
@@ -11,6 +11,7 @@ class MobileProcess < DeviceProcess
11
11
  end
12
12
 
13
13
  def after_execute
14
+ unregister_process_from_directory
14
15
  device.delete_inbox
15
16
  end
16
17
 
@@ -42,15 +43,32 @@ class MobileProcess < DeviceProcess
42
43
  private
43
44
 
44
45
  def execution_command
46
+ "|#{environment_variables_command}#{terminal_command_separator}"\
47
+ "#{running_process_command}"
48
+ end
49
+
50
+ def running_process_command
45
51
  feature_path = test_scenario.feature_file.file_path
46
52
  raise 'ERROR: Invalid feature file path' if feature_path.nil?
47
53
 
48
54
  process_apk_path = apk_path
49
55
  raise 'ERROR: Invalid APK file path' if process_apk_path.nil?
50
56
 
51
- "|ADB_DEVICE_ARG=#{device.id} calabash-android run #{process_apk_path} "\
52
- "#{feature_path} --tags @user#{id} --format pretty --format json -o "\
53
- "#{K::REPORT_PATH}/#{@test_scenario.execution_id}/#{device.id}/#{K::FILE_REPORT_NAME}" # TODO, folder to save all things
57
+ "calabash-android run #{process_apk_path} \
58
+ #{feature_path} --tags @user#{id} \
59
+ --require features/support/env.rb \
60
+ --require features/support/app_installation_hooks.rb \
61
+ --require features/support/app_life_cycle_hooks.rb \
62
+ --require features/step_definitions/mobile_steps.rb \
63
+ --format pretty --format json -o \
64
+ #{K::REPORT_PATH}/#{@test_scenario.execution_id}/#{device.id}/#{K::FILE_REPORT_NAME}"
65
+ end
66
+
67
+ def environment_variables_command
68
+ variables = {
69
+ ADB_DEVICE_ARG: device.id
70
+ }
71
+ exporting_command_for_environment_variables(variables)
54
72
  end
55
73
 
56
74
  #-------------------------------
@@ -61,6 +79,7 @@ class MobileProcess < DeviceProcess
61
79
  config_absolute_path = File.expand_path(ENV[K::CONFIG_PATH])
62
80
  file = open(config_absolute_path)
63
81
  content = file.read
82
+ file.close
64
83
  JSON.parse(content)[@id.to_s] || {}
65
84
  end
66
85
 
@@ -22,24 +22,49 @@ class FeatureFile
22
22
  #-------------------------------
23
23
  # Helpers
24
24
  #-------------------------------
25
- def number_of_required_mobile_devices
25
+ def user_tags
26
26
  all_tags = @scenarios.map(&:tags).flatten.uniq
27
- mobile_tagged_count = all_tags.select { |tag| tag == '@mobile' }.count
28
- empty_tagged_scenarios = @scenarios.select do |scenario|
29
- !scenario.tags.include?('@mobile') &&
30
- !scenario.tags.include?('@web')
27
+ all_tags.select { |tag| tag.start_with?('@user') }
28
+ end
29
+
30
+ def system_tags
31
+ @scenarios.map do |scenario|
32
+ tags = scenario.tags
33
+ system_tag = tags.select do |tag|
34
+ tag.start_with?('@web') || tag.start_with?('@mobile')
35
+ end.first
36
+ system_tag || '@mobile'
31
37
  end
32
- mobile_tagged_count + empty_tagged_scenarios.count
38
+ end
39
+
40
+ def number_of_required_mobile_devices
41
+ system_tags.select { |tag| tag == '@mobile' }.count
33
42
  end
34
43
 
35
44
  def number_of_required_web_devices
36
- all_tags = @scenarios.map(&:tags).flatten.uniq
37
- all_tags.select { |tag| tag == '@web' }.count
45
+ system_tags.select { |tag| tag == '@web' }.count
38
46
  end
39
47
 
40
48
  def number_of_required_devices
41
- all_tags = @scenarios.map(&:tags).flatten.uniq
42
- all_tags.select { |tag| tag.start_with?('@user') }.count
49
+ user_tags.count
50
+ end
51
+
52
+ def required_devices
53
+ users = user_tags
54
+ systems = system_tags
55
+
56
+ users.map do |user|
57
+ {
58
+ user_id: user.delete_prefix('@user'),
59
+ system_type: systems.shift || '@mobile'
60
+ }
61
+ end
62
+ end
63
+
64
+ def sorted_required_devices
65
+ required_devices.sort_by do |device|
66
+ device[:user_id].to_i
67
+ end
43
68
  end
44
69
 
45
70
  def tags_for_user_id(user_id)
@@ -95,7 +120,9 @@ class FeatureFile
95
120
 
96
121
  def read_content
97
122
  parser = Gherkin::Parser.new
98
- file_content = File.open(file_path).read
123
+ file = File.open(file_path)
124
+ file_content = file.read
125
+ file.close
99
126
  gherkin_document = parser.parse(file_content)
100
127
  pickles = Gherkin::Pickles::Compiler.new.compile(gherkin_document)
101
128
  pickles.each do |scenario|
@@ -5,7 +5,8 @@ class WebDevice < Device
5
5
  # Signaling
6
6
  #-------------------------------
7
7
  def create_inbox
8
- File.open(inbox_file_path, 'w')
8
+ file = File.open(inbox_file_path, 'w')
9
+ file.close
9
10
  end
10
11
 
11
12
  def delete_inbox
@@ -80,7 +81,9 @@ class WebDevice < Device
80
81
  end
81
82
 
82
83
  def inbox_last_signal
83
- lines = File.open(inbox_file_path).to_a
84
+ file = File.open(inbox_file_path)
85
+ lines = file.to_a
86
+ file.close
84
87
  lines.last&.strip
85
88
  end
86
89
  end
@@ -0,0 +1,63 @@
1
+ require 'selenium-webdriver'
2
+ require 'faker'
3
+
4
+ class WebMonkey
5
+ attr_accessor :driver
6
+ attr_accessor :wait
7
+ DEFAULT_WAIT_TIMEOUT = 0.5
8
+
9
+ def initialize(driver:)
10
+ self.driver = driver
11
+ self.wait = Selenium::WebDriver::Wait.new(timeout: DEFAULT_WAIT_TIMEOUT)
12
+ end
13
+
14
+ # Helpers
15
+ def execute_kraken_monkey(number_of_events)
16
+ number_of_events.times do |_i|
17
+ execute_random_action
18
+ end
19
+ end
20
+
21
+ def execute_random_action
22
+ arr = [
23
+ method(:random_click), method(:insert_random_text)
24
+ ]
25
+ arr.sample.call
26
+ rescue StandardError => _e
27
+ nil
28
+ end
29
+
30
+ def random_click
31
+ element = @wait.until { driver.find_elements(:xpath, '//*').sample }
32
+ highlight_element(element)
33
+ element.click
34
+ remove_element_highlight(element)
35
+ end
36
+
37
+ def insert_random_text
38
+ element = @wait.until { driver.find_elements(:xpath, '//input').sample }
39
+ highlight_element(element)
40
+ element.click
41
+ text = [Faker::Lorem.word, Faker::Lorem.sentence].sample
42
+ element.send_keys(text)
43
+ remove_element_highlight(element)
44
+ end
45
+
46
+ private
47
+
48
+ def highlight_element(element)
49
+ @driver.execute_script(
50
+ "arguments[0].setAttribute('style', arguments[1]);",
51
+ element,
52
+ 'color: red; border: 2px solid red'
53
+ )
54
+ end
55
+
56
+ def remove_element_highlight(element)
57
+ @driver.execute_script(
58
+ "arguments[0].setAttribute('style', arguments[1]);",
59
+ element,
60
+ ''
61
+ )
62
+ end
63
+ end
@@ -9,6 +9,7 @@ ParameterType(
9
9
  s.slice!(">")
10
10
  file = open(ENV["PROPERTIES_PATH"])
11
11
  content = file.read
12
+ file.close
12
13
  properties = JSON.parse(content)
13
14
  raise "Property <#{s}> not found for #{channel}" if !properties[channel] || !properties[channel][s]
14
15
  return properties[channel][s]
@@ -64,6 +64,7 @@ def all_user_properties_as_json
64
64
 
65
65
  file = open(properties_absolute_path)
66
66
  content = file.read
67
+ file.close
67
68
  JSON.parse(content)
68
69
  end
69
70
 
@@ -1,5 +1,5 @@
1
1
  require 'calabash-android/calabash_steps'
2
- require 'kraken-mobile/utils/K'
2
+ require 'kraken-mobile/utils/k.rb'
3
3
  require 'kraken-mobile/models/android_device'
4
4
  require 'kraken-mobile/steps/general_steps'
5
5
 
@@ -1,30 +1,35 @@
1
+ require 'kraken-mobile/monkeys/web/web_monkey'
2
+ require 'kraken-mobile/steps/general_steps'
3
+ require 'kraken-mobile/utils/k.rb'
1
4
  require 'selenium-webdriver'
2
5
  require 'uri'
3
6
 
4
- driver = Selenium::WebDriver.for :chrome
7
+ Before do
8
+ @driver = Selenium::WebDriver.for((ENV['BROWSER'] || 'chrome').to_sym)
9
+ end
5
10
 
6
11
  Given(/^I navigate to page "([^\"]*)"$/) do |web_url|
7
12
  raise 'ERROR: Invalid URL' if web_url.nil?
8
13
  raise 'ERROR: Invalid URL' unless web_url =~ URI::DEFAULT_PARSER.make_regexp
9
14
 
10
- driver.navigate.to web_url
15
+ @driver.navigate.to web_url
11
16
  sleep 2
12
17
  end
13
18
 
14
19
  Then(/^I enter "([^\"]*)" into input field having id "([^\"]*)"$/) do |text, id|
15
- driver.find_element(:id, id).send_keys(text)
20
+ @driver.find_element(:id, id).send_keys(text)
16
21
  sleep 2
17
22
  end
18
23
 
19
24
  Then(
20
25
  /^I enter "([^\"]*)" into input field having css selector "([^\"]*)"$/
21
26
  ) do |text, selector|
22
- driver.find_element(:css, selector).send_keys(text)
27
+ @driver.find_element(:css, selector).send_keys(text)
23
28
  sleep 2
24
29
  end
25
30
 
26
31
  Then(/^I click on element having id "(.*?)"$/) do |id|
27
- driver.find_element(:id, id).click
32
+ @driver.find_element(:id, id).click
28
33
  sleep 2
29
34
  end
30
35
 
@@ -35,7 +40,7 @@ Then(/^I wait for (\d+) seconds$/) do |seconds|
35
40
  end
36
41
 
37
42
  Then(/^I should see text "(.*?)"$/) do |text|
38
- driver.page_source.include?(text)
43
+ @driver.page_source.include?(text)
39
44
  end
40
45
 
41
46
  # Kraken Steps
@@ -73,9 +78,14 @@ Then(
73
78
  device.read_signal(signal, seconds)
74
79
  end
75
80
 
76
- private
81
+ Then(/^I start a monkey with (\d+) events$/) do |number_of_events|
82
+ monkey = WebMonkey.new(driver: @driver)
83
+ monkey.execute_kraken_monkey(number_of_events)
84
+ end
77
85
 
78
- def current_process_id
79
- tag_process_id = @scenario_tags.grep(/@user/).first
80
- tag_process_id.delete_prefix('@user')
86
+ # Hooks
87
+ AfterStep do |_scenario|
88
+ path = "#{ENV[K::SCREENSHOT_PATH]}/#{SecureRandom.hex(12)}.png"
89
+ @driver.save_screenshot(path)
90
+ embed(path, 'image/png', File.basename(path))
81
91
  end
@@ -5,7 +5,7 @@ require 'kraken-mobile/models/web_device'
5
5
  require 'kraken-mobile/web/web_process'
6
6
  require 'kraken-mobile/utils/reporter'
7
7
  require 'kraken-mobile/mobile/adb'
8
- require 'kraken-mobile/utils/k'
8
+ require 'kraken-mobile/utils/k.rb'
9
9
  require 'parallel'
10
10
 
11
11
  class TestScenario
@@ -27,6 +27,9 @@ class TestScenario
27
27
  @kraken_app = kraken_app
28
28
  @execution_id = Digest::SHA256.hexdigest(Time.now.to_f.to_s)
29
29
  @reporter = Reporter.new(test_scenario: self)
30
+
31
+ ensure_apk_specified_if_necessary
32
+ setup_scenario_environment_variables
30
33
  end
31
34
 
32
35
  #-------------------------------
@@ -70,11 +73,12 @@ class TestScenario
70
73
  Parallel.map_with_index(
71
74
  @devices, in_threads: @devices.count
72
75
  ) do |device, index|
73
- user_id = index + 1
74
- start_process_for_user_id_in_device(
75
- user_id,
76
- device
77
- )
76
+ unless device.nil?
77
+ user_id = index + 1
78
+ start_process_for_user_id_in_device(
79
+ user_id, device
80
+ )
81
+ end
78
82
  end
79
83
  end
80
84
 
@@ -135,7 +139,11 @@ class TestScenario
135
139
  def sample_devices
136
140
  return predefined_devices if requires_predefined_devices?
137
141
 
138
- (sample_mobile_devices + sample_web_devices).flatten
142
+ mobile = sample_mobile_devices
143
+ web = sample_web_devices
144
+ @feature_file.sorted_required_devices.map do |device|
145
+ device[:system_type] == '@web' ? web.shift : mobile.shift
146
+ end
139
147
  end
140
148
 
141
149
  def sample_mobile_devices
@@ -181,13 +189,39 @@ class TestScenario
181
189
  config_absolute_path = File.expand_path(ENV[K::CONFIG_PATH])
182
190
  file = open(config_absolute_path)
183
191
  content = file.read
192
+ file.close
184
193
  devices_json = JSON.parse(content).values
185
-
186
194
  devices_json.map do |device_json|
187
- AndroidDevice.new(
188
- id: device_json['id'],
189
- model: device_json['model']
190
- )
195
+ if device_json['type'] == K::ANDROID_DEVICE
196
+ AndroidDevice.new(
197
+ id: device_json['id'], model: device_json['model']
198
+ )
199
+ elsif device_json['type'] == K::WEB_DEVICE
200
+ WebDevice.new(
201
+ id: device_json['id'], model: device_json['model']
202
+ )
203
+ else
204
+ raise 'ERROR: Platform not supported'
205
+ end
191
206
  end
192
207
  end
208
+
209
+ def apk_required?
210
+ sample_mobile_devices.any? && ENV[K::CONFIG_PATH].nil?
211
+ end
212
+
213
+ def ensure_apk_specified_if_necessary
214
+ return unless apk_required?
215
+ return unless @kraken_app&.apk_path.nil?
216
+
217
+ raise 'ERROR: Invalid APK file path'
218
+ end
219
+
220
+ def setup_scenario_environment_variables
221
+ return if @kraken_app.nil? || @reporter.nil?
222
+
223
+ @kraken_app.save_value_in_environment_variable_with_name(
224
+ name: K::SCREENSHOT_PATH, value: @reporter.screenshot_path
225
+ )
226
+ end
193
227
  end
@@ -18,6 +18,7 @@ module K
18
18
  REPORT_PATH = './reports' unless defined? REPORT_PATH
19
19
  FILE_REPORT_NAME = 'report.json' unless defined? FILE_REPORT_NAME
20
20
  D3_DATA_FILE_NAME = 'data.json' unless defined? D3_DATA_FILE_NAME
21
+ SCREENSHOT_PATH = 'SCREENSHOT_PATH' unless defined? SCREENSHOT_PATH
21
22
 
22
23
  unless defined? DEVICES_REPORT_FILE_NAME
23
24
  DEVICES_REPORT_FILE_NAME = 'devices.json'
@@ -1,4 +1,4 @@
1
- require 'kraken-mobile/utils/k'
1
+ require 'kraken-mobile/utils/k.rb'
2
2
  require 'json'
3
3
 
4
4
  class Reporter
@@ -48,6 +48,7 @@ class Reporter
48
48
  "#{K::REPORT_PATH}/#{test_execution_id}/#{K::DEVICES_REPORT_FILE_NAME}"
49
49
  )
50
50
  content = report_file.read
51
+ report_file.close
51
52
  devices_report = report_by_devices
52
53
  @features_report = fetures_from_report_by_devices(devices_report)
53
54
  data_hash = feature_by_nodes_and_links @features_report
@@ -71,6 +72,16 @@ class Reporter
71
72
  end
72
73
 
73
74
  def generate_device_report(device, id)
75
+ if device.is_a? AndroidDevice
76
+ generate_mobile_report(device, id)
77
+ elsif device.is_a? WebDevice
78
+ generate_web_report(device, id)
79
+ else
80
+ raise 'ERROR: Platform not supported'
81
+ end
82
+ end
83
+
84
+ def generate_mobile_report(device, id)
74
85
  process = MobileProcess.new(
75
86
  id: id,
76
87
  device: device,
@@ -79,6 +90,36 @@ class Reporter
79
90
  @apk_path = process.apk_path
80
91
  report_file = open("#{K::REPORT_PATH}/#{test_execution_id}/#{device.id}/#{K::FILE_REPORT_NAME}")
81
92
  content = report_file.read
93
+ report_file.close
94
+ @features = JSON.parse(content)
95
+ @total_scenarios = total_scenarios @features
96
+ @device = device
97
+ @total_failed_scenarios_percentage = total_failed_scenarios_percentage @features
98
+ @total_passed_scenarios_percentage = total_passed_scenarios_percentage @features
99
+ @total_passed_features_percentage = total_passed_features_percentage @features
100
+ @total_failed_features_percentage = total_failed_features_percentage @features
101
+ erb_file = File.join(File.expand_path('../../../../reporter', __FILE__), "feature_report.html.erb")
102
+ html_file = File.join(File.expand_path("#{K::REPORT_PATH}/#{test_execution_id}/#{device.id}/"), File.basename(erb_file, '.erb')) #=>"page.html"
103
+ # Variables
104
+ template = File.read(erb_file)
105
+ result = ERB.new(template).result(binding)
106
+ # write result to file
107
+ File.open(html_file, 'w+') do |f|
108
+ f.write result
109
+ end
110
+ generate_features_report @features, device
111
+ end
112
+
113
+ def generate_web_report(device, id)
114
+ process = WebProcess.new(
115
+ id: id,
116
+ device: device,
117
+ test_scenario: @test_scenario
118
+ )
119
+ @apk_path = nil
120
+ report_file = open("#{K::REPORT_PATH}/#{test_execution_id}/#{device.id}/#{K::FILE_REPORT_NAME}")
121
+ content = report_file.read
122
+ report_file.close
82
123
  @features = JSON.parse(content)
83
124
  @total_scenarios = total_scenarios @features
84
125
  @device = device
@@ -110,6 +151,7 @@ class Reporter
110
151
  def create_report_execution_report_folder
111
152
  Dir.mkdir(K::REPORT_PATH) unless File.exist?(K::REPORT_PATH)
112
153
  Dir.mkdir("#{K::REPORT_PATH}/#{test_execution_id}")
154
+ Dir.mkdir(screenshot_path)
113
155
  FileUtils.cp_r(
114
156
  File.expand_path(K::REPORT_ASSETS_PATH, __FILE__),
115
157
  "#{K::REPORT_PATH}/#{test_execution_id}/"
@@ -134,6 +176,10 @@ class Reporter
134
176
  end
135
177
  end
136
178
 
179
+ def screenshot_path
180
+ "#{K::REPORT_PATH}/#{test_execution_id}/screenshots/"
181
+ end
182
+
137
183
  private
138
184
 
139
185
  def generate_features_report features, device
@@ -170,6 +216,7 @@ class Reporter
170
216
  "#{K::REPORT_PATH}/#{test_execution_id}/#{device[:id]}/#{K::FILE_REPORT_NAME}"
171
217
  )
172
218
  content = report_file.read
219
+ report_file.close
173
220
  devices_report[device[:user]] = JSON.parse(content)
174
221
  devices_report[device[:user]].each do |d| d['device_model'] = device[:model] if !d['device_model'] end
175
222
  devices_report[device[:user]].each do |d| d['device_id'] = device[:id] if !d['device_id'] end
@@ -316,7 +363,7 @@ class Reporter
316
363
  def devices
317
364
  raise 'ERROR: Invalid test scenario' if @test_scenario.nil?
318
365
 
319
- @test_scenario.devices
366
+ @test_scenario.devices.compact
320
367
  end
321
368
 
322
369
  def devices_json
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KrakenMobile
4
- VERSION = '1.0.5'
4
+ VERSION = '1.0.8'
5
5
  end
@@ -10,6 +10,7 @@ class WebProcess < DeviceProcess
10
10
  end
11
11
 
12
12
  def after_execute
13
+ unregister_process_from_directory
13
14
  device.delete_inbox
14
15
  end
15
16
 
@@ -31,9 +32,10 @@ class WebProcess < DeviceProcess
31
32
  feature_path = test_scenario.feature_file.file_path
32
33
  raise 'ERROR: Invalid feature file path' if feature_path.nil?
33
34
 
34
- # TODO, only execute one file
35
- "|cucumber --tags @user#{id}\
35
+ "|cucumber #{feature_path} --tags @user#{id} \
36
36
  --require features/web/step_definitions/web_steps.rb \
37
- --require features/web/support/app_life_cycle_hooks.rb"
37
+ --require features/web/support/app_life_cycle_hooks.rb \
38
+ --format pretty --format json -o \
39
+ #{K::REPORT_PATH}/#{@test_scenario.execution_id}/#{device.id}/#{K::FILE_REPORT_NAME}"
38
40
  end
39
41
  end
data/lib/kraken_mobile.rb CHANGED
@@ -27,17 +27,37 @@ class KrakenApp
27
27
  build_scenarios_queue
28
28
  end
29
29
 
30
- def start
30
+ #-------------------------------
31
+ # Observers
32
+ #-------------------------------
33
+ def on_test_scenario_finished
31
34
  execute_next_scenario
32
35
  end
33
36
 
34
37
  #-------------------------------
35
- # Observers
38
+ # Helpers
36
39
  #-------------------------------
37
- def on_test_scenario_finished
40
+
41
+ def start
38
42
  execute_next_scenario
39
43
  end
40
44
 
45
+ def save_path_in_environment_variable_with_name(name:, path:)
46
+ return if path.nil?
47
+
48
+ absolute_path = File.expand_path(path)
49
+ save_value_in_environment_variable_with_name(
50
+ name: name,
51
+ value: absolute_path
52
+ )
53
+ end
54
+
55
+ def save_value_in_environment_variable_with_name(name:, value:)
56
+ return if name.nil? || value.nil?
57
+
58
+ ENV[name] = value
59
+ end
60
+
41
61
  private
42
62
 
43
63
  def build_scenarios_queue
@@ -58,20 +78,4 @@ class KrakenApp
58
78
  scenario.run
59
79
  scenario
60
80
  end
61
-
62
- def save_path_in_environment_variable_with_name(name:, path:)
63
- return if path.nil?
64
-
65
- absolute_path = File.expand_path(path)
66
- save_value_in_environmant_variable_with_name(
67
- name: name,
68
- value: absolute_path
69
- )
70
- end
71
-
72
- def save_value_in_environmant_variable_with_name(name:, value:)
73
- return if name.nil? || value.nil?
74
-
75
- ENV[name] = value
76
- end
77
81
  end
@@ -175,7 +175,11 @@
175
175
  <%= device.model %> - <%= device.id %>
176
176
  </td>
177
177
  <td>
178
- <i class="fa fa-android fa-lg"><span>android</span></i>
178
+ <% if device.type == K::ANDROID_DEVICE %>
179
+ <i class="fa fa-android fa-lg"><span>android</span></i>
180
+ <% else %>
181
+ <i class="fa fa-globe fa-lg"><span>web</span></i>
182
+ <% end %>
179
183
  </td>
180
184
  <td>
181
185
  <%= @apk_path %>
@@ -599,12 +599,18 @@
599
599
  <div class="ui-card col-md-3">
600
600
  <div class="container device-container">
601
601
  <div class="row device-os-icon">
602
- <i class="fa fa-android fa-lg"></i>
602
+ <% if device[:type] == K::ANDROID_DEVICE %>
603
+ <i class="fa fa-android fa-lg"></i>
604
+ <% else %>
605
+ <i class="fa fa-globe fa-lg"></i>
606
+ <% end %>
603
607
  </div>
604
608
  <div class="row device-title"><%= device[:model] %></div>
605
609
  <div class="row device-info">ID - <%= device[:id] %></div>
606
- <div class="row device-info">SDK Version - <%= device[:sdk] %></div>
607
- <div class="row device-info">Screen Size - <%= "#{device[:screen_height]}x#{device[:screen_width]}" %></div>
610
+ <% if device[:type] == K::ANDROID_DEVICE %>
611
+ <div class="row device-info">SDK Version - <%= device[:sdk] %></div>
612
+ <div class="row device-info">Screen Size - <%= "#{device[:screen_height]}x#{device[:screen_width]}" %></div>
613
+ <% end %>
608
614
  <div class="row device-info result-btn">
609
615
  <a href='<%= "./#{device[:id]}/feature_report.html" %>'>See Results</a>
610
616
  </div>
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kraken-mobile
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - William Ravelo M
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-20 00:00:00.000000000 Z
11
+ date: 2021-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cucumber
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - '='
102
102
  - !ruby/object:Gem::Version
103
- version: 3.142.7
103
+ version: 3.14.0
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - '='
109
109
  - !ruby/object:Gem::Version
110
- version: 3.142.7
110
+ version: 3.14.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: faker
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -166,6 +166,7 @@ files:
166
166
  - lib/kraken-mobile/models/web_device.rb
167
167
  - lib/kraken-mobile/monkeys/mobile/android_monkey.rb
168
168
  - lib/kraken-mobile/monkeys/mobile/kraken_android_monkey.rb
169
+ - lib/kraken-mobile/monkeys/web/web_monkey.rb
169
170
  - lib/kraken-mobile/protocols/file_protocol.rb
170
171
  - lib/kraken-mobile/runners/calabash/android/android_runner.rb
171
172
  - lib/kraken-mobile/runners/calabash/android/apk_signer.rb
@@ -227,7 +228,7 @@ homepage: https://github.com/TheSoftwareDesignLab/KrakenMobile
227
228
  licenses:
228
229
  - MIT
229
230
  metadata: {}
230
- post_install_message:
231
+ post_install_message:
231
232
  rdoc_options: []
232
233
  require_paths:
233
234
  - lib
@@ -242,8 +243,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
243
  - !ruby/object:Gem::Version
243
244
  version: '0'
244
245
  requirements: []
245
- rubygems_version: 3.0.6
246
- signing_key:
246
+ rubygems_version: 3.0.8
247
+ signing_key:
247
248
  specification_version: 4
248
249
  summary: Automated E2E mobile testing involving intercommunication scenarios.
249
250
  test_files: []