Stop tasklist forms from creating new process variables?

Hi folks,

We are building our workflows currently using embedded forms within the standard Camunda task UI. This works OK, but it causes a bit of a gap in our unit tests, because the tests have no idea about embedded forms.

When we want to test a user task, we use the TaskService to complete a Task with the variables we expect a user to enter - but there’s no way to be sure these variables are actually the ones created in the embedded form without either manual testing, or a very complex (and low value) browser test against the form.

One thing I was wondering is - could we block forms from creating any new process variables? I.E let the forms update existing variables, but not create new ones? So we’d create all our variables in a start task or script task earlier, and enforce that forms could modify them only.

This would at least narrow the range of possible bugs where someone mis-spells a form field ID, and everything silently works because the form makes a brand new variable that is then ignored by the rest of the workflow.

Or is there some other cunning way people test task forms without loading the entire UI in a set of Selenium tests?

Hi @Korny,

one idea that came into my mind: you can assert the formkey in the JUnit test with the latest version of the camunda-bpm-assert library: https://github.com/camunda/camunda-bpm-assert/blob/master/camunda-bpm-assert/User_Guide_BPMN.md#task-hasFormKey.

Then you can provide some helper methods in your unit tests to read the form as a file and try simple regexpression to seach for cam-variable-name in the file and compare them to your variable list in the tests.

Do you think this is a valid approach?

Cheers, Ingo

Hmm - that’s an interesting idea - at minimum we could whitelist valid form variables that way.

It works - for reference, this is the code:

  private Set<String> getFormFieldsFromHtml(Task task) {
    String formKey = getTaskFormKey(task)
    if (!formKey.startsWith("embedded:app:")) {
      throw new RuntimeException("Non-embedded forms not yet supported: '" + formKey + "'");
    }
    String formResourceLocation = formKey.replaceFirst("embedded:app:", "static/");
    try {
      String formText =
          Resources.toString(Resources.getResource(formResourceLocation), Charsets.UTF_8);
      // sadly doing this with streams needs Java 9
      Set<String> formFields = new HashSet<>();
      Pattern camundaVariableNamePattern =
          Pattern.compile("cam-variable-name\\s*=\\s*\"([a-zA-Z0-9_\\-]+)\"");
      Matcher matcher = camundaVariableNamePattern.matcher(formText);
      while (matcher.find()) {
        formFields.add(matcher.group(1));
      }
      return formFields;
    } catch (IOException e) {
      throw new RuntimeException("Can't find form at " + formResourceLocation);
    }
  }

(I also cache the results as we don’t want to scan the form html for every test!)

So now our tests can verify that when they complete a task, all variables in the form must be set - which pretty well covers my needs:

  public T completeTaskWithVariables(Map<String, Object> variables) {
    Set<String> formFields = camundaTestService.getTaskFormFields(getCurrentTask());
    Set<String> currentVariables = processVariables().keySet();
    SetView<String> requiredFields = Sets.difference(formFields, currentVariables);
    assertThat(variables.keySet()).containsAll(requiredFields);
   camundaTestService.getTaskService().complete(getCurrentTask().getId(), variables);
   return self();
 }

(Note we are writing our own test bits with some stuff copied from camunda-bpm-assert as we can’t run that library directly due to AssertJ collisions with Spring Boot: https://github.com/camunda/camunda-bpm-assert/issues/90 )