Skip to content

Commit 0583e54

Browse files
authored
fix(java): 🐛 fixed issues in api form data request (#930)
1 parent 31174dc commit 0583e54

File tree

10 files changed

+406
-344
lines changed

10 files changed

+406
-344
lines changed

core-java/src/main/java/io/github/boykaframework/actions/api/ApiActions.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.github.boykaframework.actions.api;
1818

1919
import static io.github.boykaframework.enums.ContentType.JSON;
20+
import static io.github.boykaframework.enums.ContentType.OCTET_STREAM;
2021
import static io.github.boykaframework.enums.ListenerType.API_ACTION;
2122
import static io.github.boykaframework.enums.Message.AUTH_PASSWORD_REQUIRED;
2223
import static io.github.boykaframework.enums.Message.BASE_URL_EMPTY;
@@ -28,8 +29,9 @@
2829
import static io.github.boykaframework.manager.ParallelSession.getSession;
2930
import static io.github.boykaframework.utils.ErrorHandler.handleAndThrow;
3031
import static io.github.boykaframework.utils.StringUtils.interpolate;
32+
import static io.github.boykaframework.utils.StringUtils.isValidPath;
3133
import static io.github.boykaframework.utils.Validator.requireNonEmpty;
32-
import static java.lang.String.join;
34+
import static java.nio.file.Path.of;
3335
import static java.text.MessageFormat.format;
3436
import static java.time.Duration.ofSeconds;
3537
import static java.util.Objects.isNull;
@@ -38,6 +40,7 @@
3840
import static java.util.Optional.ofNullable;
3941
import static okhttp3.Credentials.basic;
4042
import static okhttp3.MediaType.parse;
43+
import static okhttp3.MultipartBody.FORM;
4144
import static okhttp3.RequestBody.create;
4245
import static org.apache.commons.lang3.StringUtils.EMPTY;
4346
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
@@ -46,7 +49,6 @@
4649
import java.io.IOException;
4750
import java.security.KeyManagementException;
4851
import java.security.NoSuchAlgorithmException;
49-
import java.util.ArrayList;
5052
import java.util.HashMap;
5153
import java.util.Map;
5254
import java.util.function.BiConsumer;
@@ -68,6 +70,7 @@
6870
import io.github.boykaframework.utils.JsonUtil;
6971
import okhttp3.HttpUrl;
7072
import okhttp3.MediaType;
73+
import okhttp3.MultipartBody;
7174
import okhttp3.OkHttpClient;
7275
import okhttp3.Request;
7376
import okhttp3.RequestBody;
@@ -175,11 +178,19 @@ private ApiActions body (final String body) {
175178

176179
private ApiActions body (final Map<String, String> bodyMap) {
177180
LOGGER.traceEntry ();
178-
final var body = new ArrayList<String> ();
179-
bodyMap.forEach ((k, v) -> body.add (format ("{0}={1}", k, v)));
180-
if (!body.isEmpty ()) {
181-
this.requestBody = create (join ("&", body),
182-
requireNonNull (this.mediaType, CONTENT_TYPE_NOT_SET.getMessageText ()));
181+
if (!bodyMap.isEmpty ()) {
182+
final var formBody = new MultipartBody.Builder ().setType (FORM);
183+
bodyMap.forEach ((key, value) -> {
184+
LOGGER.debug ("Form Data: {}, {}", key, value);
185+
if (isValidPath (value)) {
186+
final var filePath = of (value).toFile ();
187+
formBody.addFormDataPart (key, filePath.getName (),
188+
create (filePath, parse (OCTET_STREAM.getType ())));
189+
} else {
190+
formBody.addFormDataPart (key, value);
191+
}
192+
});
193+
this.requestBody = formBody.build ();
183194
}
184195
return LOGGER.traceExit (this);
185196
}

core-java/src/main/java/io/github/boykaframework/builders/ApiRequest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package io.github.boykaframework.builders;
1818

19+
import static io.github.boykaframework.utils.StringUtils.interpolate;
20+
1921
import java.util.Map;
2022

2123
import io.github.boykaframework.enums.ContentType;
@@ -50,4 +52,22 @@ public class ApiRequest {
5052
@Singular
5153
private Map<String, String> queryParams;
5254
private String userName;
55+
56+
/**
57+
* Gets the authentication password.
58+
*
59+
* @return password
60+
*/
61+
public String getPassword () {
62+
return interpolate (this.password);
63+
}
64+
65+
/**
66+
* Gets the authentication username
67+
*
68+
* @return user name.
69+
*/
70+
public String getUserName () {
71+
return interpolate (this.userName);
72+
}
5373
}

core-java/src/main/java/io/github/boykaframework/enums/ContentType.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,23 @@
2929
@Getter
3030
public enum ContentType {
3131
/**
32-
* Application/x-www-form-urlencoded.
32+
* Application/x-www-form-urlencoded
3333
*/
3434
FORM_URLENCODED ("application/x-www-form-urlencoded"),
3535
/**
36-
* Application/json.
36+
* Application/json
3737
*/
3838
JSON ("application/json"),
3939
/**
40-
* Multipart/form-data.
40+
* Multipart/form-data
4141
*/
4242
MULTIPART_FORM_DATA ("multipart/form-data"),
4343
/**
44-
* Plain text.
44+
* application/octet-stream
45+
*/
46+
OCTET_STREAM ("application/octet-stream"),
47+
/**
48+
* Plain text
4549
*/
4650
PLAIN_TEXT ("text/plain");
4751

core-java/src/main/java/io/github/boykaframework/utils/StringUtils.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616

1717
package io.github.boykaframework.utils;
1818

19+
import static java.nio.file.Path.of;
1920
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
2021
import static org.apache.commons.text.StringSubstitutor.createInterpolator;
2122
import static org.apache.logging.log4j.LogManager.getLogger;
2223

24+
import java.nio.file.InvalidPathException;
2325
import java.util.Map;
2426

2527
import org.apache.commons.text.StringSubstitutor;
@@ -74,6 +76,22 @@ public static String interpolate (final String value) {
7476
return result;
7577
}
7678

79+
/**
80+
* Checks if the string is a valid file path.
81+
*
82+
* @param path String to test
83+
*
84+
* @return True if the path is a valid file path, else False.
85+
*/
86+
public static boolean isValidPath (final String path) {
87+
try {
88+
return of (path).toFile ()
89+
.exists ();
90+
} catch (final InvalidPathException | NullPointerException ex) {
91+
return false;
92+
}
93+
}
94+
7795
private StringUtils () {
7896
// Utility class
7997
}

core-java/src/test/java/io/github/boykaframework/testng/api/postman/ApiPostmanTest.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
package io.github.boykaframework.testng.api.postman;
1818

1919
import static io.github.boykaframework.actions.api.ApiActions.withRequest;
20-
import static io.github.boykaframework.builders.ApiRequest.createRequest;
21-
import static io.github.boykaframework.enums.ContentType.FORM_URLENCODED;
20+
import static io.github.boykaframework.enums.ContentType.MULTIPART_FORM_DATA;
2221
import static io.github.boykaframework.enums.PlatformType.API;
2322
import static io.github.boykaframework.enums.RequestMethod.POST;
2423
import static io.github.boykaframework.manager.ParallelSession.clearSession;
2524
import static io.github.boykaframework.manager.ParallelSession.createSession;
25+
import static java.lang.System.getProperty;
26+
import static java.nio.file.Path.of;
27+
import static java.text.MessageFormat.format;
2628

29+
import io.github.boykaframework.builders.ApiRequest;
2730
import org.testng.annotations.AfterClass;
2831
import org.testng.annotations.BeforeClass;
2932
import org.testng.annotations.Test;
@@ -56,15 +59,23 @@ public void tearDownTestClass () {
5659
*/
5760
@Test (description = "Test Form body POST request")
5861
public void testFormBodyRequest () {
59-
final var request = createRequest ().contentType (FORM_URLENCODED)
62+
final var fileName = "test-file.txt";
63+
final var request = ApiRequest.createRequest ()
64+
.contentType (MULTIPART_FORM_DATA)
6065
.formBody ("strange", "boom")
6166
.formBody ("test", "abc")
67+
.formBody ("profile", of (getProperty ("user.dir"), "src/test/resources", fileName).toString ())
6268
.method (POST)
6369
.path ("/post")
6470
.create ();
6571

6672
final var response = withRequest (request).execute ();
6773
response.verifyStatusCode ()
6874
.isEqualTo (200);
75+
76+
response.verifyTextField ("form.strange")
77+
.isEqualTo ("boom");
78+
response.verifyTextField (format ("files[\"{0}\"]", fileName))
79+
.isNotEmpty ();
6980
}
7081
}

core-java/src/test/resources/boyka-config.json

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
"response": true
1212
},
1313
"timeout": {
14-
"read_timeout": 3,
15-
"write_timeout": 3,
16-
"connection_timeout": 5
14+
"read_timeout": 10,
15+
"write_timeout": 10,
16+
"connection_timeout": 10
1717
},
1818
"schema_path": "schema/"
1919
}
@@ -93,7 +93,7 @@
9393
"browser": "REMOTE",
9494
"base_url": "https://the-internet.herokuapp.com/",
9595
"target": "LOCAL",
96-
"port": "4444",
96+
"port": 4444,
9797
"capabilities": {
9898
"browserName": "chrome"
9999
}
@@ -304,8 +304,8 @@
304304
},
305305
"device": {
306306
"os": "ANDROID",
307-
"version": "12.0",
308-
"name": "Google Pixel 5",
307+
"version": "14.0",
308+
"name": "Google Pixel 8 Pro",
309309
"type": "CLOUD",
310310
"ignore_unimportant_views": true,
311311
"application": {
@@ -318,7 +318,7 @@
318318
"projectName": "BrowserStack Android Project",
319319
"buildName": "Test BrowserStack Build",
320320
"sessionName": "Test BrowserStack Session",
321-
"appiumVersion": "2.0.0",
321+
"appiumVersion": "2.6.0",
322322
"automationVersion": "latest",
323323
"deviceLogs": true,
324324
"networkLogs": true,
@@ -348,8 +348,8 @@
348348
"ignore_unimportant_views": true,
349349
"capabilities": {
350350
"platformName": "Android",
351-
"deviceName": "Pixel 5",
352-
"platformVersion": "11",
351+
"deviceName": "Pixel 8 Pro",
352+
"platformVersion": "14",
353353
"app": "AndroidApp",
354354
"project": "LambdaTest Android Project",
355355
"build": "Test LambdaTest Build",
@@ -539,7 +539,7 @@
539539
},
540540
"device": {
541541
"os": "IOS",
542-
"version": "16",
542+
"version": "18",
543543
"name": "iPhone 14",
544544
"type": "CLOUD",
545545
"application": {
@@ -551,7 +551,7 @@
551551
"projectName": "BrowserStack iOS Project",
552552
"buildName": "Test BrowserStack Build",
553553
"sessionName": "Test BrowserStack Session",
554-
"appiumVersion": "2.0.0",
554+
"appiumVersion": "2.6.0",
555555
"automationVersion": "latest",
556556
"deviceLogs": true,
557557
"networkLogs": true,
@@ -648,7 +648,12 @@
648648
"base_uri": "https://restful-booker.herokuapp.com"
649649
},
650650
"test_postman": {
651-
"base_uri": "https://postman-echo.com"
651+
"base_uri": "https://postman-echo.com",
652+
"timeout": {
653+
"connection_timeout": 60,
654+
"read_timeout": 60,
655+
"write_timeout": 60
656+
}
652657
},
653658
"test_bad_ssl_wo_verify": {
654659
"base_uri": "https://expired.badssl.com",

core-java/test-suites/testng-mobile-lt.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
-->
1717

1818
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
19-
<suite name="Boyka Framework LambdaTest Mobile Suite" verbose="2" parallel="tests">
19+
<suite name="Boyka Framework LambdaTest Mobile Suite" verbose="2">
2020
<listeners>
2121
<listener class-name="io.github.boykaframework.testng.listeners.TestResultListener"/>
2222
</listeners>

core-java/test-suites/testng-web-lt.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616
-->
1717

1818
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
19-
<suite name="Boyka Framework LambdaTest Web Suite" verbose="2" parallel="tests">
19+
<suite name="Boyka Framework LambdaTest Web Suite" verbose="2">
2020
<listeners>
2121
<listener class-name="io.github.boykaframework.testng.listeners.TestResultListener"/>
2222
</listeners>
23-
<test name="Test web on LambdaTest Browser" parallel="classes">
23+
<test name="Test web on LambdaTest Browser">
2424
<parameter name="platformType" value="WEB"/>
2525
<parameter name="driverKey" value="test_lambda_test_chrome"/>
2626
<packages>

package.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,17 @@
3030
"license": "MIT",
3131
"private": true,
3232
"devDependencies": {
33-
"@commitlint/cli": "^19.5.0",
34-
"@commitlint/config-conventional": "^19.5.0",
33+
"@commitlint/cli": "^19.6.0",
34+
"@commitlint/config-conventional": "^19.6.0",
3535
"@eslint/compat": "^1.2.3",
3636
"@lerna/child-process": "^7.4.2",
3737
"@release-it-plugins/lerna-changelog": "^7.0.0",
38-
"@stylistic/eslint-plugin-js": "^2.10.1",
39-
"@stylistic/eslint-plugin-ts": "^2.10.1",
38+
"@stylistic/eslint-plugin-js": "^2.11.0",
39+
"@stylistic/eslint-plugin-ts": "^2.11.0",
4040
"@types/node": "^22.9.0",
41-
"@typescript-eslint/eslint-plugin": "^8.14.0",
42-
"@typescript-eslint/parser": "^8.14.0",
43-
"commitlint": "^19.5.0",
41+
"@typescript-eslint/eslint-plugin": "^8.15.0",
42+
"@typescript-eslint/parser": "^8.15.0",
43+
"commitlint": "^19.6.0",
4444
"eslint": "^9.15.0",
4545
"eslint-config-google": "^0.14.0",
4646
"eslint-config-prettier": "^9.1.0",
@@ -49,7 +49,7 @@
4949
"eslint-plugin-prettier": "^5.2.1",
5050
"eslint-plugin-react": "^7.37.2",
5151
"globals": "^15.12.0",
52-
"husky": "^9.1.6",
52+
"husky": "^9.1.7",
5353
"js-yaml": "^4.1.0",
5454
"lerna": "8.1.9",
5555
"lerna-changelog": "^2.2.0",
@@ -63,7 +63,7 @@
6363
"release-it": "^17.10.0",
6464
"ts-node": "^10.9.2",
6565
"typescript": "^5.6.3",
66-
"typescript-eslint": "^8.14.0"
66+
"typescript-eslint": "^8.15.0"
6767
},
6868
"scripts": {
6969
"preinstall": "npx only-allow pnpm",

0 commit comments

Comments
 (0)