8.7 C
New York
Friday, November 22, 2024

Take a look at Drive HTML Templates


foo

Let’s examine the way to do it in levels: We begin with the next take a look at that tries to compile the template. In Go we use the usual html/template bundle.

Go

  func Test_wellFormedHtml(t *testing.T) {
    templ := template.Should(template.ParseFiles("index.tmpl"))
    _ = templ
  }

In Java we use moustache
as a result of it is rather simple to make use of; free marker both
Velocity are different widespread choices.

Java

  @Take a look at
  void indexIsSoundHtml() {
      var template = Mustache.compiler().compile(
              new InputStreamReader(
                      getClass().getResourceAsStream("/index.tmpl")));
  }

If we run this take a look at, it’s going to fail, as a result of the index.tmpl the file doesn’t exist. So we create it, with the damaged HTML above. Now the take a look at ought to move.

Then we create a mannequin for the template to make use of. The app manages a to-do listing and we will create a minimal mannequin for demonstration functions.

Go

  func Test_wellFormedHtml(t *testing.T) {
    templ := template.Should(template.ParseFiles("index.tmpl"))
    mannequin := todo.NewList()
    _ = templ
    _ = mannequin
  }

Java

  @Take a look at
  void indexIsSoundHtml() {
      var template = Mustache.compiler().compile(
              new InputStreamReader(
                      getClass().getResourceAsStream("/index.tmpl")));
      var mannequin = new TodoList();
  }

Now we render the template, saving the leads to a byte buffer (Go) or as a String (Java).

Go

  func Test_wellFormedHtml(t *testing.T) {
    templ := template.Should(template.ParseFiles("index.tmpl"))
    mannequin := todo.NewList()
    var buf bytes.Buffer
    err := templ.Execute(&buf, mannequin)
    if err != nil {
      panic(err)
    }
  }

Java

  @Take a look at
  void indexIsSoundHtml() {
      var template = Mustache.compiler().compile(
              new InputStreamReader(
                      getClass().getResourceAsStream("/index.tmpl")));
      var mannequin = new TodoList();
  
      var html = template.execute(mannequin);
  }

At this level we would like parse the HTML and we count on to see an error, as a result of in our damaged HTML there’s a div factor that’s closed by a p factor. There may be an HTML parser within the Go customary library, but it surely’s too forgiving: if we run it on our damaged HTML, we do not get an error. Fortuitously, the Go customary library additionally has an XML parser that may be configured to parse HTML (due to this stack overflow reply)

Go

  func Test_wellFormedHtml(t *testing.T) {
    templ := template.Should(template.ParseFiles("index.tmpl"))
    mannequin := todo.NewList()
    
    // render the template right into a buffer
    var buf bytes.Buffer
    err := templ.Execute(&buf, mannequin)
    if err != nil {
      panic(err)
    }
  
    // test that the template could be parsed as (lenient) XML
    decoder := xml.NewDecoder(bytes.NewReader(buf.Bytes()))
    decoder.Strict = false
    decoder.AutoClose = xml.HTMLAutoClose
    decoder.Entity = xml.HTMLEntity
    for {
      _, err := decoder.Token()
      swap err {
      case io.EOF:
        return // We're accomplished, it is legitimate!
      case nil:
        // do nothing
      default:
        t.Fatalf("Error parsing html: %s", err)
      }
    }
  }

fountain

This code configures the HTML parser to have the right stage of leniency for HTML after which parses the HTML token by token. In reality, we see the error message we wished:

--- FAIL: Test_wellFormedHtml (0.00s)
    index_template_test.go:61: Error parsing html: XML syntax error on line 4: sudden finish factor 

In Java, a flexible library to make use of is jsopa:

Java

  @Take a look at
  void indexIsSoundHtml() {
      var template = Mustache.compiler().compile(
              new InputStreamReader(
                      getClass().getResourceAsStream("/index.tmpl")));
      var mannequin = new TodoList();
  
      var html = template.execute(mannequin);
  
      var parser = Parser.htmlParser().setTrackErrors(10);
      Jsoup.parse(html, "", parser);
      assertThat(parser.getErrors()).isEmpty();
  }

fountain

And we see it fail:

java.lang.AssertionError: 
Anticipating empty however was:<(<1:13>: Surprising EndTag token () when in state (InBody),

Success! Now if we copy TodoMVC template content material to our index.tmpl file, the take a look at passes.

The proof, nonetheless, is just too detailed: we extract two auxiliary features to make clear the intent of the proof and acquire

Go

  func Test_wellFormedHtml(t *testing.T) {
    mannequin := todo.NewList()
  
    buf := renderTemplate("index.tmpl", mannequin)
  
    assertWellFormedHtml(t, buf)
  }

fountain

Java

  @Take a look at
  void indexIsSoundHtml() {
      var mannequin = new TodoList();
  
      var html = renderTemplate("/index.tmpl", mannequin);
  
      assertSoundHtml(html);
  }

fountain

Degree 2: Take a look at the HTML construction

What else ought to we attempt?

We all know that in the end solely a human can take a look at the look of a web page and see the way it renders in a browser. Nonetheless, there may be usually logic in templates and we would like to have the ability to take a look at that logic.

One is likely to be tempted to attempt rendered HTML with string equality, however this method fails in observe, as a result of templates comprise many particulars that make string equality assertions impractical. The claims develop into very detailed and when studying them it’s obscure what we try to show.

What we want is a way to claim that some components of the rendered HTML correspond to what we count on, since ignore all the main points that do not matter to us. A technique to do that is by working queries with the CSS selector language: is a robust language that enables us to pick the weather that curiosity us from all the HTML doc. As soon as we’ve got chosen these components, we (1) depend that the variety of components returned is what we count on and (2) that they comprise the textual content or different content material we count on.

The UI we’re presupposed to generate appears to be like like this:

There are a number of particulars which are rendered dynamically:

  1. The variety of components and their textual content material change, clearly.
  2. The model of the duty merchandise modifications when it’s accomplished (for instance, the second)
  3. The “2 gadgets left” textual content will change based mostly on the variety of uncompleted gadgets
  4. One of many three buttons “All”, “Lively”, “Accomplished” will probably be highlighted, relying on the present URL; for instance, if we determine that the URL that exhibits solely “energetic” gadgets is /energeticthen when the present url is /energeticthe “Lively” button needs to be surrounded by a skinny pink rectangle
  5. The “Clear Accomplished” button ought to solely be seen if any merchandise is accomplished

Every of those issues could be examined with the assistance of CSS selectors.

It is a snippet of the TodoMVC template (barely simplified). I have not added the dynamic bits but, so what we see right here is static content material, supplied for example:

index.tmpl

  

fountain

Related Articles

Latest Articles