k6
k6 copied to clipboard
response.submitForm() shall use formaction attribute of input tag
Feature Description
response.submitForm() shall handle the formaction attribute of the input tag.
<form action="/formPost">
<input name="custname" value="smurf">
<input type="submit" value="save" formaction="/savePost" />
<input type="submit" value="next" formaction="/nextPost" />
</form>
Actually submitForm post its request either to the action defined in the form tag, or to the response URL.
k6 shall use the formaction when submitForm is called with an submitSelector parameter:
res.submitForm({ formSelector: 'form', submitSelector: '[value="save"]' });
Suggested Solution (optional)
My quick and dirty implemention. Problems:
- it uses too much CPU/RAM, because of unnecessary Attr parsings.
- have not taken care which action is used when submitSelector returns nil.
- additional parameter useFormAction may be better than checking for overwritten submitSelector
func (res *Response) SubmitForm(args ...goja.Value) (*Response, error) {
rt := res.client.moduleInstance.vu.Runtime()
formSelector := "form"
submitSelector := "[type=\"submit\"]"
var fields map[string]goja.Value
requestParams := goja.Null()
submitOverwritten := false
if len(args) > 0 {
params := args[0].ToObject(rt)
for _, k := range params.Keys() {
switch k {
case "formSelector":
formSelector = params.Get(k).String()
case "submitSelector":
submitSelector = params.Get(k).String()
submitOverwritten = true
case "fields":
if rt.ExportTo(params.Get(k), &fields) != nil {
fields = nil
}
case "params":
requestParams = params.Get(k)
}
}
}
form := res.HTML(formSelector)
if form.Size() == 0 {
common.Throw(rt, fmt.Errorf("no form found for selector '%s' in response '%s'", formSelector, res.URL))
}
methodAttr := form.Attr("method")
var requestMethod string
if methodAttr == goja.Undefined() {
// Use GET by default
requestMethod = http.MethodGet
} else {
requestMethod = strings.ToUpper(methodAttr.String())
}
responseURL, err := url.Parse(res.URL)
if err != nil {
common.Throw(rt, err)
}
// Set the body based on the form values
values := form.SerializeObject()
// Set the name + value of the submit button
submit := form.Find(submitSelector)
submitName := submit.Attr("name")
submitAction := submit.Attr("formaction")
submitValue := submit.Val()
if submitName != goja.Undefined() && submitValue != goja.Undefined() {
values[submitName.String()] = submitValue
}
actionAttr := form.Attr("action")
if(submitOverwritten && submitAction != nil){
actionAttr = submitAction
}
var requestURL *url.URL
if actionAttr == goja.Undefined() {
// Use the url of the response if no action is set
requestURL = responseURL
} else {
actionURL, err := url.Parse(actionAttr.String())
if err != nil {
common.Throw(rt, err)
}
requestURL = responseURL.ResolveReference(actionURL)
}
// Set the values supplied in the arguments, overriding automatically set values
for k, v := range fields {
values[k] = v
}
if requestMethod == http.MethodGet {
q := url.Values{}
for k, v := range values {
q.Add(k, v.String())
}
requestURL.RawQuery = q.Encode()
return res.client.Request(requestMethod, rt.ToValue(requestURL.String()), goja.Null(), requestParams)
}
return res.client.Request(
requestMethod, rt.ToValue(requestURL.String()),
rt.ToValue(values), requestParams,
)
}
Already existing or connected issues / PRs (optional)
No response
Hi @Pej0815, thanks for reporting, and sorry for the really slow reply. There were vacations and then we had to release v0.46.0 and this fell between the cracks.
The current k6/http is in maintainance mode and we are actvely trying to develop v2.
V2 is skipping this particular functionality though. In no small part because this is quite tightly coupling http responses with html parsing which arguably should be only a k6/html thing. And k6/html likely shouldn't make http requests.
Having said that - looking at the patch it seems small enough. And while the k6 core team will likely never pick this up, I think we will be okay with a PR from the community that has tests and still keeps the change to the few lines this version above presents.
Looking at the code - I don't think that this adds a lot more things to the current SubmitForm. As such I am not certain what you mean by:
it uses too much CPU/RAM, because of unnecessary Attr parsings.
So again, sorry for the slow reply :bow:. If you want you are welcome to making a PR adding this + at least one test that tests the new functionality.