{"id":26552694,"url":"https://github.com/luontola/html-utils","last_synced_at":"2025-03-22T08:39:40.879Z","repository":{"id":279503513,"uuid":"939021733","full_name":"luontola/html-utils","owner":"luontola","description":"Utilities for writing and testing HTML on Node.js","archived":false,"fork":false,"pushed_at":"2025-03-20T18:37:37.000Z","size":43,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-20T20:04:17.223Z","etag":null,"topics":["html","html-templating","htmx","javascript","javascript-library","nodejs","react","testing-tools","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/luontola.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-02-25T21:37:49.000Z","updated_at":"2025-03-20T18:39:37.000Z","dependencies_parsed_at":"2025-02-25T23:28:34.521Z","dependency_job_id":null,"html_url":"https://github.com/luontola/html-utils","commit_stats":null,"previous_names":["luontola/html-utils"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luontola%2Fhtml-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luontola%2Fhtml-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luontola%2Fhtml-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luontola%2Fhtml-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/luontola","download_url":"https://codeload.github.com/luontola/html-utils/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244931585,"owners_count":20534009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["html","html-templating","htmx","javascript","javascript-library","nodejs","react","testing-tools","typescript"],"created_at":"2025-03-22T08:39:40.338Z","updated_at":"2025-03-22T08:39:40.868Z","avatar_url":"https://github.com/luontola.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Esko's HTML Utils\n\nThis project contains a couple utilities for writing and testing HTML in JavaScript/Node.js.\n\nThese utilities are not available on npm, but they are meant to be copy-pasted into your project. They come complete\nwith unit tests, so they can be evolved to fit your project's needs.\n\n## HTML Templating\n\nThere is a tag function for writing tagged templates, to produce HTML without a heavy framework like React.\n\nThe placeholders are automatically escaped to avoid XSS vulnerabilities.\n\n```js\nconst input = \"\u003cscript\u003ealert(1)\u003c/script\u003e\"\nconst output = html`\u003cp\u003eHello ${input}\u003c/p\u003e`\nexpect(output.html).toBe(\"\u003cp\u003eHello \u0026lt;script\u0026gt;alert(1)\u0026lt;/script\u0026gt;\u003c/p\u003e\")\n```\n\nYou can create components using plain old functions. Works great with [htmx](https://htmx.org/).\n\n```js\nfunction homePage() {\n    return html`\n        \u003ch1\u003eWelcome\u003c/h1\u003e\n        \u003cp\u003e${clickerButton()}\u003c/p\u003e\n    `\n}\n\nfunction clickerButton(counter: number = 0) {\n    return html`\n        \u003cbutton hx-get=\"/clicker?counter=${counter + 1}\"\n                hx-target=\"this\"\n                hx-swap=\"outerHTML\"\u003e\n            Clicked ${counter} times\n        \u003c/button\u003e\n    `\n}\n```\n\nSee [html-templates.ts](src/html-templates.ts) and [html-templates.test.ts](test/html-templates.test.ts)\n\n## Unit Testing the UI\n\nThere is a helper function for extracting the visible text from HTML, to easily unit test HTML templates.\n\nThe components mentioned in the previous section could be unit tested like this:\n\n```js\nexpect(visualizeHtml(homePage())).toBe(normalizeWhitespace(`\n        Welcome\n        Clicked 0 times`))\n\nconst button = clickerButton(5)\nexpect(visualizeHtml(button)).toBe(\"Clicked 5 times\")\nexpect(button.html).toContain(`hx-get=\"/clicker?counter=6\"`)\n```\n\nBy default `visualizeHtml` strips all HTML tags.\nBut if you add a `data-test-icon` attribute to an element, the element will be replaced with its value.\nThis enables [stringly asserted](https://martinfowler.com/articles/tdd-html-templates.html#BonusLevelStringlyAsserted)\ntesting to assert non-textual information.\n\n```js\nexpect(visualizeHtml(\"\u003cp\u003eone\u003c/p\u003e\u003cp\u003etwo\u003c/p\u003e\")).toBe(\"one two\")\nexpect(visualizeHtml(`\u003cinput type=\"checkbox\" checked data-test-icon=\"☑️\"\u003e`)).toBe(\"☑️\")\n```\n\nIn addition to raw HTML and [our HTML templates](#html-templating), `visualizeHtml` works also for React elements.\nIf you use only one of them, you can delete a few lines from `visualizeHtml` to remove the unnecessary dependency.\n\nSee [html-testing.ts](src/html-testing.ts) and [html-testing.test.ts](test/html-testing.test.ts)\n\n## Installing\n\nTo use this library, download it to be part of your project:\n\n```\nwget https://raw.githubusercontent.com/luontola/html-utils/refs/heads/main/src/html-templates.ts\nwget https://raw.githubusercontent.com/luontola/html-utils/refs/heads/main/test/html-templates.test.ts\nwget https://raw.githubusercontent.com/luontola/html-utils/refs/heads/main/src/html-testing.ts\nwget https://raw.githubusercontent.com/luontola/html-utils/refs/heads/main/test/html-testing.test.ts\n```\n\nIn particular, the testing library often benefits from project-specific customizations.\n\nThis library is [finished software](https://josem.co/the-beauty-of-finished-software/), so there is no need to get\nconstant updates to it.\nNo new features is a feature in itself.\nYou wouldn't want to be [left-padded](https://en.wikipedia.org/wiki/Npm_left-pad_incident) because of just 50 lines of\ncode, would you?\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluontola%2Fhtml-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fluontola%2Fhtml-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluontola%2Fhtml-utils/lists"}