Friday, April 4, 2025
Home Blog Page 1280

Adobe’s hidden cancellation charge is illegal, FTC go well with says

0

Adobe’s hidden cancellation fee is unlawful, FTC suit says

Adobe prioritized earnings whereas spending years ignoring quite a few complaints from customers struggling to cancel expensive subscriptions with out incurring hefty hidden charges, the US Federal Commerce Fee (FTC) alleged in a lawsuit Monday.

In line with the FTC, Adobe knew that canceling subscriptions was laborious however decided that it could damage income to make canceling any simpler, so Adobe by no means modified the “convoluted” course of. Even when the FTC launched a probe in 2022 particularly indicating that Adobe’s practices could also be unlawful, Adobe did nothing to deal with the alleged hurt to customers, the FTC grievance famous. Adobe additionally “gives no refunds or solely partial refunds to some subscribers who incur expenses after an tried, unsuccessful cancellation.”

Adobe “repeatedly determined in opposition to rectifying a few of Adobe’s illegal practices due to the income implications,” the FTC alleged, asking a jury to completely block Adobe from persevering with the seemingly misleading practices.

Dana Rao, Adobe’s common counsel and chief belief officer, supplied a assertion confirming to Ars that Adobe plans to defend its enterprise practices in opposition to the FTC’s claims.

“Subscription providers are handy, versatile, and cost-effective to permit customers to decide on the plan that most closely fits their wants, timeline, and funds,” Rao stated. “Our precedence is to at all times guarantee our prospects have a optimistic expertise. We’re clear with the phrases and situations of our subscription agreements and have a easy cancellation course of. We’ll refute the FTC’s claims in courtroom.”

Cancellation charge allegedly used as retention device

The federal government’s closely redacted grievance laid out Adobe’s alleged scheme, which begins with “manipulative enrollment practices.”

To lock subscribers into recurring month-to-month funds, Adobe would sometimes pre-select by default its hottest “annual paid month-to-month” plan, the FTC alleged. That subscription possibility locked customers into an annual plan regardless of paying month to month. In the event that they canceled after a two-week interval, they’d owe Adobe an early termination charge (ETF) that prices 50 p.c of their remaining annual subscription. The “materials phrases” of this charge are hidden throughout enrollment, the FTC claimed, solely showing in “disclosures which can be designed to go unnoticed and that the majority customers by no means see.”

For particular person customers, accessing Adobe’s suite of apps can value greater than $700 yearly, Bloomberg reported. For a lot of customers all of the sudden confronted with paying an ETF value a whole lot whereas dropping entry to providers immediately, the choice to cancel just isn’t as simple because it may be with out the hidden charge. the FTC alleged.

As a result of Adobe allegedly solely alerted customers to the ETF in effective print—by hovering over a small icon or clicking a hyperlink in small textual content—whereas the corporate’s cancellation flows made it laborious to finish recurring funds, the FTC is suing and accusing Adobe of misleading practices beneath the FTC Act.

Moreover, Adobe’s “stealth ETF” could violate the Restore On-line Consumers’ Confidence Act (ROSCA), the FTC alleged.

Beneath ROSCA, Adobe’s ETF might be thought-about a “adverse function possibility” as a result of Adobe allegedly doesn’t clearly disclose the ETF throughout subscription sign-ups. Subsequently, Adobe solely will get a buyer to comply with pay the ETF by way of their “silence or failure to take an affirmative motion to reject items or providers or to cancel the settlement.”

ROSCA solely permits on-line companies to cost for items or providers by way of a adverse function possibility beneath sure situations. In Adobe’s case, the ETF would’ve wanted to be clearly disclosed previous to gathering billing data. In any other case, the shopper ought to have been requested to offer knowledgeable consent, or Adobe ought to have supplied “easy mechanisms to cease recurring expenses.”

Adobe did none of that, the FTC alleged, failing to offer “a easy means” to finish subscriptions and harming prospects who have been “ambushed” by ETFs that “can typically be a number of hundred {dollars}.”

Scattered Spider Boss Cuffed in Spain Boarding a Flight to Italy

0

The ringleader of brazen cybercrime ring Scattered Spider led profitable cyberattacks that introduced US powerhouse corporations like MGM Resorts and Caesars Leisure to a standstill. Extra not too long ago, he spent the previous couple of weeks dwelling in Spain. Nevertheless, the celebration, it appears, has abruptly ended.

The 22-year-old British nationwide is now within the custody of Spanish police after being arrested on the Palma Airport in Palma de Mallorca as he was attempting to board a flight to Italy, in keeping with stories from Murica Information. Police advised the outlet they imagine the suspect arrived in Barcelona on the finish of Might.

On the time of the arrest, the accused cybercriminal was in possession of a laptop computer, a cell phone, and maintained management of a $27 million Bitcoin fortune, the Spanish police added.

He’s accused of greater than 45 cyberattacks towards US corporations and a warrant for his arrest was issued by the FBI in Los Angeles, the stories added.

Profitable World Cybercrime Arrests Proceed

Worldwide legislation enforcement has been cracking down on cybercriminals over the previous few weeks.

On June 3 Europol introduced Operation Endgame, a coordinated legislation enforcement effort throughout the globe to trace down particular person cybercriminals, and added 5 Russian nationals to the checklist of Europe’s most wished fugitives. On June 12, Operation Endgame introduced the arrest of LockBit and Conti Ransomware developer in Ukraine.

Whereas the arrests ship an necessary message that searching down cybercriminals is a precedence for legislation enforcement, cybercrime teams proceed to function and adapt.

Simply days in the past, as an example, researchers at Mandiant mentioned they noticed Scattered Spider increasing into cyberattacks towards software-as-a-service (SaaS) purposes to ship ransomware.


Introducing Databricks LakeFlow: A unified, clever resolution for information engineering

0

At present, we’re excited to announce Databricks LakeFlow, a brand new resolution that incorporates every thing it is advisable to construct and function manufacturing information pipelines. It consists of new native, extremely scalable connectors for databases together with MySQL, Postgres, SQL Server and Oracle and enterprise purposes like Salesforce, Microsoft Dynamics, NetSuite, Workday, ServiceNow and Google Analytics. Customers can remodel information in batch and streaming utilizing customary SQL and Python. We’re additionally saying Actual Time Mode for Apache Spark, permitting stream processing at orders of magnitude quicker latencies than microbatch. Lastly, you possibly can orchestrate and monitor workflows and deploy to manufacturing utilizing CI/CD. Databricks LakeFlow is native to the Knowledge Intelligence Platform, offering serverless compute and unified governance with Unity Catalog.

LakeFlow
LakeFlow is the one unified information engineering resolution for ingestion, transformation and orchestration

On this weblog submit we talk about the the explanation why we consider LakeFlow will assist information groups meet the rising demand of dependable information and AI in addition to LakeFlow’s key capabilities built-in right into a single product expertise.

Challenges in constructing and working dependable information pipelines

Knowledge engineering – accumulating and getting ready contemporary, high-quality and dependable information – is a vital ingredient for democratizing information and AI in your small business. But reaching this stays filled with complexity and requires stitching collectively many various instruments.

 

First, information groups have to ingest information from a number of methods every with their very own codecs and entry strategies. This requires constructing and sustaining in-house connectors for databases and enterprise purposes. Simply maintaining with enterprise purposes’ API modifications is usually a full-time job for a complete information group. Knowledge then must be ready in each batch and streaming, which requires writing and sustaining complicated logic for triggering and incremental processing. When latency spikes or a failure happens, it means getting paged, a set of sad information shoppers and even disruptions to the enterprise that have an effect on the underside line. Lastly, information groups have to deploy these pipelines utilizing CI/CD and monitor the standard and lineage of knowledge property. This usually requires deploying, studying and managing one other solely new instrument like Prometheus or Grafana.

 

That is why we determined to construct LakeFlow, a unified resolution for information ingestion, transformation, and orchestration powered by information intelligence. Its three key elements are: LakeFlow Join, LakeFlow Pipelines and LakeFlow Jobs.

LakeFlow Join: Easy and scalable information ingestion 

LakeFlow Join supplies point-and-click information ingestion from databases reminiscent of MySQL, Postgres, SQL Server and Oracle and enterprise purposes like Salesforce, Microsoft Dynamics, NetSuite, Workday, ServiceNow and Google Analytics. LakeFlow Join can even ingest unstructured information reminiscent of PDFs and Excel spreadsheets from sources like SharePoint.

 

It extends our widespread native connectors for cloud storage (e.g. S3, ADLS Gen2 and GCS) and queues (e.g. Kafka, Kinesis, Occasion Hub and Pub/Sub connectors), and associate options reminiscent of Fivetran, Qlik and Informatica.

LakeFlow Connector
Setup an ingestion pipeline in a couple of straightforward steps with LakeFlow Join

We’re notably enthusiastic about database connectors, that are powered by our acquisition of Arcion. An unbelievable quantity of precious information is locked away in operational databases. As an alternative of naive approaches to load this information, which hit operational and scaling points, LakeFlows makes use of change information seize (CDC) know-how to make it easy, dependable and operationally environment friendly to deliver this information to your lakehouse.

 

Databricks prospects who’re utilizing LakeFlow Join discover {that a} easy ingestion resolution improves productiveness and lets them transfer quicker from information to insights. Insulet, a producer of a wearable insulin administration system, the Omnipod, makes use of the Salesforce ingestion connector to ingest information associated to buyer suggestions into their information resolution which is constructed on Databricks. This information is made obtainable for evaluation by means of Databricks SQL to achieve insights relating to high quality points and monitor buyer complaints. The group discovered vital worth in utilizing the brand new capabilities of LakeFlow Join.

“With the brand new Salesforce ingestion connector from Databricks, we have considerably streamlined our information integration course of by eliminating fragile and problematic middleware. This enchancment permits Databricks SQL to straight analyze Salesforce information inside Databricks. In consequence, our information practitioners can now ship up to date insights in near-real time, lowering latency from days to minutes.”

— Invoice Whiteley, Senior Director of AI,  Analytics, and Superior Algorithms, Insulet

LakeFlow Pipelines: Environment friendly declarative information pipelines

LakeFlow Pipelines decrease the complexity of constructing and managing environment friendly batch and streaming information pipelines. Constructed on the declarative Delta Stay Tables framework, they free you as much as write enterprise logic in SQL and Python whereas Databricks automates information orchestration, incremental processing and compute infrastructure autoscaling in your behalf. Furthermore, LakeFlow Pipelines provides built-in information high quality monitoring and its Actual Time Mode helps you to allow persistently low-latency supply of time-sensitive datasets with none code modifications.

LakeFlow Pipelines simplifies data pipeline automation
LakeFlow Pipelines simplifies information pipeline automation

LakeFlow Jobs: Dependable orchestration for each workload

LakeFlow Jobs reliably orchestrates and displays manufacturing workloads. Constructed on the superior capabilities of Databricks Workflows, it orchestrates any workload, together with ingestion, pipelines, notebooks, SQL queries, machine studying coaching, mannequin deployment and inference. Knowledge groups can even leverage triggers, branching and looping to satisfy complicated information supply use circumstances.

 

LakeFlow Jobs additionally automates and simplifies the method of understanding and monitoring information well being and supply. It takes a data-first view of well being, giving information groups full lineage together with relationships between ingestion, transformations, tables and dashboards. Moreover, it tracks information freshness and high quality, permitting information groups so as to add displays by way of Lakehouse Monitoring with the press of a button.

Constructed on the Knowledge Intelligence Platform

Databricks LakeFlow is natively built-in with our Knowledge Intelligence Platform, which brings these capabilities:

  • Knowledge intelligence: AI-powered intelligence is not only a characteristic of LakeFlow, it’s a foundational functionality that touches each facet of the product. Databricks Assistant powers the invention, authoring and monitoring of knowledge pipelines, so you possibly can spend extra time constructing dependable information.
  • Unified governance: LakeFlow can be deeply built-in with Unity Catalog, which powers lineage and information high quality. 
  • Serverless compute: Construct and orchestrate pipelines at scale and assist your group concentrate on work with out having to fret about infrastructure.

The way forward for information engineering is easy, unified and clever

We consider that LakeFlow will allow our prospects to ship brisker, extra full and higher-quality information to their companies. LakeFlow will enter preview quickly beginning with LakeFlow Join. If you need to request entry, join right here. Over the approaching months, search for extra LakeFlow bulletins as further capabilities turn into obtainable.

Mastering Nutanix Hyperconverged Infrastructure on Cisco’s Black Belt Academy

0

The digital panorama witnessed a big milestone on August 28, 2023, when Cisco and Nutanix unveiled a world strategic partnership that guarantees to be a game-changer within the realm of hybrid multi-cloud computing. This alliance is about to fast-track and streamline the hybrid multi-cloud expedition for purchasers, all whereas redefining the core rules of knowledge middle modernization. With the mixing of Nutanix’s premier software program platform and Cisco’s cutting-edge server portfolio, this collaboration has produced what’s arguably the business’s most sturdy and complete hyperconverged infrastructure resolution so far.

