Skip to content

Commit 71f7667

Browse files
Added documentation for installing CA certificate and examples for mock usage (#6)
1 parent 8cf1d13 commit 71f7667

5 files changed

Lines changed: 142 additions & 14 deletions

File tree

.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.md

README.md

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# appium-interceptor-plugin
22

3-
This is an Appium plugin designed to intercept API response and mocking easy.
3+
This is an Appium plugin designed to intercept API response and mocking easy.
44
This plugin uses mitmproxy
55

66
## Prerequisite
77

8-
Appium version 2.0
8+
1. Appium version 2.0
9+
2. Intercepting API requests from android requires CA certificate to be installed on the device. Follow the instructions in [How to install CA certificate on android](./docs/certificate-installation.md) section and install the CA certificate.
910

1011
## Installation - Server
1112

@@ -21,27 +22,31 @@ The plugin will not be active unless turned on when invoking the Appium server:
2122

2223
`appium server -ka 800 --use-plugins=appium-interceptor -pa /wd/hub`
2324

25+
## what does this plugin do?
26+
27+
For every appium session, interceptor plugin will start a proxy server and updates the device proxy settings to pass all network traffic to proxy server. Mocking is disabled by default and can be enabled from the test by passing `appium:intercept : true` in the desired capability while creating a new appium session.
28+
29+
Please refer to the [commands](/docs/commands.md) sections for detailed usage.
30+
2431
## Supported Platforms
2532

2633
💚 `Android`
2734

28-
### what does this plugin do?
29-
30-
Plugin will set proxy to the device and intercept the API response and mock the response based on the request.
35+
**Mocking support**
3136

32-
**Mocking support**
37+
1. Update outgoing request URL
38+
2. Fully Replace or partially modify the request payload (POST Body)
39+
3. Update the request headers
40+
4. Update the response headers
41+
5. Fully Replace or partially modify the response body
42+
6. Update the response status code.
3343

34-
1. Mocking response based on the request
35-
2. Mocking response based on the request and response
36-
3. Mocking response based on the request and response and request body
37-
4. Mocking request headers
38-
5. Mocking partial response from server
44+
## Usage
3945

40-
### Usage
4146
Refer Examples [here](./test/plugin.spec.js)
47+
4248
## Build local
49+
4350
`npm install`
4451

4552
`npm run build`
46-
47-

docs/ca_install_steps.gif

4.48 MB
Loading

docs/certificate-installation.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## Installing CA vertificate on android device
2+
3+
1. Download the `ca.pem` file from here and save it to the computer.
4+
5+
2. Push the downloaded certificate to the devices manually or via abd push command as below
6+
7+
```shell
8+
adb push downloaded_cert_path/ca.pem /storage/emulated/0/Download
9+
```
10+
11+
The above command will push the certificate to download directory of the android device.
12+
13+
3. Open `Settings` > `Security settings` > `Encryption and Credentials` > `Install a certificate` > `CA Certificate` > `Install anyway` and choose the `ca.pem` file and install the certificate.
14+
15+
4. Make sure the installed certificate is displayed under `User` section of `Trusted Credentials` settings.
16+
17+
<img src="./ca_install_steps.gif">

docs/commands.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
## Appium interceptor commands
2+
3+
Create the appium session by passing `appium:intercept : true` option in the desired capability. Once the session is successfully created, tests can manage the api mocking using below commands.
4+
5+
### Mock Configuration
6+
Mock configuration is a json object that defines the specification for filtering and applying various updates to the api request and below is the structure for the config object.
7+
8+
```javascript
9+
{
10+
url: string;
11+
method?: string;
12+
updateUrl?: [{ regexp: string, value: string}];
13+
headers?: object | { add: object : string, remove: string[]};
14+
requestBody?: string;
15+
updateRequestBody?: [{regexp: string, value: string }] | [{jsonPath: string, value: string}];
16+
statusCode?: number;
17+
responseHeaders?: object | { add: object : string, remove: string[]};
18+
responseBody?: string;
19+
updateResponseBody?: [{regexp: string, value: string }] | [{jsonPath: string, value: string}];
20+
}
21+
```
22+
23+
| Name | Type | Required | Description | Example |
24+
| ------ | ------ | -------- | --------------------------------------------------------- | ------- |
25+
| url | string | yes | Regular Expression or Glob pattern matcher to filter the request for applying the mock | Sample url : `https://www.reqres.in/api/users?page=1` <br> Regex example: `/api/users?.*/g` <br> Glob pattern: `**/api/users*?*` |
26+
| method | string | no | Method to matching the request for applying the mock | `GET` / `POST` / `PUT` / `PATCH` |
27+
| updateUrl |string | no | Regular Expression patter and replaceable value to update the outgoing url | Sample url : `https://www.reqres.in/api/users?page=1` <br> When passing `{ updateUrl : {regexp: "/page=(\\d)+/g", value: "page=5"} }` <br> Then outgoing url will be replaced to `https://www.reqres.in/api/users?page=2` |
28+
| headers | object | no | Map of key value pairs to be added or removed from the request header | 1. Passing a plain object map will add all the key: value pairs to the request headers `{headers : {"Content-Type" : "application/json", "Authorization": "Bearer sometoken"} }` <br> 2. If you want to add and remove header values simulaneously then you can pass the header as `{headers : { add : {"Content-Type" : "application/json"}, remove: ["Authorization", "X-Content-Type"] } }` |
29+
| requestBody | string | no | This will replace the original payload (post body) send to api the from the application and updates it with new body | When passing `{"url" : "/api/login/g" , "requestBody": "{\"email\": \"invalid@email.com\", \"password\": \"wrongpassword\"}"}` will send the given payload for all login api calls made from the application |
30+
| updateRequestBody | string | no | This is similar to requestBody but instead of fully replacing the request payload, you can replace any value in the payload using Regular expression or jsonpath | Consider you application sending `{\"username\": \"someusername\", \"email\": \"someemail@email.com\", \"password\": \"somepassword\", \"isAdmin\" : \"false\"}` as a payload for a register user api request and you want to update the email and username, then you can pass <br> `{"updateRequestBody": [{ "jsonPath": "$.email", "newemail@email.com" }, { "jsonPath": "$.username", "new_username" }]}` and it will update the email and username field before sending the request to the server|
31+
| statusCode | number | no | Updates the response status code with the given value | To simulate any unexpected error you can send some of the below statusCode <br> 1. `500` - Internal server error <br> 2. `400` - Bad request <br> 3. `401` - Unauthorized |
32+
| responseHeaders | object | no | Map of key value pairs to be added or removed from the response header | Same syntax as `headers` key. But this will update the response header |
33+
| responseBody | object | no | This will replace the original response data returned by the api server and updates it with new data | Passing the config as `{"url" : "/api/login/g" , "responseBody": "{\"error\": \"User account locked\"}", `statusCode`: 400 }` will simulate a error scenario when logged in with any user credentilas |
34+
| updateResponseBody | string | no | This is similar to responseBody but instead of fully mocking the server response, you can replace any value in the response using Regular expression or jsonpath | Consider you application returns user data as `{\"username\": \"someusername\", \"email\": \"someemail@email.com\", \"isAdmin\" : \"false\"}` as a response for get user api request and you want to update the values for email and IsAdmin fiels, then you can pass <br> `{"updateRequestBody": [{ "jsonPath": "$.email", "newemail@email.com" }, { "jsonPath": "$.isAdmin", "true" }]}` and it will update the email and isAdmin field before sending the response back to the application|
35+
36+
37+
## Commands:
38+
39+
### interceptor: addMock
40+
41+
Add a new mock specification for intercepting and updating the request. The command will returns a unique id for each mock which can be used in future to delete the mock at any point in the test.
42+
43+
#### Example:
44+
45+
```javascript
46+
const authorizationMock = await driver.execute("interceptor: addMock", [{
47+
config: {
48+
url "*reqres.in*",
49+
headers: {
50+
"Authorization" : "Bearer bearertoken"
51+
}
52+
}
53+
}]);
54+
55+
const userListGetMock = await driver.execute("interceptor: addMock", [{
56+
config: {
57+
url "**reqres.in/api/users",
58+
method: "GET",
59+
responseBody: JSON.stringify({
60+
page: 2,
61+
count: 2,
62+
data: [
63+
{
64+
"first_name" : "User",
65+
"last_name" : "1"
66+
},
67+
{
68+
"first_name" : "User",
69+
"last_name" : "2"
70+
}
71+
]
72+
})
73+
}
74+
}]);
75+
```
76+
77+
`authorizationMock` will be executed for all api calls made to `reqres.in` domain and `userListGetMock` will be applied for `https://www.reqres.in/api/users` with `GET` http method.
78+
79+
### interceptor: removeMock
80+
Given a mockId return during addMock command, will remove the mock configuration from the proxy sever.
81+
82+
#### Example:
83+
84+
```javascript
85+
const authorizationMock = await driver.execute("interceptor: addMock", [{
86+
config: {
87+
url "*reqres.in*",
88+
headers: {
89+
"Authorization" : "Bearer bearertoken"
90+
}
91+
}
92+
}]);
93+
94+
//peform user action
95+
//perform validation
96+
..
97+
..
98+
99+
await driver.execute("interceptor: removeMock", [{
100+
id: authorizationMock
101+
}]);
102+
103+
// authorizationMock will not be active after this point and the test will proceed with normal flow
104+
```
105+

0 commit comments

Comments
 (0)