When Cisco introduced the Finish-of-Life for Cisco HyperFlex Information Platform (HXDP) on September 12, 2023; it left our prospects and companions equally overwhelmed. So, when Cisco proposed that the Nutanix Software program, working on Cisco’s {Hardware} can be a direct substitute of HyperFlex; we at Cisco Black Belt Academy made certain that our companions get immediate steerage on the brand new resolution with thorough particulars on its enhanced HCI capabilities topped with a path on transitioning or migrating from HyperFlex to Cisco’s HCI Answer with Nutanix.

The ”Chronicle” of Nutanix on Cisco Black Belt Academy

The Nutanix Stage 1 & 2 tracks on Cisco Black Belt Academy are launched for each Presales and Deployment roles. These tracks cowl:

1. Cisco’s Hyperconverged Technique

Explains how the partnership of Cisco and Nutanix is solid on their mixed edge on utility, information and infrastructure administration.

2. Introduction to the Hyper Converged Infrastructure

Makes our companions acquainted with Subsequent Era HCI, Advantages of HCI, Sustained improvements and HCI Vendor Panorama.

3. Answer Overview

Particulars Cisco Compute Hyperconverged resolution with Nutanix and covers it’s cloud infrastructure, broad Information Providers portfolio, Nutanix Cloud Supervisor, Nutanix Unified Storage and Prism, the Cloud Administration interface.

4. Structure Deep Dive

Elucidates why Nutanix Structure is totally different from different HCI options; Reveals how Cisco servers, storage, networking, and SaaS operations are mixed with the Nutanix Cloud Platform; explains how the controller VM’s are working to get a excessive efficiency construction; introduces resiliency and functioning of the storage layer.

5. Configuration & Deployment

In-depth demonstrations and methods surrounding Nutanix Deployment, protecting:

  • Preliminary Configurations/Information to getting began
  • Deploying the Nutanix Basis installer VM to a VMware ESX 7 cluster.
  • Deploying a Nutanix cluster on UCS servers managed by UCS Supervisor and including these hosts to vCenter.
  • Increasing a Nutanix cluster with a node that has been beforehand provisioned.
  • Deploying Prism Central from Prism Factor and registering the cluster with the newly created Prism Central.
  • Updating the UCS Server Firmware with Nutanix Life Cycle Supervisor (LCM) with out disrupting general cluster operations.

6. Migration from HyperFlex

Study the assorted choices emigrate current HyperFlex platforms to the brand new Nutanix Platform. Achieve an understanding of how Migrations of digital machines between clusters of VMware ESXi servers is most simply completed by way of “shared nothing” vMotion. As well as, be taught in regards to the a free software program software known as Transfer that Nutanix presents, which acts as an middleman agent and coordinator to maneuver VMs between two methods.

7. Sizing Cisco HCI with Nutanix

Discusses the Cisco HCI with Nutanix sizing primarily based on:

  • Output recordsdata from RVTools and Nutanix Collector instruments
  • Present HyperFlex and Nutanix Invoice Of Supplies (BOM)
  • VM-based and Capability-based sizing of the Cisco HCI with Nutanix utilizing Nutanix Sizer software.

8. Successful with Nutanix

Purchase a information of Nutanix differentiators available in the market, Insights on the aggressive surroundings and edge over VMware, HPE & Lenovo while protecting the methods to efficiently navigate CI and HCI buyer conversations.

9. Dcloud/Seize the Flag (CTF)

Arms on demo with entry to a easy Nutanix deployment on Cisco UCS, with Cisco Intersight, Nutanix Prism Factor, Nutanix AHV, Prism Central and Cisco UCS Supervisor. The Seize the Flag (CTF) missions present a gamified method of understanding what the brand new Cisco & Nutanix Partnership brings to the desk.

The Nutanix Stage 1 & 2 tracks on Cisco Black Belt Academy for both Presales and Deployment roles.

The place to be taught extra?

With the fashionable enterprise challenges and the ever-changing Market Dynamics, functions have develop into the middle for each buyer and these functions are rising at a quick tempo. IT groups are required to deploy these functions quicker and that too with a cloud working mannequin in place. Therefore, it turns into very important to be taught and perceive how the partnership of Cisco and Nutanix can assist ship the infrastructure and functions globally whereas utilizing the best-in-class cloud working fashions, that too with added resiliency and adaptability. The curriculum of “Cisco HCI resolution with Nutanix” on Cisco Black Belt Academy, can instill confidence to deal with buyer conversations and carry out a profitable PoC/PoV as a Presales SE or navigate thorough deployments of the Nutanix Answer as a subject engineer whereas migrating from the older HyperFlex base.

 

So, begin at the moment and get licensed! Go to our

 

 


We’d love to listen to what you suppose. Ask a Query, Remark Under, and Keep Related with #CiscoPartners on social!

Cisco Companions Fb  |  @CiscoPartners X/Twitter  |  Cisco Companions LinkedIn

Share:


Check-Driving HTML Templates

After a decade or extra the place Single-Web page-Purposes generated by
JavaScript frameworks have
grow to be the norm
, we see that server-side rendered HTML is turning into
widespread once more, additionally due to libraries corresponding to HTMX or Turbo. Writing a wealthy net UI in a
historically server-side language like Go or Java is not simply attainable,
however a really enticing proposition.

We then face the issue of how you can write automated exams for the HTML
elements of our net functions. Whereas the JavaScript world has advanced highly effective and subtle methods to check the UI,
ranging in dimension from unit-level to integration to end-to-end, in different
languages we would not have such a richness of instruments accessible.

When writing an internet software in Go or Java, HTML is usually generated
by way of templates, which include small fragments of logic. It’s actually
attainable to check them not directly by way of end-to-end exams, however these exams
are sluggish and costly.

We will as a substitute write unit exams that use CSS selectors to probe the
presence and proper content material of particular HTML components inside a doc.
Parameterizing these exams makes it simple so as to add new exams and to obviously
point out what particulars every take a look at is verifying. This method works with any
language that has entry to an HTML parsing library that helps CSS
selectors; examples are offered in Go and Java.

Degree 1: checking for sound HTML

The primary factor we wish to examine is that the HTML we produce is
principally sound. I do not imply to examine that HTML is legitimate in accordance with the
W3C; it will be cool to do it, but it surely’s higher to start out with a lot less complicated and quicker checks.
As an example, we wish our exams to
break if the template generates one thing like

<div>foo</p> 

Let’s examine how you can 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 jmustache
as a result of it is quite simple to make use of; Freemarker or
Velocity are different frequent selections.

Java

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

If we run this take a look at, it can fail, as a result of the index.tmpl file does
not exist. So we create it, with the above damaged HTML. Now the take a look at ought to move.

Then we create a mannequin for the template to make use of. The applying manages a todo-list, and
we are able to 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

  @Check   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 bytes 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

  @Check   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 wish to parse the HTML and we count on to see an
error, as a result of in our damaged HTML there’s a div component that
is closed by a p component. There’s an HTML parser within the Go
customary library, however it’s too lenient: if we run it on our damaged HTML, we do not get an
error. Fortunately, 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)     }        // examine that the template may 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()       change err {       case io.EOF:         return // We're carried out, it is legitimate!       case nil:         // do nothing       default:         t.Fatalf("Error parsing html: %s", err)       }     }   }

supply

This code configures the HTML parser to have the appropriate stage of leniency
for HTML, after which parses the HTML token by token. Certainly, we see the error
message we needed:

--- FAIL: Test_wellFormedHtml (0.00s)     index_template_test.go:61: Error parsing html: XML syntax error on line 4: surprising finish component </p> 

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

Java

  @Check   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();   }

supply

And we see it fail:

java.lang.AssertionError:  Anticipating empty however was:<[<1:13>: Unexpected EndTag token [</p>] when in state [InBody], 

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

The take a look at, nevertheless, is simply too verbose: we extract two helper features, in
order to make the intention of the take a look at clearer, and we get

Go

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

supply

Java

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

supply

Degree 2: testing HTML construction

What else ought to we take a look at?

We all know that the seems of a web page can solely be examined, in the end, by a
human how it’s rendered in a browser. Nonetheless, there may be usually
logic in templates, and we wish to have the ability to take a look at that logic.

One may be tempted to check the rendered HTML with string equality,
however this method fails in apply, as a result of templates include lots of
particulars that make string equality assertions impractical. The assertions
grow to be very verbose, and when studying the assertion, it turns into troublesome
to grasp what it’s that we’re attempting to show.

What we want
is a method to say that some elements of the rendered HTML
correspond to what we count on, and to ignore all the main points we do not
care about.
A method to do that is by operating queries with the CSS selector language:
it’s a highly effective language that enables us to pick out the
components that we care about from the entire HTML doc. As soon as now we have
chosen these components, we (1) rely that the variety of component returned
is what we count on, and (2) that they include the textual content or different content material
that we count on.

The UI that we’re speculated to generate seems like this:

Check-Driving HTML Templates

There are a number of particulars which can be rendered dynamically:

  1. The variety of gadgets and their textual content content material change, clearly
  2. The model of the todo-item modifications when it is accomplished (e.g., the
    second)
  3. The “2 gadgets left” textual content will change with the variety of non-completed
    gadgets
  4. One of many three buttons “All”, “Lively”, “Accomplished” might be
    highlighted, relying on the present url; as an illustration if we resolve that the
    url that reveals solely the “Lively” gadgets is /lively, then when the present url
    is /lively, the “Lively” button ought to be surrounded by a skinny purple
    rectangle
  5. The “Clear accomplished” button ought to solely be seen if any merchandise is
    accomplished

Every of this issues may be examined with the assistance of CSS selectors.

It is a snippet from the TodoMVC template (barely simplified). I
haven’t but added the dynamic bits, so what we see right here is static
content material, offered for example:

index.tmpl

  <part class="todoapp">     <ul class="todo-list">       <!-- These are right here simply to point out the construction of the record gadgets -->       <!-- Listing gadgets ought to get the category `accomplished` when marked as accomplished -->       <li class="accomplished">           <div class="view">           <enter class="toggle" kind="checkbox" checked>           <label>Style JavaScript</label>            <button class="destroy"></button>         </div>       </li>       <li>         <div class="view">           <enter class="toggle" kind="checkbox">           <label>Purchase a unicorn</label>            <button class="destroy"></button>         </div>       </li>     </ul>     <footer class="footer">       <!-- This ought to be `0 gadgets left` by default -->       <span class="todo-count"><sturdy>0</sturdy> merchandise left</span>        <ul class="filters">         <li>           <a class="chosen" href="#/">All</a>          </li>         <li>           <a href="#/lively">Lively</a>         </li>         <li>           <a href="#/accomplished">Accomplished</a>         </li>       </ul>       <!-- Hidden if no accomplished gadgets are left ↓ -->       <button class="clear-completed">Clear accomplished</button>      </footer>   </part>  

supply

By wanting on the static model of the template, we are able to deduce which
CSS selectors can be utilized to determine the related components for the 5 dynamic
options listed above:

function CSS selector
All of the gadgets ul.todo-list li
Accomplished gadgets ul.todo-list li.accomplished
Gadgets left span.todo-count
Highlighted navigation hyperlink ul.filters a.chosen
Clear accomplished button button.clear-completed

We will use these selectors to focus our exams on simply the issues we wish to take a look at.

Testing HTML content material

The primary take a look at will search for all of the gadgets, and show that the info
arrange by the take a look at is rendered accurately.

func Test_todoItemsAreShown(t *testing.T) {   mannequin := todo.NewList()   mannequin.Add("Foo")   mannequin.Add("Bar")   buf := renderTemplate(mannequin)   // assert there are two <li> components contained in the <ul class="todo-list">    // assert the primary <li> textual content is "Foo"   // assert the second <li> textual content is "Bar" } 

We’d like a approach to question the HTML doc with our CSS selector; an excellent
library for Go is goquery, that implements an API impressed by jQuery.
In Java, we maintain utilizing the identical library we used to check for sound HTML, specifically
jsoup. Our take a look at turns into:

Go

  func Test_todoItemsAreShown(t *testing.T) {     mannequin := todo.NewList()     mannequin.Add("Foo")     mannequin.Add("Bar")        buf := renderTemplate("index.tmpl", mannequin)        // parse the HTML with goquery     doc, err := goquery.NewDocumentFromReader(bytes.NewReader(buf.Bytes()))     if err != nil {       // if parsing fails, we cease the take a look at right here with t.FatalF       t.Fatalf("Error rendering template %s", err)     }        // assert there are two <li> components contained in the <ul class="todo-list">     choice := doc.Discover("ul.todo-list li")     assert.Equal(t, 2, choice.Size())        // assert the primary <li> textual content is "Foo"     assert.Equal(t, "Foo", textual content(choice.Nodes[0]))        // assert the second <li> textual content is "Bar"     assert.Equal(t, "Bar", textual content(choice.Nodes[1]))   }      func textual content(node *html.Node) string {     // A bit of mess on account of the truth that goquery has     // a .Textual content() methodology on Choice however not on html.Node     sel := goquery.Choice{Nodes: []*html.Node{node}}     return strings.TrimSpace(sel.Textual content())   }

supply

Java

  @Check   void todoItemsAreShown() throws IOException {       var mannequin = new TodoList();       mannequin.add("Foo");       mannequin.add("Bar");          var html = renderTemplate("/index.tmpl", mannequin);          // parse the HTML with jsoup       Doc doc = Jsoup.parse(html, "");          // assert there are two <li> components contained in the <ul class="todo-list">       var choice = doc.choose("ul.todo-list li");       assertThat(choice).hasSize(2);          // assert the primary <li> textual content is "Foo"       assertThat(choice.get(0).textual content()).isEqualTo("Foo");          // assert the second <li> textual content is "Bar"       assertThat(choice.get(1).textual content()).isEqualTo("Bar");   }

supply

If we nonetheless have not modified the template to populate the record from the
mannequin, this take a look at will fail, as a result of the static template
todo gadgets have completely different textual content:

Go

  --- FAIL: Test_todoItemsAreShown (0.00s)       index_template_test.go:44: First record merchandise: need Foo, bought Style JavaScript       index_template_test.go:49: Second record merchandise: need Bar, bought Purchase a unicorn

Java

  IndexTemplateTest > todoItemsAreShown() FAILED       org.opentest4j.AssertionFailedError:       Anticipating:        <"Style JavaScript">       to be equal to:        <"Foo">       however was not.

We repair it by making the template use the mannequin information:

Go

  <ul class="todo-list">     {{ vary .Gadgets }}       <li>         <div class="view">           <enter class="toggle" kind="checkbox">           <label>{{ .Title }}</label>           <button class="destroy"></button>         </div>       </li>     {{ finish }}   </ul>

supply

Java – jmustache

  <ul class="todo-list">     {{ #allItems }}     <li>       <div class="view">         <enter class="toggle" kind="checkbox">         <label>{{ title }}</label>         <button class="destroy"></button>       </div>     </li>     {{ /allItems }}   </ul>

supply

Check each content material and soundness on the identical time

Our take a look at works, however it’s a bit verbose, particularly the Go model. If we’ll have extra
exams, they’ll grow to be repetitive and troublesome to learn, so we make it extra concise by extracting a helper perform for parsing the html. We additionally take away the
feedback, because the code ought to be clear sufficient

Go

  func Test_todoItemsAreShown(t *testing.T) {     mannequin := todo.NewList()     mannequin.Add("Foo")     mannequin.Add("Bar")        buf := renderTemplate("index.tmpl", mannequin)        doc := parseHtml(t, buf)     choice := doc.Discover("ul.todo-list li")     assert.Equal(t, 2, choice.Size())     assert.Equal(t, "Foo", textual content(choice.Nodes[0]))     assert.Equal(t, "Bar", textual content(choice.Nodes[1]))   }      func parseHtml(t *testing.T, buf bytes.Buffer) *goquery.Doc {     doc, err := goquery.NewDocumentFromReader(bytes.NewReader(buf.Bytes()))     if err != nil {       // if parsing fails, we cease the take a look at right here with t.FatalF       t.Fatalf("Error rendering template %s", err)     }     return doc   } 

Java

  @Check   void todoItemsAreShown() throws IOException {       var mannequin = new TodoList();       mannequin.add("Foo");       mannequin.add("Bar");          var html = renderTemplate("/index.tmpl", mannequin);          var doc = parseHtml(html);       var choice = doc.choose("ul.todo-list li");       assertThat(choice).hasSize(2);       assertThat(choice.get(0).textual content()).isEqualTo("Foo");       assertThat(choice.get(1).textual content()).isEqualTo("Bar");   }      non-public static Doc parseHtml(String html) {       return Jsoup.parse(html, "");   } 

A lot better! At the least in my view. Now that we extracted the parseHtml helper, it is
a good suggestion to examine for sound HTML within the helper:

Go

  func parseHtml(t *testing.T, buf bytes.Buffer) *goquery.Doc {     assertWellFormedHtml(t, buf)     doc, err := goquery.NewDocumentFromReader(bytes.NewReader(buf.Bytes()))     if err != nil {       // if parsing fails, we cease the take a look at right here with t.FatalF       t.Fatalf("Error rendering template %s", err)     }     return doc   }

supply

Java

  non-public static Doc parseHtml(String html) {       var parser = Parser.htmlParser().setTrackErrors(10);       var doc = Jsoup.parse(html, "", parser);       assertThat(parser.getErrors()).isEmpty();       return doc;   }

supply

And with this, we are able to do away with the primary take a look at that we wrote, as we are actually testing for sound HTML on a regular basis.

The second take a look at

Now we’re in an excellent place for testing extra rendering logic. The
second dynamic function in our record is “Listing gadgets ought to get the category
accomplished when marked as accomplished”. We will write a take a look at for this:

Go

  func Test_completedItemsGetCompletedClass(t *testing.T) {     mannequin := todo.NewList()     mannequin.Add("Foo")     mannequin.AddCompleted("Bar")        buf := renderTemplate("index.tmpl", mannequin)        doc := parseHtml(t, buf)     choice := doc.Discover("ul.todo-list li.accomplished")     assert.Equal(t, 1, choice.Measurement())     assert.Equal(t, "Bar", textual content(choice.Nodes[0]))   }

supply

Java

  @Check   void completedItemsGetCompletedClass() {       var mannequin = new TodoList();       mannequin.add("Foo");       mannequin.addCompleted("Bar");          var html = renderTemplate("/index.tmpl", mannequin);          Doc doc = Jsoup.parse(html, "");       var choice = doc.choose("ul.todo-list li.accomplished");       assertThat(choice).hasSize(1);       assertThat(choice.textual content()).isEqualTo("Bar");   }

supply

And this take a look at may be made inexperienced by including this little bit of logic to the
template:

Go

  <ul class="todo-list">     {{ vary .Gadgets }}       <li class="{{ if .IsCompleted }}accomplished{{ finish }}">         <div class="view">           <enter class="toggle" kind="checkbox">           <label>{{ .Title }}</label>           <button class="destroy"></button>         </div>       </li>     {{ finish }}   </ul>

supply

Java – jmustache

  <ul class="todo-list">     {{ #allItems }}     <li class="{{ #isCompleted }}accomplished{{ /isCompleted }}">       <div class="view">         <enter class="toggle" kind="checkbox">         <label>{{ title }}</label>         <button class="destroy"></button>       </div>     </li>     {{ /allItems }}   </ul>

supply

So little by little, we are able to take a look at and add the assorted dynamic options
that our template ought to have.

Make it simple so as to add new exams

The primary of the 20 ideas from the superb discuss by Russ Cox on Go
Testing
is “Make it simple so as to add new take a look at circumstances“. Certainly, in Go there
is a bent to make most exams parameterized, for this very cause.
Alternatively, whereas Java has
good assist
for parameterized exams
with JUnit 5, they aren’t used as a lot.

Since our present two exams have the identical construction, we
may issue them right into a single parameterized take a look at.

A take a look at case for us will encompass:

  • A reputation (in order that we are able to produce clear error messages when the take a look at
    fails)
  • A mannequin (in our case a todo.Listing)
  • A CSS selector
  • A listing of textual content matches that we anticipate finding once we run the CSS
    selector on the rendered HTML.

So that is the info construction for our take a look at circumstances:

Go

  var testCases = []struct {     title     string     mannequin    *todo.Listing     selector string     matches  []string   }{     {       title: "all todo gadgets are proven",       mannequin: todo.NewList().         Add("Foo").         Add("Bar"),       selector: "ul.todo-list li",       matches:  []string{"Foo", "Bar"},     },     {       title: "accomplished gadgets get the 'accomplished' class",       mannequin: todo.NewList().         Add("Foo").         AddCompleted("Bar"),       selector: "ul.todo-list li.accomplished",       matches:  []string{"Bar"},     },   }

supply

Java

  file TestCase(String title,                   TodoList mannequin,                   String selector,                   Listing<String> matches) {       @Override       public String toString() {           return title;       }   }      public static TestCase[] indexTestCases() {       return new TestCase[]{               new TestCase(                       "all todo gadgets are proven",                       new TodoList()                               .add("Foo")                               .add("Bar"),                       "ul.todo-list li",                       Listing.of("Foo", "Bar")),               new TestCase(                       "accomplished gadgets get the 'accomplished' class",                       new TodoList()                               .add("Foo")                               .addCompleted("Bar"),                       "ul.todo-list li.accomplished",                       Listing.of("Bar")),       };   }

supply

And that is our parameterized take a look at:

Go

  func Test_indexTemplate(t *testing.T) {     for _, take a look at := vary testCases {       t.Run(take a look at.title, func(t *testing.T) {         buf := renderTemplate("index.tmpl", take a look at.mannequin)            assertWellFormedHtml(t, buf)         doc := parseHtml(t, buf)         choice := doc.Discover(take a look at.selector)         require.Equal(t, len(take a look at.matches), len(choice.Nodes), "surprising # of matches")         for i, node := vary choice.Nodes {           assert.Equal(t, take a look at.matches[i], textual content(node))         }       })     }   }

supply

Java

  @ParameterizedTest   @MethodSource("indexTestCases")   void testIndexTemplate(TestCase take a look at) {       var html = renderTemplate("/index.tmpl", take a look at.mannequin);          var doc = parseHtml(html);       var choice = doc.choose(take a look at.selector);       assertThat(choice).hasSize(take a look at.matches.dimension());       for (int i = 0; i < take a look at.matches.dimension(); i++) {           assertThat(choice.get(i).textual content()).isEqualTo(take a look at.matches.get(i));       }   }

supply

We will now run our parameterized take a look at and see it move:

Go

  $ go take a look at -v   === RUN   Test_indexTemplate   === RUN   Test_indexTemplate/all_todo_items_are_shown   === RUN   Test_indexTemplate/completed_items_get_the_'accomplished'_class   --- PASS: Test_indexTemplate (0.00s)       --- PASS: Test_indexTemplate/all_todo_items_are_shown (0.00s)       --- PASS: Test_indexTemplate/completed_items_get_the_'accomplished'_class (0.00s)   PASS   okay    tdd-html-templates  0.608s

Java

  $ ./gradlew take a look at      > Activity :take a look at      IndexTemplateTest > testIndexTemplate(TestCase) > [1] all todo gadgets are proven PASSED   IndexTemplateTest > testIndexTemplate(TestCase) > [2] accomplished gadgets get the 'accomplished' class PASSED

Be aware how, by giving a reputation to our take a look at circumstances, we get very readable take a look at output, each on the terminal and within the IDE:

Having rewritten our two outdated exams in desk type, it is now tremendous simple so as to add
one other. That is the take a look at for the “x gadgets left” textual content:

Go

  {     title: "gadgets left",     mannequin: todo.NewList().       Add("One").       Add("Two").       AddCompleted("Three"),     selector: "span.todo-count",     matches:  []string{"2 gadgets left"},   },

supply

Java

  new TestCase(       "gadgets left",       new TodoList()               .add("One")               .add("Two")               .addCompleted("Three"),       "span.todo-count",       Listing.of("2 gadgets left")),

supply

And the corresponding change within the html template is:

Go

  <span class="todo-count"><sturdy>{{len .ActiveItems}}</sturdy> gadgets left</span>

supply

Java – jmustache

  <span class="todo-count"><sturdy>{{activeItemsCount}}</sturdy> gadgets left</span>

supply

The above change within the template requires a supporting methodology within the mannequin:

Go

  kind Merchandise struct {     Title       string     IsCompleted bool   }      kind Listing struct {     Gadgets []*Merchandise   }      func (l *Listing) ActiveItems() []*Merchandise {     var end result []*Merchandise     for _, merchandise := vary l.Gadgets {       if !merchandise.IsCompleted {         end result = append(end result, merchandise)       }     }     return end result   } 

supply

Java

  public class TodoList {       non-public last Listing<TodoItem> gadgets = new ArrayList<>();       // ...       public lengthy activeItemsCount() {           return gadgets.stream().filter(TodoItem::isActive).rely();       }   }

supply

We have invested slightly effort in our testing infrastructure, in order that including new
take a look at circumstances is simpler. Within the subsequent part, we’ll see that the necessities
for the following take a look at circumstances will push us to refine our take a look at infrastructure additional.

Making the desk extra expressive, on the expense of the take a look at code

We are going to now take a look at the “All”, “Lively” and “Accomplished” navigation hyperlinks at
the underside of the UI (see the image above),
and these depend upon which url we’re visiting, which is
one thing that our template has no approach to discover out.

Presently, all we move to our template is our mannequin, which is a todo-list.
It is not appropriate so as to add the at the moment visited url to the mannequin, as a result of that’s
consumer navigation state, not software state.

So we have to move extra info to the template past the mannequin. A straightforward method
is to move a map, which we assemble in our
renderTemplate perform:

Go

  func renderTemplate(mannequin *todo.Listing, path string) bytes.Buffer {     templ := template.Should(template.ParseFiles("index.tmpl"))     var buf bytes.Buffer     information := map[string]any{       "mannequin": mannequin,       "path":  path,     }     err := templ.Execute(&buf, information)     if err != nil {       panic(err)     }     return buf   }

Java

  non-public String renderTemplate(String templateName, TodoList mannequin, String path) {       var template = Mustache.compiler().compile(               new InputStreamReader(                       getClass().getResourceAsStream(templateName)));       var information = Map.of(               "mannequin", mannequin,               "path", path       );       return template.execute(information);   }

And correspondingly our take a look at circumstances desk has yet another area:

Go

  var testCases = []struct {     title     string     mannequin    *todo.Listing     path     string     selector string     matches  []string   }{     {       title: "all todo gadgets are proven",       mannequin: todo.NewList().         Add("Foo").         Add("Bar"),       selector: "ul.todo-list li",       matches:  []string{"Foo", "Bar"},     },   // ... the opposite circumstances     {       title:     "highlighted navigation hyperlink: All",       path:     "/",       selector: "ul.filters a.chosen",       matches:  []string{"All"},     },     {       title:     "highlighted navigation hyperlink: Lively",       path:     "/lively",       selector: "ul.filters a.chosen",       matches:  []string{"Lively"},     },     {       title:     "highlighted navigation hyperlink: Accomplished",       path:     "/accomplished",       selector: "ul.filters a.chosen",       matches:  []string{"Accomplished"},     },   }

Java

  file TestCase(String title,                   TodoList mannequin,                   String path,                   String selector,                   Listing<String> matches) {       @Override       public String toString() {           return title;       }   }      public static TestCase[] indexTestCases() {       return new TestCase[]{               new TestCase(                       "all todo gadgets are proven",                       new TodoList()                               .add("Foo")                               .add("Bar"),                       "/",                       "ul.todo-list li",                       Listing.of("Foo", "Bar")),               // ... the earlier circumstances               new TestCase(                       "highlighted navigation hyperlink: All",                       new TodoList(),                       "/",                       "ul.filters a.chosen",                       Listing.of("All")),               new TestCase(                       "highlighted navigation hyperlink: Lively",                       new TodoList(),                       "/lively",                       "ul.filters a.chosen",                       Listing.of("Lively")),               new TestCase(                       "highlighted navigation hyperlink: Accomplished",                       new TodoList(),                       "/accomplished",                       "ul.filters a.chosen",                       Listing.of("Accomplished")),       };   }

We discover that for the three new circumstances, the mannequin is irrelevant;
whereas for the earlier circumstances, the trail is irrelevant. The Go syntax permits us
to initialize a struct with simply the fields we’re occupied with, however Java doesn’t have
the same function, so we’re pushed to move additional info, and this makes the take a look at circumstances
desk tougher to grasp.

A developer may take a look at the primary take a look at case and marvel if the anticipated conduct relies upon
on the trail being set to "/", and may be tempted so as to add extra circumstances with
a unique path. In the identical method, when studying the
highlighted navigation hyperlink take a look at circumstances, the developer may marvel if the
anticipated conduct relies on the mannequin being set to an empty todo record. In that case, one may
be led so as to add irrelevant take a look at circumstances for the highlighted hyperlink with non-empty todo-lists.

We wish to optimize for the time of the builders, so it is worthwhile to keep away from including irrelevant
information to our take a look at case. In Java we’d move null for the
irrelevant fields, however there’s a greater method: we are able to use
the builder sample,
popularized by Joshua Bloch.
We will rapidly write one for the Java TestCase file this manner:

Java

  file TestCase(String title,                   TodoList mannequin,                   String path,                   String selector,                   Listing<String> matches) {       @Override       public String toString() {           return title;       }          public static last class Builder {           String title;           TodoList mannequin;           String path;           String selector;           Listing<String> matches;              public Builder title(String title) {               this.title = title;               return this;           }              public Builder mannequin(TodoList mannequin) {               this.mannequin = mannequin;               return this;           }              public Builder path(String path) {               this.path = path;               return this;           }              public Builder selector(String selector) {               this.selector = selector;               return this;           }              public Builder matches(String ... matches) {               this.matches = Arrays.asList(matches);               return this;           }              public TestCase construct() {               return new TestCase(title, mannequin, path, selector, matches);           }       }   }

Hand-coding builders is slightly tedious, however doable, although there are
automated methods to jot down them.
Now we are able to rewrite our Java take a look at circumstances with the Builder, to
obtain larger readability:

Java

  public static TestCase[] indexTestCases() {       return new TestCase[]{               new TestCase.Builder()                       .title("all todo gadgets are proven")                       .mannequin(new TodoList()                               .add("Foo")                               .add("Bar"))                       .selector("ul.todo-list li")                       .matches("Foo", "Bar")                       .construct(),               // ... different circumstances               new TestCase.Builder()                       .title("highlighted navigation hyperlink: Accomplished")                       .path("/accomplished")                       .selector("ul.filters a.chosen")                       .matches("Accomplished")                       .construct(),       };   }

So, the place are we with our exams? At current, they fail for the unsuitable cause: null-pointer exceptions
as a result of lacking mannequin and path values.
So as to get our new take a look at circumstances to fail for the appropriate cause, specifically that the template does
not but have logic to focus on the right hyperlink, we should
present default values for mannequin and path. In Go, we are able to do that
within the take a look at methodology:

Go

  func Test_indexTemplate(t *testing.T) {     for _, take a look at := vary testCases {       t.Run(take a look at.title, func(t *testing.T) {         if take a look at.mannequin == nil {           take a look at.mannequin = todo.NewList()         }         buf := renderTemplate(take a look at.mannequin, take a look at.path)         // ... identical as earlier than        })     }   }

supply

In Java, we are able to present default values within the builder:

Java

  public static last class Builder {       String title;       TodoList mannequin = new TodoList();       String path = "/";       String selector;       Listing<String> matches;       // ...   }

supply

With these modifications, we see that the final two take a look at circumstances, those for the highlighted hyperlink Lively
and Accomplished fail, for the anticipated cause that the highlighted hyperlink doesn’t change:

Go

  === RUN   Test_indexTemplate/highlighted_navigation_link:_Active       index_template_test.go:82:              Error Hint:  .../tdd-templates/go/index_template_test.go:82             Error:        Not equal:                            anticipated: "Lively"                           precise  : "All"   === RUN   Test_indexTemplate/highlighted_navigation_link:_Completed       index_template_test.go:82:              Error Hint:  .../tdd-templates/go/index_template_test.go:82             Error:        Not equal:                            anticipated: "Accomplished"                           precise  : "All" 

Java

  IndexTemplateTest > testIndexTemplate(TestCase) > [5] highlighted navigation hyperlink: Lively FAILED       org.opentest4j.AssertionFailedError:       Anticipating:        <"All">       to be equal to:        <"Lively">       however was not.      IndexTemplateTest > testIndexTemplate(TestCase) > [6] highlighted navigation hyperlink: Accomplished FAILED       org.opentest4j.AssertionFailedError:       Anticipating:        <"All">       to be equal to:        <"Accomplished">       however was not.

To make the exams move, we make these modifications to the template:

Go

  <ul class="filters">     <li>       <a class="{{ if eq .path "/" }}chosen{{ finish }}" href="#/">All</a>     </li>     <li>       <a class="{{ if eq .path "/lively" }}chosen{{ finish }}" href="#/lively">Lively</a>     </li>     <li>       <a class="{{ if eq .path "/accomplished" }}chosen{{ finish }}" href="#/accomplished">Accomplished</a>     </li>   </ul>

supply

Java – jmustache

  <ul class="filters">     <li>       <a class="{{ #pathRoot }}chosen{{ /pathRoot }}" href="#/">All</a>     </li>     <li>       <a class="{{ #pathActive }}chosen{{ /pathActive }}" href="#/lively">Lively</a>     </li>     <li>       <a class="{{ #pathCompleted }}chosen{{ /pathCompleted }}" href="#/accomplished">Accomplished</a>     </li>   </ul>

supply

For the reason that Mustache template language doesn’t enable for equality testing, we should change the
information handed to the template in order that we execute the equality exams earlier than rendering the template:

Java

  non-public String renderTemplate(String templateName, TodoList mannequin, String path) {       var template = Mustache.compiler().compile(               new InputStreamReader(                       getClass().getResourceAsStream(templateName)));       var information = Map.of(               "mannequin", mannequin,               "pathRoot", path.equals("/"),               "pathActive", path.equals("/lively"),               "pathCompleted", path.equals("/accomplished")       );       return template.execute(information);   }

supply

And with these modifications, all of our exams now move.

To recap this part, we made the take a look at code slightly bit extra difficult, in order that the take a look at
circumstances are clearer: it is a excellent tradeoff!

Degree 3: testing HTML behaviour

Within the story to this point, we examined the behaviour of the HTML
templates
, by checking the construction of the generated HTML.
That is good, however what if we needed to check the behaviour of the HTML
itself, plus any CSS and JavaScript it could use?

The behaviour of HTML by itself is often fairly apparent, as a result of
there may be not a lot of it. The one components that may work together with the
consumer are the anchor (<a>), <type> and
<enter> components, however the image modifications utterly when
we add CSS, that may disguise, present, transfer round issues and much extra, and
with JavaScript, that may add any behaviour to a web page.

In an software that’s primarily rendered server-side, we count on
that the majority behaviour is applied by returning new HTML with a
round-trip to the consumer, and this may be examined adequately with the
strategies we have seen to this point, however what if we needed to hurry up the
software behaviour with a library corresponding to HTMX? This library works by way of particular
attributes which can be added to components so as to add Ajax behaviour. These
attributes are in impact a DSL that we’d wish to
take a look at.

How can we take a look at the mixture of HTML, CSS and JavaScript in
a unit take a look at?

Testing HTML, CSS and JavaScript requires one thing that is ready to
interpret and execute their behaviours; in different phrases, we want a
browser! It’s customary to make use of headless browsers in end-to-end exams;
can we use them for unitary exams as a substitute? I believe that is attainable,
utilizing the next strategies, though I have to admit I’ve but to attempt
this on an actual mission.

We are going to use the Playwright
library, that’s accessible for each Go and
Java. The exams we
are going to jot down might be slower, as a result of we must wait a couple of
seconds for the headless browser to start out, however will retain among the
vital traits of unit exams, primarily that we’re testing
simply the HTML (and any related CSS and JavaScript), in isolation from
some other server-side logic.

Persevering with with the TodoMVC
instance, the following factor we’d wish to take a look at is what occurs when the
consumer clicks on the checkbox of a todo merchandise. What we might prefer to occur is
that:

  1. A POST name to the server is made, in order that the applying is aware of
    that the state of a todo merchandise has modified
  2. The server returns new HTML for the dynamic a part of the web page,
    specifically the entire part with class “todoapp”, in order that we are able to present the
    new state of the applying together with the rely of remaining “lively”
    gadgets (see the template above)
  3. The web page replaces the outdated contents of the “todoapp” part with
    the brand new ones.

Loading the web page within the Playwright browser

We begin with a take a look at that may simply load the preliminary HTML. The take a look at
is slightly concerned, so I present the whole code right here, after which I’ll
remark it little by little.

Go

  func Test_toggleTodoItem(t *testing.T) {     // render the preliminary HTML     mannequin := todo.NewList().       Add("One").       Add("Two")     initialHtml := renderTemplate("index.tmpl", mannequin, "/")        // open the browser web page with Playwright     web page := openPage()     defer web page.Shut()     logActivity(web page)        // stub community calls     err := web page.Route("**", func(route playwright.Route) {       if route.Request().URL() == "http://localhost:4567/index.html" {         // serve the preliminary HTML         stubResponse(route, initialHtml.String(), "textual content/html")       } else {         // keep away from surprising requests         panic("surprising request: " + route.Request().URL())       }     })     if err != nil {       t.Deadly(err)     }        // load preliminary HTML within the web page     response, err := web page.Goto("http://localhost:4567/index.html")     if err != nil {       t.Deadly(err)     }     if response.Standing() != 200 {       t.Fatalf("surprising standing: %d", response.Standing())     }   }

supply

Java

  public class IndexBehaviourTest {       static Playwright playwright;       static Browser browser;          @BeforeAll       static void launchBrowser() {           playwright = Playwright.create();           browser = playwright.chromium().launch();       }          @AfterAll       static void closeBrowser() {           playwright.shut();       }          @Check       void toggleTodoItem() {           // Render the preliminary html           TodoList mannequin = new TodoList()                   .add("One")                   .add("Two");           String initialHtml = renderTemplate("/index.tmpl", mannequin, "/");                      attempt (Web page web page = browser.newPage()) {               logActivity(web page);                  // stub community calls               web page.route("**", route -> {                   if (route.request().url().equals("http://localhost:4567/index.html")) {                       // serve the preliminary HTML                       route.fulfill(new Route.FulfillOptions()                               .setContentType("textual content/html")                               .setBody(initialHtml));                   } else {                       // we do not need surprising calls                       fail(String.format("Sudden request: %s %s", route.request().methodology(), route.request().url()));                   }               });                          // load preliminary html               web page.navigate("http://localhost:4567/index.html");           }       }   }

supply

Firstly of the take a look at, we initialize the mannequin with two todo
gadgets “One” and “Two”, then we render the template as earlier than:

Go

  mannequin := todo.NewList().     Add("One").     Add("Two")   initialHtml := renderTemplate("index.tmpl", mannequin, "/") 

Java

  TodoList mannequin = new TodoList()           .add("One")           .add("Two");   String initialHtml = renderTemplate("/index.tmpl", mannequin, "/");

Then we open the Playwright “web page”, which can begin a headless
browser

Go

  web page := openPage()   defer web page.Shut()   logActivity(web page) 

Java

  attempt (Web page web page = browser.newPage()) {       logActivity(web page);

The openPage perform in Go returns a Playwright
Web page object,

Go

  func openPage() playwright.Web page {     pw, err := playwright.Run()     if err != nil {       log.Fatalf("couldn't begin playwright: %v", err)     }     browser, err := pw.Chromium.Launch()     if err != nil {       log.Fatalf("couldn't launch browser: %v", err)     }     web page, err := browser.NewPage()     if err != nil {       log.Fatalf("couldn't create web page: %v", err)     }     return web page   }

and the logActivity perform gives suggestions on what
the web page is doing

Go

  func logActivity(web page playwright.Web page) {     web page.OnRequest(func(request playwright.Request) {       log.Printf(">> %s %sn", request.Methodology(), request.URL())     })     web page.OnResponse(func(response playwright.Response) {       log.Printf("<< %d %sn", response.Standing(), response.URL())     })     web page.OnLoad(func(web page playwright.Web page) {       log.Println("Loaded: " + web page.URL())     })     web page.OnConsole(func(message playwright.ConsoleMessage) {       log.Println("!  " + message.Textual content())     })   }

Java

  non-public void logActivity(Web page web page) {       web page.onRequest(request -> System.out.printf(">> %s %spercentn", request.methodology(), request.url()));       web page.onResponse(response -> System.out.printf("<< %s %spercentn", response.standing(), response.url()));       web page.onLoad(page1 -> System.out.println("Loaded: " + page1.url()));       web page.onConsoleMessage(consoleMessage -> System.out.println("!  " + consoleMessage.textual content()));   }

Then we stub all community exercise that the web page may attempt to do

Go

  err := web page.Route("**", func(route playwright.Route) {     if route.Request().URL() == "http://localhost:4567/index.html" {       // serve the preliminary HTML       stubResponse(route, initialHtml.String(), "textual content/html")     } else {       // keep away from surprising requests       panic("surprising request: " + route.Request().URL())     }   }) 

Java

  // stub community calls   web page.route("**", route -> {       if (route.request().url().equals("http://localhost:4567/index.html")) {           // serve the preliminary HTML           route.fulfill(new Route.FulfillOptions()                   .setContentType("textual content/html")                   .setBody(initialHtml));       } else {           // we do not need surprising calls           fail(String.format("Sudden request: %s %s", route.request().methodology(), route.request().url()));       }   });

and we ask the web page to load the preliminary HTML

Go

  response, err := web page.Goto("http://localhost:4567/index.html") 

Java

  web page.navigate("http://localhost:4567/index.html");

With all this equipment in place, we run the take a look at; it succeeds and
it logs the stubbed community exercise on customary output:

Go

  === RUN   Test_toggleTodoItem   >> GET http://localhost:4567/index.html   << 200 http://localhost:4567/index.html   Loaded: http://localhost:4567/index.html   --- PASS: Test_toggleTodoItem (0.89s)

Java

  IndexBehaviourTest > toggleTodoItem() STANDARD_OUT       >> GET http://localhost:4567/index.html       << 200 http://localhost:4567/index.html       Loaded: http://localhost:4567/index.html      IndexBehaviourTest > toggleTodoItem() PASSED

So with this take a look at we are actually capable of load arbitrary HTML in a
headless browser. Within the subsequent sections we’ll see how you can simulate consumer
interplay with components of the web page, and observe the web page’s
behaviour. However first we have to resolve an issue with the shortage of
identifiers in our area mannequin.

Figuring out todo gadgets

Now we wish to click on on the “One” checkbox. The issue now we have is
that at current, now we have no approach to determine particular person todo gadgets, so
we introduce an Id area within the todo merchandise:

Go – up to date mannequin with Id

  kind Merchandise struct {     Id          int     Title       string     IsCompleted bool   }      func (l *Listing) AddWithId(id int, title string) *Listing {     merchandise := Merchandise{       Id:    id,       Title: title,     }     l.Gadgets = append(l.Gadgets, &merchandise)     return l   }      // Add creates a brand new todo.Merchandise with a random Id   func (l *Listing) Add(title string) *Listing {     merchandise := Merchandise{       Id:    generateRandomId(),       Title: title,     }     l.Gadgets = append(l.Gadgets, &merchandise)     return l   }      func generateRandomId() int {     return abs(rand.Int())   }

Java – up to date mannequin with Id

  public class TodoList {       non-public last Listing<TodoItem> gadgets = new ArrayList<>();          public TodoList add(String title) {           gadgets.add(new TodoItem(generateRandomId(), title, false));           return this;       }          public TodoList addCompleted(String title) {           gadgets.add(new TodoItem(generateRandomId(), title, true));           return this;       }          public TodoList add(int id, String title) {           gadgets.add(new TodoItem(id, title, false));           return this;       }          non-public static int generateRandomId() {           return new Random().nextInt(0, Integer.MAX_VALUE);       }   }      public file TodoItem(int id, String title, boolean isCompleted) {       public boolean isActive() {           return !isCompleted;       }   }

And we replace the mannequin in our take a look at so as to add express Ids

Go – including Id within the take a look at information

  func Test_toggleTodoItem(t *testing.T) {     // render the preliminary HTML     mannequin := todo.NewList().       AddWithId(101, "One").       AddWithId(102, "Two")     initialHtml := renderTemplate("index.tmpl", mannequin, "/")     // ...    }

Java – including Id within the take a look at information

  @Check   void toggleTodoItem() {       // Render the preliminary html       TodoList mannequin = new TodoList()               .add(101, "One")               .add(102, "Two");       String initialHtml = renderTemplate("/index.tmpl", mannequin, "/");   }

We are actually prepared to check consumer interplay with the web page.

Clicking on a todo merchandise

We wish to simulate consumer interplay with the HTML web page. It may be
tempting to proceed to make use of CSS selectors to determine the particular
checkbox that we wish to click on, however there’s a greater method: there’s a
consensus amongst front-end builders that one of the best ways to check
interplay with a web page is to make use of it
the identical method that customers do
. As an example, you do not search for a
button by way of a CSS locator corresponding to button.purchase; as a substitute,
you search for one thing clickable with the label “Purchase”. In apply,
this implies figuring out elements of the web page by way of their
ARIA
roles.

To this finish, we add code to our take a look at to search for a checkbox labelled
“One”:

Go

  func Test_toggleTodoItem(t *testing.T) {     // ...     // click on on the "One" checkbox     checkbox := web page.GetByRole(*playwright.AriaRoleCheckbox, playwright.PageGetByRoleOptions{Identify: "One"})     if err := checkbox.Click on(); err != nil {       t.Deadly(err)     }   }

Java

  @Check   void toggleTodoItem() {           // ...           // click on on the "One" checkbox           var checkbox = web page.getByRole(AriaRole.CHECKBOX, new Web page.GetByRoleOptions().setName("One"));           checkbox.click on();       }   }

We run the take a look at, and it fails:

Go

  >> GET http://localhost:4567/index.html   << 200 http://localhost:4567/index.html   Loaded: http://localhost:4567/index.html   --- FAIL: Test_toggleTodoItem (32.74s)       index_behaviour_test.go:50: playwright: timeout: Timeout 30000ms exceeded.

Java

  IndexBehaviourTest > toggleTodoItem() STANDARD_OUT       >> GET http://localhost:4567/index.html       << 200 http://localhost:4567/index.html       Loaded: http://localhost:4567/index.html      IndexBehaviourTest > toggleTodoItem() FAILED       com.microsoft.playwright.TimeoutError: Error {         message="hyperlink the label to the checkbox correctly: 

generated HTML with dangerous accessibility

  <li>     <div class="view">       <enter class="toggle" kind="checkbox">       <label>One</label>       <button class="destroy"></button>     </div>   </li>

We repair it through the use of the for attribute within the
template,

index.tmpl – Go

  <li>     <div class="view">       <enter id="checkbox-{{.Id}}" class="toggle" kind="checkbox">       <label for="checkbox-{{.Id}}">{{.Title}}</label>       <button class="destroy"></button>     </div>   </li>

index.tmpl – Java

  <li>     <div class="view">       <enter id="checkbox-{{ id }}" class="toggle" kind="checkbox">       <label for="checkbox-{{ id }}">{{ title }}</label>       <button class="destroy"></button>     </div>   </li>

In order that it generates correct, accessible HTML:

generated HTML with higher accessibility

  <li>     <div class="view">       <enter id="checkbox-101" class="toggle" kind="checkbox">       <label for="checkbox-101">One</label>       <button class="destroy"></button>     </div>   </li>

We run once more the take a look at, and it passes.

On this part we noticed how testing the HTML in the identical was as customers
work together with it led us to make use of ARIA roles, which led to enhancing
accessibility of our generated HTML. Within the subsequent part, we'll see
how you can take a look at that the clicking on a todo merchandise triggers a distant name to the
server, that ought to lead to swapping part of the present HTML with
the HTML returned by the XHR name.

Spherical-trip to the server

Now we’ll prolong our take a look at. We inform the take a look at that if name to
POST /toggle/101 is obtained, it ought to return some
stubbed HTML.

Go

  } else if route.Request().URL() == "http://localhost:4567/toggle/101" && route.Request().Methodology() == "POST" {     // we count on {that a} POST /toggle/101 request is made once we click on on the "One" checkbox     const stubbedHtml = `       <part class="todoapp">         <p>Stubbed html</p>       </part>`     stubResponse(route, stubbedHtml, "textual content/html")

Java

  } else if (route.request().url().equals("http://localhost:4567/toggle/101") && route.request().methodology().equals("POST")) {       // we count on {that a} POST /toggle/101 request is made once we click on on the "One" checkbox       String stubbedHtml = """           <part class="todoapp">               <p>Stubbed html</p>           </part>           """;       route.fulfill(new Route.FulfillOptions()               .setContentType("textual content/html")               .setBody(stubbedHtml));

And we stub the loading of the HTMX library, which we load from a
native file:

Go

  } else if route.Request().URL() == "https://unpkg.com/htmx.org@1.9.12" {     // serve the htmx library     stubResponse(route, readFile("testdata/htmx.min.js"), "software/javascript")

Go

  } else if (route.request().url().equals("https://unpkg.com/htmx.org@1.9.12")) {       // serve the htmx library       route.fulfill(new Route.FulfillOptions()               .setContentType("textual content/html")               .setBody(readFile("/htmx.min.js")));

Lastly, we add the expectation that, after we click on the checkbox,
the part of the HTML that incorporates many of the software is
reloaded.

Go

  // click on on the "One" checkbox   checkbox := web page.GetByRole(*playwright.AriaRoleCheckbox, playwright.PageGetByRoleOptions{Identify: "One"})   if err := checkbox.Click on(); err != nil {     t.Deadly(err)   }   // examine that the web page has been up to date   doc := parseHtml(t, content material(t, web page))   components := doc.Discover("physique > part.todoapp > p")   assert.Equal(t, "Stubbed html", components.Textual content(), should(web page.Content material())) 

java

  // click on on the "One" checkbox   var checkbox = web page.getByRole(AriaRole.CHECKBOX, new Web page.GetByRoleOptions().setName("One"));   checkbox.click on();   // examine that the web page has been up to date   var doc = parseHtml(web page.content material());   var components = doc.choose("physique > part.todoapp > p");   assertThat(components.textual content())           .describedAs(web page.content material())           .isEqualTo("Stubbed html");

We run the take a look at, and it fails, as anticipated. So as to perceive
why precisely it fails, we add to the error message the entire HTML
doc.

Go

  assert.Equal(t, "Stubbed html", components.Textual content(), should(web page.Content material())) 

Java

  assertThat(components.textual content())           .describedAs(web page.content material())           .isEqualTo("Stubbed html");

The error message may be very verbose, however we see that the explanation it
fails is that we do not see the stubbed HTML within the output. This implies
that the web page didn’t make the anticipated XHR name.

Go – Java is analogous

  --- FAIL: Test_toggleTodoItem (2.75s)   === RUN   Test_toggleTodoItem   >> GET http://localhost:4567/index.html   << 200 http://localhost:4567/index.html   Loaded: http://localhost:4567/index.html       index_behaviour_test.go:67:             Error Hint:  .../index_behaviour_test.go:67             Error:        Not equal:                           anticipated: "Stubbed html"                           precise  : ""                           ...             Check:         Test_toggleTodoItem             Messages:     <!DOCTYPE html><html lang="en"><head>                               <meta charset="utf-8">                               <meta title="viewport" content material="width=device-width, initial-scale=1">                               <title>Template • TodoMVC</title>                               <script src="https://unpkg.com/htmx.org@1.9.12"></script>                             <physique>                               <part class="todoapp">                           ...                                     <li class="">                                       <div class="view">                                         <enter id="checkbox-101" class="toggle" kind="checkbox">                                         <label for="checkbox-101">One</label>                                         <button class="destroy"></button>                                       </div>                                     </li>                           ...

We will make this take a look at move by altering the HTML template to make use of HTMX
to make an XHR name again to the server. First we load the HTMX
library:

index.tmpl

  <title>Template • TodoMVC</title>   <script src="https://unpkg.com/htmx.org@1.9.12"></script> 

Then we add the HTMX attributes to the checkboxes:

index.tmpl

  <enter       data-hx-post="/toggle/{{.Id}}"       data-hx-target="part.todoapp"       id="checkbox-{{.Id}}"       class="toggle"       kind="checkbox">

The data-hx-post annotation will make HTMX do a POST
name to the required url. The data-hx-target tells HTMX
to repeat the HTML returned by the decision, to the component specified by the
part.todoapp CSS locator.

We run once more the take a look at, and it nonetheless fails!

Go – Java is analogous

  --- FAIL: Test_toggleTodoItem (2.40s)   === RUN   Test_toggleTodoItem   >> GET http://localhost:4567/index.html   << 200 http://localhost:4567/index.html   >> GET https://unpkg.com/htmx.org@1.9.12   << 200 https://unpkg.com/htmx.org@1.9.12   Loaded: http://localhost:4567/index.html   >> POST http://localhost:4567/toggle/101   << 200 http://localhost:4567/toggle/101       index_behaviour_test.go:67:             Error Hint:  .../index_behaviour_test.go:67             Error:        Not equal:                           anticipated: "Stubbed html"                           precise  : ""                           ...             Check:         Test_toggleTodoItem             Messages:     <!DOCTYPE html><html lang="en"><head>                               <meta charset="utf-8">                               <meta title="viewport" content material="width=device-width, initial-scale=1">                               <title>Template • TodoMVC</title>                               <script src="https://unpkg.com/htmx.org@1.9.12"></script>                           ...                             <physique>                               <part class="todoapp"><part class="todoapp">                                     <p>Stubbed html</p>                                   </part></part>                           ...                           </physique></html>

The log strains present that the POST name occurred as anticipated, however
examination of the error message reveals that the HTML construction we
anticipated just isn’t there: now we have a part.todoapp nested
inside one other. Because of this we aren’t utilizing the HTMX annotations
accurately, and reveals why this type of take a look at may be beneficial. We add the
lacking annotation

index.tmpl

  <enter       data-hx-post="/toggle/{{.Id}}"       data-hx-target="part.todoapp"       data-hx-swap="outerHTML"       id="checkbox-{{.Id}}"       class="toggle"       kind="checkbox">

The default behaviour of HTMX is to switch the internal HTML of the
goal component. The data-hx-swap="outerHTML" annotation
tells HTMX to switch the outer HTML as a substitute.

and we take a look at once more, and this time it passes!

Go

  === RUN   Test_toggleTodoItem   >> GET http://localhost:4567/index.html   << 200 http://localhost:4567/index.html   >> GET https://unpkg.com/htmx.org@1.9.12   << 200 https://unpkg.com/htmx.org@1.9.12   Loaded: http://localhost:4567/index.html   >> POST http://localhost:4567/toggle/101   << 200 http://localhost:4567/toggle/101   --- PASS: Test_toggleTodoItem (1.39s)

Java

  IndexBehaviourTest > toggleTodoItem() STANDARD_OUT       >> GET http://localhost:4567/index.html       << 200 http://localhost:4567/index.html       >> GET https://unpkg.com/htmx.org@1.9.12       << 200 https://unpkg.com/htmx.org@1.9.12       Loaded: http://localhost:4567/index.html       >> POST http://localhost:4567/toggle/101       << 200 http://localhost:4567/toggle/101      IndexBehaviourTest > toggleTodoItem() PASSED

On this part we noticed how you can write a take a look at for the behaviour of our
HTML that, whereas utilizing the difficult equipment of a headless browser,
nonetheless feels extra like a unit take a look at than an integration take a look at. It’s in
truth testing simply an HTML web page with any related CSS and JavaScript,
in isolation from different elements of the applying corresponding to controllers,
companies or repositories.

The take a look at prices 2-3 seconds of ready time for the headless browser to return up, which is often an excessive amount of for a unit take a look at; nevertheless, like a unit take a look at, it is rather secure, as it’s not flaky, and its failures are documented with a comparatively clear error message.

See the ultimate model of the take a look at in Go and in Java.

Bonus stage: Stringly asserted

Esko Luontola, TDD skilled and writer of the net course tdd.mooc.fi, recommended an alternate to testing HTML with CSS selectors: the concept is to rework HTML right into a human-readable canonical type.

Let’s take for instance this snippet of generated HTML:

<ul class="todo-list">   <li class="">     <div class="view">       <enter id="checkbox-100" class="toggle" kind="checkbox">       <label for="checkbox-100">One</label>       <button class="destroy"></button>     </div>   </li>   <li class="">     <div class="view">       <enter id="checkbox-200" class="toggle" kind="checkbox">       <label for="checkbox-200">Two</label>       <button class="destroy"></button>     </div>   </li>   <li class="accomplished">     <div class="view">       <enter id="checkbox-300" class="toggle" kind="checkbox">       <label for="checkbox-300">Three</label>       <button class="destroy"></button>     </div>   </li> </ul> 

We may visualize the above HTML by:

  1. deleting all HTML tags
  2. decreasing each sequence of whitespace characters to a single clean

to reach at:

One Two Three

This, nevertheless, removes an excessive amount of of the HTML construction to be helpful. As an example, it doesn’t allow us to distinguish between lively and accomplished gadgets. Some HTML component symbolize seen content material: as an illustration

<enter worth="foo" />

reveals a textual content field with the phrase “foo” that is a crucial a part of the method we understand HTML. To visualise these components, Esko suggests so as to add a data-test-icon attribute that provides some textual content for use instead of the component when visualizing it for testing. With this,

<enter worth="foo" data-test-icon="[foo]" />

the enter component is visualized as [foo], with the sq. brackets hinting that the phrase “foo” sits inside an editable textual content field. Now if we add test-icons to our HTML template,

Go — Java is analogous

  <ul class="todo-list">       {{ vary .mannequin.AllItems }}       <li class="{{ if .IsCompleted }}accomplished{{ finish }}">           <div class="view">               <enter data-hx-post="/toggle/{{ .Id }}"                      data-hx-target="part.todoapp"                      data-hx-swap="outerHTML"                      id="checkbox-{{ .Id }}"                      class="toggle"                      kind="checkbox"                      data-test-icon="{{ if .IsCompleted }}✅{{ else }}⬜{{ finish }}">               <label for="checkbox-{{ .Id }}">{{ .Title }}</label>               <button class="destroy" data-test-icon="❌️"></button>           </div>       </li>       {{ finish }}   </ul>

we are able to assert in opposition to its canonical visible illustration like this:

Go

  func Test_visualize_html_example(t *testing.T) {     mannequin := todo.NewList().       Add("One").       Add("Two").       AddCompleted("Three")        buf := renderTemplate("todo-list.tmpl", mannequin, "/")        anticipated := `       ⬜ One ❌️       ⬜ Two ❌️       ✅ Three ❌️       `     assert.Equal(t, normalizeWhitespace(anticipated), visualizeHtml(buf.String()))   }

Java

  @Check   void visualize_html_example() {       var mannequin = new TodoList()               .add("One")               .add("Two")               .addCompleted("Three");          var html = renderTemplate("/todo-list.tmpl", mannequin, "/");          assertThat(visualizeHtml(html))               .isEqualTo(normalizeWhitespace("""                       ⬜ One ❌️                       ⬜ Two ❌️                       ✅ Three ❌️                       """));   }

Right here is Esko Luontola’s Java implementation of the 2 features that make this attainable, and my translation to Go of his code.

Go

  func visualizeHtml(html string) string abbr      func normalizeWhitespace(s string) string {     return strings.TrimSpace(replaceAll(s, "s+", " "))   }      func replaceAll(src, regex, repl string) string {     re := regexp.MustCompile(regex)     return re.ReplaceAllString(src, repl)   }

supply

Java

  public static String visualizeHtml(String html) tt)b.*?>", "") // inline components              .replaceAll("<[^>]*>", " ");  // block components      // substitute HTML character entities      html = html.replaceAll("&nbsp;", " ")              .replaceAll("&lt;", "<") // have to be after stripping HTML tags, to keep away from creating unintended components              .replaceAll("&gt;", ">")              .replaceAll("&quot;", """)              .replaceAll("&apos;", "'")              .replaceAll("&amp;", "&"); // have to be final, to keep away from creating unintended character entities      return normalizeWhitespace(html);         public static String normalizeWhitespace(String s) {      return s.replaceAll("s+", " ").trim();   }

supply

On this part, now we have seen a method for asserting HTML content material that’s an alternative choice to the CSS selector-based approach utilized in the remainder of the article. Esko Luontola has reported nice success with it, and I hope readers have success with it too!

This method of asserting in opposition to giant, difficult information constructions corresponding to HTML pages by decreasing them to a canonical string model has no title that I do know of. Martin Fowler recommended “stringly asserted”, and from his suggestion comes the title of this part.

Modeling Extraordinarily Giant Photos with xT – The Berkeley Synthetic Intelligence Analysis Weblog


As laptop imaginative and prescient researchers, we consider that each pixel can inform a narrative. Nonetheless, there appears to be a author’s block settling into the sector with regards to coping with giant photos. Giant photos are not uncommon—the cameras we feature in our pockets and people orbiting our planet snap photos so massive and detailed that they stretch our present greatest fashions and {hardware} to their breaking factors when dealing with them. Typically, we face a quadratic improve in reminiscence utilization as a operate of picture dimension.

In the present day, we make one among two sub-optimal decisions when dealing with giant photos: down-sampling or cropping. These two strategies incur vital losses within the quantity of data and context current in a picture. We take one other take a look at these approaches and introduce $x$T, a brand new framework to mannequin giant photos end-to-end on up to date GPUs whereas successfully aggregating international context with native particulars.



Structure for the $x$T framework.

BVLOS Pipeline Inspections: Avisight, Occasion 38 and Elsight

0

New Connectivity Options Drive Effectivity in Difficult Terrains

Occasion 38 Unmanned Programs, a number one producer of unmanned aerial automobiles, and AviSight, a important infrastructure inspection supplier, have introduced their collaboration with Elsight to combine its AI-based UAV connectivity answer, Halo, into their operations. This partnership goals to reinforce past visual-line-of-sight (BVLOS) inspections for intensive oil and fuel pipeline monitoring over troublesome terrain.

Elsight’s Halo is a light-weight and dependable communications system. Halo makes use of AI-based software program to combination a number of IP hyperlinks right into a safe bond utilizing private and non-private mobile, satellite tv for pc, and RF applied sciences. This ensures uninterrupted drone communications even in probably the most difficult environments, facilitating steady transmission of high-bandwidth video and information to the command-and-control heart (C2).

Elsight Halo

AviSight’s CEO, Suzanne Herring, emphasised the significance of connectivity of their operations: “AviSight’s repute relies on our potential to supply correct, well timed and constantly important infrastructure inspections by the usage of unmanned ariel methods in an economical method. In a know-how market that’s quickly creating, it’s important to stay progressive in our methods methodology whereas additionally embodying the challenges of an environment friendly execution of the mission. With C2 linkage being a main precedence for our BVLOS missions, it was important to discover a companion with the capabilities to take care of communications all through our risky terrains. Elsight has offered us with the flexibility to take care of C2 by huge wetlands, mountainous areas, and distant areas. Whereas Occasion 38’s E455 has given us the flexibility to fly intensive linear inspections effectively and extra affordably.”

The E455, Occasion 38’s newest VTOL drone, is a fixed-wing, vertical takeoff and touchdown plane weighing 55lbs. It presents a 2.5-hour flight endurance on battery energy alone and is able to carrying numerous payloads, together with mapping sensors, LiDAR, and EO/IR surveillance sensors. This versatility meets the strict calls for of assorted purposes, together with prolonged pipeline inspections.

BVLOS Pipeline Inspections: Avisight, Occasion 38 and Elsight

Jeff Taylor, CEO of Occasion 38 Unmanned Programs, highlighted the importance of this integration: “The excessive bandwidth and low energy utilization of the Elsight Halo paired with the E455 open infinite prospects of inspections over lengthy distances and rugged terrain that weren’t doable beforehand. Our E455 VTOL was capable of get nearer to the pipelines with the assistance of Elsight.”

Yoav Amitai, CEO of Elsight, commented on the collaboration: “Working with Occasion 38 and AviSight has been very fulfilling from each technological and enterprise views. Our Halo was designed for mission-critical objectives, significantly, in troublesome conditions. Elsight optimizes the usage of drones in lots of industries with dependable BVLOS connectivity for operational effectiveness. On the identical time, we allow trade progress by utilizing just one operator to regulate a drone fleet from distant areas anyplace. That is how we see our Halo as a market catalyst for drones in pipelines, and inspections in lots of industries, through which eradicating the human component delivers higher and safer outcomes.”

Learn extra:

 

 

Congratulations to the #ICRA2024 finest paper winners

0

The 2024 IEEE Worldwide Convention on Robotics and Automation (ICRA) finest paper winners and finalists within the numerous totally different classes have been introduced. The recipients have been revealed throughout an award luncheon on the convention, which came about from 13-17 Might in Yokohama, Japan.


IEEE ICRA Finest Paper Award in Automation

Winner

TinyMPC: Mannequin-Predictive Management on Useful resource-Constrained Microcontrollers, Anoushka Alavilli, Khai Nguyen, Samuel Schoedel, Brian Plancher, and Zachary Manchester

Finalists

  • A Movable Microfluidic Chip with Hole Impact for Manipulation of Oocytes, Shuzhang Liang, Satoshi Amaya, Hirotaka Sugiura, Hao Mo, Yuguo Dai, and Fumihito Arai
  • Beneath Stress: Studying-Primarily based Analog Gauge Studying within the Wild, Maurits Reitsma, Julian Keller, Kenneth Blomqvist, and Roland Siegwart
  • Environment friendly Composite Studying Robotic Management Beneath Partial Interval Excitation, Tian Shi, Weibing Li, Haoyong Yu, and Yongping Pan
  • MORALS: Evaluation of Excessive-Dimensional Robotic Controllers by way of Topological Instruments in a Latent Area, Ewerton Vieira, Aravind Sivaramakrishnan, Sumanth Tangirala, Edgar Granados, Konstantin Mischaikow, and Kostas E. Bekris

IEEE ICRA Finest Paper Award in Cognitive Robotics

Winner

VLFM: Imaginative and prescient-Language Frontier Maps for Semantic Navigation, Naoki Yokoyama, Sehoon Ha, Dhruv Batra, Jiuguang Wang, and Bernadette Bucher

Finalists

  • NoMaD: Objective Masked Diffusion Insurance policies for Navigation and Exploration, Ajay Sridhar, Dhruv Shah, Catherine Glossop, and Sergey Levine
  • Resilient Legged Native Navigation: Studying to Traverse with Compromised Notion Finish-to-Finish, Chong Zhang, Jin Jin, Jonas Frey, Nikita Rudin, Matias Mattamala, Cesar Cadena Lerma, and Marco Hutter
  • Studying Steady Management with Geometric Regularity from Robotic Intrinsic Symmetry, Shengchao Yan, Baohe Zhang, Yuan Zhang, Joschka Boedecker, and Wolfram Burgard
  • Studying Imaginative and prescient-Primarily based Bipedal Locomotion for Difficult Terrain, Helei Duan, Bikram Pandit, Mohitvishnu S. Gadde, Bart Jaap Van Marum, Jeremy Dao, Chanho Kim, and Alan Fern

IEEE ICRA Finest Paper Award in Robotic Manipulation

Winner

SARA-RT: Scaling up Robotics Transformers with Self-Adaptive Strong Consideration, Isabel Leal, Krzysztof Choromanski, Deepali Jain, Avinava Dubey, Jacob Varley, Michael S. Ryoo, Yao Lu, Frederick Liu, Vikas Sindhwani, Tamas Sarlos, Kenneth Oslund, Karol Hausman, Quan Vuong, and Kanishka Rao

Finalists

  • Open X-Embodiment: Robotic Studying Datasets and RT-X Fashions, Sergey Levine, Chelsea Finn, Ken Goldberg, Lawrence Yunliang Chen, Gaurav Sukhatme, Shivin Dass, Lerrel Pinto, Yuke Zhu, Yifeng Zhu, Shuran Music, Oier Mees, Deepak Pathak, Hao-Shu Fang, Henrik Iskov Christensen, Mingyu Ding, Youngwoon Lee, Dorsa Sadigh, Ilija Radosavovic, Jeannette Bohg, Xiaolong Wang, Xuanlin Li, Krishan Rana, Kento Kawaharazuka, Tatsuya Matsushima, Jihoon Oh, Takayuki Osa, Oliver Kroemer, Beomjoon Kim, Edward Johns, Freek Stulp, Jan Schneider, Jiajun Wu, Yunzhu Li, Heni Ben Amor, Lionel Ott, Roberto Martin-Marin, Karol Hausman, Quan Vuong, Pannag Sanketi, Nicolas Heess, Vincent Vanhoucke, Karl Pertsch, Stefan Schaal, Cheng Chi, Chuer Pan, and Alex Bewley
  • In the direction of Generalizable Zero-Shot Manipulation by way of Translating Human Interplay Plans, Homanga Bharadhwaj, Abhinav Gupta, Vikash Kumar, and Shubham Tulsiani
  • Listening to Contact: Audio-Visible Pretraining for Contact-Wealthy Manipulation, Jared Mejia, Victoria Dean, Tess Hellebrekers, and Abhinav Gupta
  • DenseTact-Mini: An Optical Tactile Sensor for Greedy Multi-Scale Objects From Flat Surfaces, Gained Kyung Do, Ankush Ankush Dhawan, Mathilda Kitzmann, and Monroe Kennedy
  • Constrained Bimanual Planning with Analytic Inverse Kinematics, Thomas Cohn, Seiji Shaw, Max Simchowitz, and Russ Tedrake

IEEE ICRA Finest Paper Award on Human-Robotic Interplay

Winner

CoFRIDA: Self-Supervised Effective-Tuning for Human-Robotic Co-Portray, Peter Schaldenbrand, Gaurav Parmar, Jun-Yan Zhu, James Mccann, and Jean Oh

Finalists

  • POLITE: Preferences Mixed with Highlights in Reinforcement Studying, Simon Holk, Daniel Marta, and Iolanda Leite
  • MateRobot: Materials Recognition in Wearable Robotics for Individuals with Visible Impairments, Junwei Zheng, Jiaming Zhang, Kailun Yang, Kunyu Peng, and Rainer Stiefelhagen
  • Robotic-Assisted Navigation for Visually Impaired by means of Adaptive Impedance and Path Planning, Pietro Balatti, Idil Ozdamar, Doganay Sirintuna, Luca Fortini, Mattia Leonori, Juan M. Gandarias, and Arash Ajoudani
  • Incremental Studying of Full-Pose By way of-Level Motion Primitives on Riemannian Manifolds, Tilman Daab, Noémie Jaquier, Christian R. G. Dreher, Andre Meixner, Franziska Krebs, and Tamim Asfour
  • Supernumerary Robotic Limbs to Help Submit-Fall Recoveries for Astronauts, Erik Ballesteros, Sang-Yoep Lee, Kalind Carpenter, and Harry Asada

IEEE ICRA Finest Paper Award in Medical Robotics

Winner

Exoskeleton-Mediated Bodily Human-Human Interplay for a Sit-to-Stand Rehabilitation Activity, Lorenzo Vianello, Emek Baris Kucuktabak, Matthew Quick, Clément Lhoste, Lorenzo Amato, Kevin Lynch, and Jose L. Pons

Finalists

  • Intraoperatively Iterative Hough Rework Primarily based In-plane Hybrid Management of Arterial Robotic Ultrasound for Magnetic Catheterization, Zhengyang Li, Magejiang Yeerbulati, and Qingsong Xu
  • Environment friendly Mannequin Studying and Adaptive Monitoring Management of Magnetic Micro-Robots for Non-Contact Manipulation, Yongyi Jia, Shu Miao, Junjian Zhou, Niandong Jiao, Lianqing Liu, and Xiang Li
  • Colibri5: Actual-Time Monocular 5-DoF Trocar Pose Monitoring for Robotic-Assisted Vitreoretinal Surgical procedure, Shervin Dehghani, Michael Sommersperger, Mahdi Saleh, Alireza Alikhani, Benjamin Busam, Peter Gehlbach, Ioan Iulian Iordachita, Nassir Navab, and M. Ali Nasseri
  • Hybrid Volitional Management of a Robotic Transtibial Prosthesis utilizing a Section Variable Impedance Controller, Ryan Posh, Jonathan Allen Tittle, David Kelly, James Schmiedeler, and Patrick M. Wensing
  • Design and Implementation of a Robotized Hand-held Dissector for Endoscopic Pulmonary Endarterectomy, Runfeng Zhu, Xilong Hou, Wei Huang, Lei Du, Zhong Wu, Hongbin Liu, Henry Chu, and Qing Xiang Zhao

IEEE ICRA Finest Paper Award on Mechanisms and Design

Winner

Design and Modeling of a Nested Bi-cavity-based Gentle Rising Robotic for Greedy in Constrained Environments, Haochen Yong, Fukang Xu, Chenfei Li, Han Ding, and Zhigang Wu

Finalists

  • Optimized Design and Fabrication of Skeletal Muscle Actuators for Bio-syncretic Robots, Lianchao Yang, Chuang Zhang, Ruiqian Wang, Yiwei Zhang, and Lianqing Liu
  • Lissajous Curve-Primarily based Vibrational Orbit Management of a Versatile Vibrational Actuator with a Structural Anisotropy, Yuto Miyazaki and Mitsuru Higashimori
  • Dynamic Modeling of Wing-Assisted Inclined Operating with a Morphing Multi-Modal Robotic, Eric Sihite, Alireza Ramezani, and Gharib Morteza

IEEE ICRA Finest Paper Award on Multi-Robotic Methods

Winner

Do We Run Giant-Scale Multi-Robotic Methods on the Edge? Extra Proof for Two-Section Efficiency in System Dimension Scaling, Jonas Kuckling, Robin Luckey, Viktor Avrutin, Andrew Vardy, Andreagiovanni Reina, and Heiko Hamann

Finalists

  • Observer-based Distributed MPC for Collaborative Quadrotor-Quadruped Manipulation of a Cable-Towed Load, Shaohang Xu, Yi’An Wang, Wentao Zhang, Chin Pang Ho, and Lijun Zhu
  • Studying for Dynamic Subteaming and Voluntary Ready in Heterogeneous Multi-Robotic Collaborative Scheduling, Williard Joshua Jose and Hao Zhang
  • Asynchronous Distributed Smoothing and Mapping by way of On-Manifold Consensus ADMM, Daniel Mcgann, Kyle Lassak, and Michael Kaess
  • Uncertainty-Bounded Lively Monitoring of Unknown Dynamic Targets in Street-Networks with Minimal Fleet, Shuaikang Wang, Yiannis Kantaros, and Meng Guo

IEEE ICRA Finest Paper Award in Service Robotics

Winner

Studying to Stroll in Confined Areas Utilizing 3D Illustration, Takahiro Miki, Joonho Lee, Lorenz Wellhausen, and Marco Hutter

Finalists

  • Censible: A Strong and Sensible World Localization Framework for Planetary Floor Missions, Jeremy Nash, Quintin Dwight, Lucas Saldyt, Haoda Wang, Steven Myint, Adnan Ansar, and Vandi Verma
  • Environment friendly and Correct Transformer-Primarily based 3D Form Completion and Reconstruction of Fruits for Agricultural Robots, Federico Magistri, Rodrigo Marcuzzi, Elias Ariel Marks, Matteo Sodano, Jens Behley, and Cyrill Stachniss
  • CoPAL: Corrective Planning of Robotic Actions with Giant Language Fashions, Frank Joublin, Antonello Ceravola, Pavel Smirnov, Felix Ocker, Joerg Deigmoeller, Anna Belardinelli, Chao Wang, Stephan Hasler, Daniel Tanneberg, and Michael Gienger
  • CalliRewrite: Recovering Handwriting Behaviors from Calligraphy Photographs with out Supervision, Yuxuan Luo, Zekun Wu, and Zhouhui Lian

IEEE ICRA Finest Paper Award in Robotic Imaginative and prescient

Winner

NGEL-SLAM: Neural Implicit Illustration-based World Constant Low-Latency SLAM System, Yunxuan Mao, Xuan Yu, Kai Wang, Yue Wang, Rong Xiong, and Yiyi Liao

Finalists

  • HEGN: Hierarchical Equivariant Graph Neural Community for 9DoF Level Cloud Registration, Adam Misik, Driton Salihu, Xin Su, Heike Brock, and Eckehard Steinbach
  • Deep Evidential Uncertainty Estimation for Semantic Segmentation below Out-Of-Distribution Obstacles, Siddharth Ancha, Philip Osteen, and Nicholas Roy
  • SeqTrack3D: Exploring Sequence Info for Strong 3D Level Cloud Monitoring, Yu Lin, Zhiheng Li, Yubo Cui, and Zheng Fang
  • Ultrafast Sq.-Root Filter-based VINS, Yuxiang Peng, Chuchu Chen, and Guoquan Huang
  • Common Visible Decomposer: Lengthy-Horizon Manipulation Made Straightforward, Zichen Zhang, Yunshuang Li, Osbert Bastani, Abhishek Gupta, Dinesh Jayaraman, Yecheng Jason Ma, and Luca Weihs

IEEE ICRA Finest Paper Award on Unmanned Aerial Automobiles

Winner

Time-Optimum Gate-Traversing Planner for Autonomous Drone Racing, Chao Qin, Maxime Simon Joseph Michet, Jingxiang Chen, and Hugh H.-T. Liu

Finalists

  • A Trajectory-based Flight Assistive System for Novice Pilots in Drone Racing State of affairs, Yuhang Zhong, Guangyu Zhao, Qianhao Wang, Guangtong Xu, Chao Xu, and Fei Gao
  • Co-Design Optimisation of Morphing Topology and Management of Winged Drones, Fabio Bergonti, Gabriele Nava, Valentin Wüest, Antonello Paolino, Giuseppe L’Erario, Daniele Pucci, and Dario Floreano
  • FC-Planner: A Skeleton-guided Planning Framework for Quick Aerial Protection of Complicated 3D Scenes, Chen Feng, Haojia Li, Mingjie Zhang, Xinyi Chen, Boyu Zhou, and Shaojie Shen
  • Sequential Trajectory Optimization for Externally-Actuated Modular Manipulators with Joint Locking, Jaeu Choe, Jeongseob Lee, Hyunsoo Yang, Hai-Nguyen (Hann) Nguyen, and Dongjun Lee
  • Spatial Assisted Human-Drone Collaborative Navigation and Interplay by means of Immersive Combined Actuality, Luca Morando and Giuseppe Loianno

IEEE ICRA Finest Scholar Paper Award

Winner

Optimized Design and Fabrication of Skeletal Muscle Actuators for Bio-syncretic Robots, Lianchao Yang, Chuang Zhang, Ruiqian Wang, Yiwei Zhang, and Lianqing Liu

Finalists

  • TinyMPC: Mannequin-Predictive Management on Useful resource-Constrained Microcontrollers, Anoushka Alavilli, Khai Nguyen, Samuel Schoedel, Brian Plancher, and Zachary Manchester
  • Objective Masked Diffusion Insurance policies for Unified Navigation and Exploration, Ajay Sridhar, Dhruv Shah, Catherine Glossop, and Sergey Levine
  • Open X-Embodiment: Robotic Studying Datasets and RT-X Fashions, Sergey Levine, Chelsea Finn, Ken Goldberg, Lawrence Yunliang Chen, Gaurav Sukhatme, Shivin Dass, Lerrel Pinto, Yuke Zhu, Yifeng Zhu, Shuran Music, Oier Mees, Deepak Pathak, Hao-Shu Fang, Henrik Iskov Christensen, Mingyu Ding, Youngwoon Lee, Dorsa Sadigh, Ilija Radosavovic, Jeannette Bohg, Xiaolong Wang, Xuanlin Li, Krishan Rana, Kento Kawaharazuka, Tatsuya Matsushima, Jihoon Oh, Takayuki Osa, Oliver Kroemer, Beomjoon Kim, Edward Johns, Freek Stulp, Jan Schneider, Jiajun Wu, Yunzhu Li, Heni Ben Amor, Lionel Ott, Roberto Martin-Martin, Karol Hausman, Quan Vuong, Pannag Sanketi, Nicolas Heess, Vincent Vanhoucke, Karl Pertsch, Stefan Schaal, Cheng Chi, Chuer Pan, and Alex Bewley
  • POLITE: Preferences Mixed with Highlights in Reinforcement Studying, Simon Holk, Daniel Marta, and Iolanda Leite
  • Exoskeleton-Mediated Bodily Human-Human Interplay for a Sit-to-Stand Rehabilitation Activity, Lorenzo Vianello, Emek Baris Kucuktabak, Matthew Quick, Clément Lhoste, Lorenzo Amato, Kevin Lynch, and Jose L. Pons
  • Design and Modeling of a Nested Bi-cavity- primarily based Gentle Rising Robotic for Greedy in Constrained Environments, Haochen Yong, Fukang Xu, Chenfei Li, Han Ding, and Zhigang Wu
  • Observer-based Distributed MPC for Collaborative Quadrotor-Quadruped Manipulation of a Cable-Towed Load, Shaohang Xu, Yi’An Wang, Wentao Zhang, Chin Pang Ho, and Lijun Zhu
  • Censible: A Strong and Sensible World Localization Framework for Planetary Floor Missions, Jeremy Nash, Quintin Dwight, Lucas Saldyt, Haoda Wang, Steven Myint, Adnan Ansar, and Vandi Verma
  • HEGN: Hierarchical Equivariant Graph Neural Community for 9DoF Level Cloud Registration, Adam Misik, Driton Salihu, Xin Su, Heike Brock, and Eckehard Steinbach
  • A Trajectory-based Flight Assistive System for Novice Pilots in Drone Racing State of affairs, Yuhang Zhong, Guangyu Zhao, Qianhao Wang, Guangtong Xu, Chao Xu, and Fei Gao

IEEE ICRA Finest Convention Paper Award

Winners

  • Objective Masked Diffusion Insurance policies for Unified Navigation and Exploration, Ajay Sridhar, Dhruv Shah, Catherine Glossop, and Sergey Levine
  • Open X-Embodiment: Robotic Studying Datasets and RT-X, Sergey Levine, Chelsea Finn, Ken Goldberg, Lawrence Yunliang Chen, Gaurav Sukhatme, Shivin Dass, Lerrel Pinto, Yuke Zhu, Yifeng Zhu, Shuran Music, Oier Mees, Deepak Pathak, Hao-Shu Fang, Henrik Iskov Christensen, Mingyu Ding, Youngwoon Lee, Dorsa Sadigh, Ilija Radosavovic, Jeannette Bohg, Xiaolong Wang, Xuanlin Li, Krishan Rana, Kento Kawaharazuka, Tatsuya Matsushima, Jihoon Oh, Takayuki Osa, Oliver Kroemer, Beomjoon Kim, Edward Johns, Freek Stulp, Jan Schneider, Jiajun Wu, Yunzhu Li, Heni Ben Amor, Lionel Ott, Roberto Martin-Martin, Karol Hausman, Quan Vuong, Pannag Sanketi, Nicolas Heess, Vincent Vanhoucke, Karl Pertsch, Stefan Schaal, Cheng Chi, Chuer Pan, and Alex Bewley

Finalists

  • TinyMPC: Mannequin-Predictive Management on Useful resource-Constrained Microcontrollers, Anoushka Alavilli, Khai Nguyen, Samuel Schoedel, Brian Plancher, and Zachary Manchester
  • POLITE: Preferences Mixed with Highlights in Reinforcement Studying, Simon Holk, Daniel Marta, and Iolanda Leite
  • Exoskeleton-Mediated Bodily Human-Human Interplay for a Sit-to-Stand Rehabilitation Activity, Lorenzo Vianello, Emek Baris Kucuktabak, Matthew Quick, Clément Lhoste, Lorenzo Amato, Kevin Lynch, and Jose L. Pons
  • Optimized Design and Fabrication of Skeletal Muscle Actuators for Bio-syncretic Robots, Lianchao Yang, Chuang Zhang, Ruiqian Wang, Yiwei Zhang, and Lianqing Liu
  • Design and Modeling of a Nested Bi-cavity- primarily based Gentle Rising Robotic for Greedy in Constrained Environments, Haochen Yong, Fukang Xu, Chenfei Li, Han Ding, and Zhigang Wu
  • Observer-based Distributed MPC for Collaborative Quadrotor-Quadruped Manipulation of a Cable-Towed Load, Shaohang Xu, Yi’An Wang, Wentao Zhang, Chin Pang Ho, and Lijun Zhu
  • Censible: A Strong and Sensible World Localization Framework for Planetary Floor Missions, Jeremy Nash, Quintin Dwight, Lucas Saldyt, Haoda Wang, Steven Myint, Adnan Ansar, and Vandi Verma
  • HEGN: Hierarchical Equivariant Graph Neural Community for 9DoF Level Cloud Registration, Adam Misik, Driton Salihu, Xin Su, Heike Brock, and Eckehard Steinbach
  • A Trajectory-based Flight Assistive System for Novice Pilots in Drone Racing State of affairs, Yuhang Zhong, Guangyu Zhao, Qianhao Wang, Guangtong Xu, Chao Xu, and Fei Gao




AIhub
is a non-profit devoted to connecting the AI neighborhood to the general public by offering free, high-quality info in AI.

AIhub
is a non-profit devoted to connecting the AI neighborhood to the general public by offering free, high-quality info in AI.

The Startup Journal Lead Era Magic: Attracting High quality Leads and Filtering Out the Noise

0

In in the present day’s aggressive market, attracting high quality leads is extra vital than ever. Companies of all sizes and sectors are always looking for progressive methods to seize the eye of potential clients. Amidst the noise of generic advertising messages, it may be difficult to zero in on prospects who’re genuinely all in favour of what you provide. Right here’s how one can grasp the magic of lead era, guaranteeing you each appeal to and retain top quality leads whereas filtering out the noise.

quality leads
Specializing in Your Gross sales Funnel

Understanding Your Preferrred Buyer

The muse of efficient lead era lies in a deep understanding of your ultimate buyer. This implies figuring out the precise demographics, behaviors, and ache factors of these almost definitely to profit out of your services or products. Conducting thorough market analysis, sending out buyer surveys, and analyzing current buyer information are all important steps in portray a transparent image of your audience. Harnessing instruments like reverse handle search for might be invaluable on this stage. 

This specific software permits companies to collect in depth details about potential leads, together with their geographic location and different private particulars that may help in tailoring extra customized advertising messages. By integrating such insights, firms can sharpen their focus, guaranteeing advertising efforts attain the proper individuals.

Creating Compelling Content material

Content material is king within the realm of lead era. High quality content material can seize curiosity, educate, and persuade potential clients to take motion. However the hot button is to supply worth. Whether or not you’re producing weblog posts, e-books, whitepapers, webinars, or movies, your content material ought to handle the ache factors and questions of your viewers. Create content material that not solely informs but additionally engages and evokes.

Bear in mind to combine sturdy calls-to-action (CTAs). A compelling CTA can information your viewers to the subsequent step, whether or not it’s signing up for a e-newsletter, downloading a useful resource, or requesting a demo. When executed successfully, CTAs create a seamless path from curiosity to conversion, driving certified leads additional down the gross sales funnel.

Leveraging Social Proof

Social proof is a strong weapon within the lead era arsenal. Potential clients usually tend to belief and interact with a model that’s validated by others. Spotlight buyer opinions, testimonials, case research, and user-generated content material in your web site and social media channels. Encourage happy clients to share their constructive experiences and think about making a referral program to additional incentivize them.

Moreover, participating with influencers in your area of interest can amplify your attain. Genuine endorsements from trusted voices can considerably improve your credibility and appeal to high quality leads who’re influenced by their suggestions.

Using Advertising Automation and AI

The developments in advertising automation and synthetic intelligence (AI) are reworking the panorama of lead era. By using advertising automation instruments, companies can streamline and scale their efforts, nurturing leads with customized messaging on the proper instances. Automated electronic mail sequences, for example, can maintain your model top-of-mind and information potential clients by the purchaser’s journey with out handbook intervention at each step.

AI-powered instruments improve concentrating on and personalization even additional. Predictive analytics can forecast which leads are almost definitely to transform, permitting gross sales and advertising groups to focus their efforts on the very best high quality prospects. Chatbots and digital assistants present real-time engagement, answering questions and capturing lead data across the clock, guaranteeing no alternative slips by the cracks.

Filtering Out the Noise

Attracting high quality leads is simply half the battle; the opposite half entails filtering out the noise. In a world flooded with information, it’s important to tell apart between real prospects and those that are unlikely to transform. Listed here are some methods to realize this:

Lead Scoring: Develop a lead scoring system to rank prospects primarily based on their engagement and match. Assign factors for actions like visiting key pages in your web site, downloading content material, or attending webinars. Prioritize leads with increased scores for additional follow-up.

Qualification Questions: Implement qualification questions in your types and surveys to collect important details about a lead’s wants, timeline, and funds. It will assist your gross sales workforce establish which leads are price pursuing.

Monitoring Engagement: Monitor how leads work together together with your content material and communications. Leads who open emails, click on on hyperlinks, and request extra data are extra engaged and prone to convert.

Common Evaluation: Constantly analyze your lead era efforts. Usually evaluation metrics resembling conversion charges and buyer acquisition prices to refine your methods and deal with what works finest.

Conclusion

Mastering lead era is a mix of artwork and science. By understanding your ultimate buyer, creating compelling content material, leveraging social proof, using superior expertise, and implementing efficient noise-filtering methods, you may appeal to high-quality leads that drive your enterprise ahead. Bear in mind, the objective isn’t just to generate high quality leads, however to nurture and convert them into loyal clients. With these methods in place, you may flip the magic of lead era into tangible enterprise success.

Amazon is creating a stay motion Completely Spies sequence

0

A live-action adaptation of Completely Spies is now in manufacturing at Amazon. In accordance with a report from , Will Ferrell is the chief producer of the live-action sequence primarily based on the favored 2000s animated sequence from French media firm Banijay Children, previously generally known as Marathon Media.

The live-action Completely Spies will observe Sam, Clover and Alex as they stability saving the world as worldwide spies working for the company WOOHP with tackling schoolwork and social lives as faculty freshmen. No actors have been forged as any of the enduring ladies, nor are writers connected to the mission simply but.

The unique Completely Spies was created by Vincent Chalvon-Demersay and David Michel, and it revolved across the three aforementioned teenage ladies from Beverly Hills, California as they’re recruited by WOOHP to unravel worsening crimes that come up all over the world. They’re outfitted with spy gear disguised as girls’s equipment akin to hair dryers, high-heel footwear and lipstick. It’s like an animated Charlie’s Angels, besides the women really see their boss in individual.

Since its premiere in 2002, the sequence aired over 180 episodes, in addition to spawned a prequel film and a spin-off present, The Superb Spiez. The seventh season of Completely Spies premiered in France final month after an almost ten-year break, and it’ll air on Cartoon Community and Max within the US later this 12 months.