UI TDD with StoryBook

 The Test Driven Development process assumes the incremental steps of module logic improving starting with unit test following the implementation in the source code. As unit test is created, it immediately should fail as the logic still has to be done. Once logic is in place, the next feature added to the unit test and the cycle repeats…

The UI development used to be different as there was no ability to do the checks and incremental code improvements. The module (UI component) used to be tested within the web application without insulation and ability to visualize the variations without app state change or the following the whole flow leading to the UI variation. Till the StoryBook became a natural part of UI SDLC. 

What is a StoryBook? It is a toolkit for various aspects for UI development. 

When installed inside of the web UI project as a NPM module, it allows to run the components collection with all variations within the StoryBook interface which is not attached to the actual web app your team is working on. Instead, it exposes the collection of UI components hierarchically organized and exposes the samples of the UI variations and use cases.

Of course the UI has a lot of aspects besides basic variations. Those include but not limited to:

  • Color theming: dark, light, high contrast light/dark

  • Language switch

  • Various screen sizes and mobile variations

  • Accessibility: 

    • blurred vision, limited colors, etc.

    • Screen reader 

    • Keyboard navigation

  • Set of mocked user roles

And so on… All the listed is covered by StoryBook making it “a must” part of the UI development stack. Which is especially important for enterprise grade applications bound by various compliance requirements.

Compliances aside, StoryBook gives the frame to practice TDD during UI component development. Once the SB UI is running, developers would be able to work on individual UI component in insulation. 

( in examples I use the “native” JS web components, the React or Angular typescript module work in similar fashion )

  1. For xxx module, create the xxx.stories.ts file either in the folder for component or in directory dedicated for stories

  2. Inside of .stories.tx file you would keep the UI variations of component (similar to unit tests variations). Those would export

    1. Parameters set for SB which should cover all use cases 

  1. Template to render component UI with parameters ^^

  2. Use cases. A template to particular parameters binding.

Once the use cases created, they would be listed in SB interface. To work with component in insulation, there is a “Open Canvas in new tab” button:

That is where the primary development for your component would be shown:

As SB is served in the browser, the dev tools at your service to inspect the UI styles, debug code, etc. The code hot reload allows you to change the code and immediately see the affected UI.

StoryBook gives you the ability to integrate with Figma and other UI design services. The link inside of your story would lead to the UI design to compare the components against design.

Once your component is ready and becomes a part of the application, it is important to check whether following changes break any UI appearance. The pixel comparison tools like Chromatic or SauceLabs Selenium would give you ability to:

  • See the pixel difference between original and code in pool request

  • Engage UX team in visual changes approval

That assures there are no UI regressions introduced by pool request.

Here we touched just UI TDD aspects, but other features by SB are not less important in enterprise grade UI.

The StoryBook is well detailed on https://storybook.js.org and covered by multiple web and video blogs. 

<custom-element> test project used as example. Happy coding!


2023 retrospective

 Kind of personal. As 2024 approaches, looking back how 2023 has been for me and people around. 

In my family the year has completed the cycle of learning. All kids graduated in the subjects of their choice. Myself personally gone over being the performing force to the subject of steering the things around. The initiatives from ideas and POCs become real projects thanks to colleagues and management in Bluescape. This has laid the foundation for a new role I am looking forward to take for next year as the founder and owner in the Cyber Security space. The final separation from Bluescape had cut off the unnecessary obligations, opening the clean and fresh start. 

What 2023 taught me? The motto “BE CURIOUS, LEARN AND ADOPT KNOWLEDGE, SEEK THE PATH, STATE THE GOALS AND OVERCOME” become a powerful set of principles. The curiosity on things around along with learning and comparing allowed me to approach the challenges as on business as on technology sides. The curiosity extended to the team’ challenges, along with learning following the discoveries and sharing brought people closer. Resulting in efficient cooperation and expanding the personal abilities to the team synergy. It also exposed that working in the team is a level of magnitude more efficient. 

In 2023 AI has stepped into professional life. Not much as the syntax and ‘tune’ checker for public writing, but rather an efficient helper on search services for relatively simple solutions which are not yet covered by someone’s blog or Q&A site like stackoverflow or Reddit. The coding with AI itself is not yet powerful, though great for algorithm and unit tests stubs generation.

AI vs team. The AI at its current level is not a replacement for a team at all. It allowed me to write up my own thoughts, but when it comes to cognitive analysis and critical thinking, there is no replacement for a team. Next year, I plan to try different AI services as it has been proven to be a great time saver.

Once again, the statement “in software there is no impossible, it is just a matter of time and available resources” have been proven. Ability to explore the options from different angles and not limiting to seem to be easiest solutions, allowed to beat the border between native executable and web microapplication. The nodeJs CLI app can be packaged as native executable. But there was no reference on how to make it in-browser application. The answer was in implementing node APIs when assembling the web app. Many Open Source projects paved the base for the Cloud version of CLI I made, which inspired me to contribute more to OSS. 

2023 being an apogee in my OSS efforts. With the help of web stack leaders from W3C groups, the Declarative Web Application has been shaped into a useful NO-JS UI platform, with Declarative Custom Element at the forefront. Apparently that became an answer to the Cyber Security Office challenge on safe programming languages, frameworks and app engines. The RFI we created would lay out the basis for my activities for the next few years. However, to make a real impact, the idea must become a sustainable business. This is another challenge I plan to tackle in 2024.

Be Dragon in you! Wise and powerful.



How to integrate MSW queries mocking with @web/test-runner and StoryBook

In short, follow the comments in Pool Request


The serious WebComponents and UI components development SDLC needs the TDD ability to create UI, visually test with incremental changes, apply the unit tests for functional parts, CI/CD integration for visual and functional regression. 

Those tasks are perfectly covered by 

  • StoryBook as component based UI development media. It allows to do the development per component detached from main application/library. In addition to development of single use case, it gives ability to change the component parameters, and its behavior in various external conditions like high contrast/dark/light display mode, blurred vision, etc. Which is a must during development of accessible UI components and components with parameter driven variations.  
  • @web/test-runner - the browser based unit test runner. The perfect combo of CLI and in-browser development. 
Both, a visual development in StoryBook, and functional unit testing need the data mocking which is provided by
  • MockServiceWorker - MSW helper for interrupting the back-end HTTP calls and simulating the response behavior with headers, data and errors.   
All sounds as a perfect combo till the moment trying to make a plumbing in real project. It happen that many nuances are not covered by docs and some aspects of MSW deployment strategies become impossible to resolve. Till now. 

MSW packaging includes CJS( node kind of modules ) and IILF (ES5 no-module) formats. In StoryBook it works out of the box as it is based on WebPack build which resolves CJS and bundles-in the MSW code. 
Unfortunately it become an issue in non-compile based environments including @web/test-runner. There is no es6 module which can be imported directly. 

The top-level await become a savior. IILF formatted script can be loaded by SCRIPT tag and its variables re-exported by es6 module. msw.js module source
const msw = await new Promise((resolve,reject)=>
    ((d, s)=>
    {   s = d.createElement('script')
        s.onload = ()=> resolve( window.MockServiceWorker );

export const    { GraphQLHandler
                , MockedRequest
                , RESTMethods
                , RequestHandler
                , RestHandler
                , SetupApi
                , SetupWorkerApi
                , cleanUrl
                , compose
                , context
                , createResponseComposition
                , defaultContext
                , defaultResponse
                , graphql
                , graphqlContext
                , handleRequest
                , matchRequestUrl
                , response
                , rest
                , restContext
                , setupWorker
                } = msw;
This module is used by unit test config and in mock handlers. To make it compatible with usual use by StoryBook compatible code, add the import maps support in web-test-runner.config.mjs
      inject: {
        importMap: {
          imports: {
            'msw': '/src/mocks/msw.js',
Which would make the import in StoryBook and in unit test alike. handlers.js:
import { rest } from 'msw'

import pokemonsMock from "../../stories/pokemons.mock";

export const handlers =
[   rest.get("*/api/v2/pokemon", (req, res, ctx) =>
        return res(ctx.json(pokemonsMock));
    rest.get("*/noreturn", (req, res, ctx) =>
            {   console.log(req.url, 'trapped')
                return new Promise((resolve)=>{ setTimeout(()=>
                {   console.log(req.url, 'resolving')
                }, 10000)}); // 1 second to be able to catch the initial state before the full data returned;
The service worker needs a bit of tuning to be reused by StoryBook and unit tests. First comes initialization on root level:

npx msw init "./" --save

Then in .storybook/main.js
module.exports = {
    staticDirs: [
        {from: '../mockServiceWorker.js', to: '/mockServiceWorker.js'} // MSW support

and in .storybook/preview.js
import { initialize, mswDecorator } from "msw-storybook-addon";

import {handlers} from "../src/mocks/handlers";

export const parameters = {
    msw: {handlers},

// Initialize MSW

// Provide the MSW addon decorator globally
export const decorators = [mswDecorator];
The unit test MSW setup is a bit trickier. Besides configuration of the import maps to simulated JS msw module above, in each test you would need to import browser.js
// src/mocks/browser.js
import { setupWorker } from './msw.js'
import { handlers } from './handlers.js'

// This configures a Service Worker with the given request handlers.
export const worker = setupWorker(...handlers)
await worker.start({ serviceWorker: { url: '/mockServiceWorker.js' } });
Hopefully that is sufficient. If not, take a look into notes on PR or bug me.

Happy coding!


npx dockerize-npm-module

Thinking aloud on challenge I am facing as JS developer.

Problem: NPM-based projects often require specific dependencies versions installation and version tune up which is 

  • time consuming ( curse of node-gyp or sass )
  • could mess up machine environment for other projects. 
Such dev and build dependencies could be pre-configured and jailed within docker image exposing only input/output folders and working ports on developer's machine.  

GitHub and other code management repositories are given ability to run continuous integration (CI) steps as Docker container actions

Those actions could be run as part of CI during deployment but also locally to prevent aforementioned problems. 

Solutionhttps://github.com/nektos/act - locally installed "act' app.

PROS: almost complete CI/CD cycle coverage. 

CONS: requires installation and ? per-project tune-up.

Proposal: npx dockerize-npm-module [NPM_SCRIPT_COMMAND]

Seamless as non-installable CLI to run all package.json commands in preconfigured image for docker container.

+ config generation/load

? reuse GitHub container actions  

+ upgrade package.json with safe:xxx scripts meant to run same NPM commands in docker container or add docker CI/CD steps. 


HTML5 SLOT tag for content management explained

Web Components stack includes efficient and well thought through templating solution with TEMPLATE and SLOT tags. While those have been widely adopted in web components world for multiple reasons, the shadow DOM behind of this tech prevents to use it in environments where UI styles managed separately and often driven by heavy legacy content: while styling in shadow DOM has own perks like css insulation, it does not work well with global css styling. 

I would suggest to utilize the concept of slot in template  in content management environments with classic css use. You could implement the convention by yourself with showing/hiding the slot with name  

el.querySelector('slot[name="final"]').hidden = false;

To avoid the UI flickering , make sure the initial HTML includes the visibility state meant to be shown before JS is able to act:

<slot name="initial">Please wait while loading...</slot>
<slot name="final" hidden> initially is hidden, filled by JS and then shown </slot>


NOTE. The hidden attribute behavior is self-explanatory and works out of the box, no need for CSS. But if your environment is a CMS like Adobe AEM, Liferay, or Drupal, the CSS on the page is most likely a product of multiple people/teams over the years. Here the default behavior could be tricked by different CSS rules and you would need to elevate:
slot[hidden]{ display:none!important;}

Of course the page level javascript and HTML would limit only one slot name a time. Wrapping slots combinations into identifiable by JS container would help to handle multiple UI components with same kind of UI pattern(template). Like the avatar in the list and in profile UI. 

The most convenient way to connect JS and HTML element is a custom element, i.e. Web Component with own tag. `this` in its methods would point to html element of own tag which would be triggered every time the tag appear in HTM, initially or dynamically later. In CMS it would prevent the messing with page, document, and script load handlers, a huge win for code maintenance when the code is spread across developers/teams and time.

Web Component does not dictate the use of ShadowDOM and allows to pick any way of template implementation. There are multiple "frameworks" with opinionated ways of templates handling. The HTML content meant to be handled by middle tier in classic CMS. Where the templates also play important role in content lifecycle. Adding another templating engine is not just increasing the complexity but also created the conflict between different approaches and handling the content variations like multi-lingual support or cohort targeting.  Hence ability to reuse the CMS HTML capabilities along with template/slot concept would be most beneficial.

As CMS usually is not designed to serve the dynamic data, the fusion of externally served data and UI from CMS becomes a data plumbing task on UI tier. During this "data plumbing" process the UI should support multiple states including initial waiting, loading, error of multiple kind, and final with rendered data, perhaps with variations on data internals.

slotted-element comes handy for eliminating the coding for data plumbing in simplest cases and simplifying the programming otherwise. 

Here this custom element is a sample for typical data plumbing to CMS driven HTML tasks.

  • switch between slots to be shown. Hide all, display only one. 
  • clone slot content to be filled with data
  • add customized slot. Could be more than once for list.
  • data retrieval layer: url/method/headers/body, status, error handling, fetched data conversion.
  • UI sub-elements access and manipulation convenience methods.

Whether you choose to use slotted-element, extend it, or decide to create own, keep in mind the list ^^. 


Using templates and slots


XSLT 1.0 in-browser Q&A

  • How to get XSLT path from within XSLT?

<xsl:value-of select="substring-before(substring-after(/processing-instruction('xml-stylesheet'),'href=&quot;'),'&quot;')"/>

XML: <?xml-stylesheet type="text/xsl" href="../AsTable.xsl" ?>

Gives: ../AsTable.xsl

  • How to get relative URL of  specific XSLT from XML?

<xsl:value-of select="substring-before(substring-after(/processing-instruction('xml-stylesheet'),'href=&quot;'),'AsTable.xsl&quot;')"/>

    Gives: ../

    • How to get Javascript URL relative to XSLT applied to XML as processing instruction?
    <xsl:param name="baseUrl" select="substring-before(substring-after(/processing-instruction('xml-stylesheet'),'href=&quot;'),'AsTable.xsl&quot;')"  />
    <script type="module" src="{$baseUrl}XmlView.js">/**/</script> 

    Gives: ../XmlView.js

      • list of unique children tags (each last)
      *[ not( name() = name(following-sibling::*) ) ]
      • how to output XSL from XSL
      Add namespace with altered URL, namespace-alias, use the namespace in output:
      <xsl:stylesheet version="1.0"
      * get entries for table presentation and
      * fills in xsl:template mode="DisplayAs" for each
      <xsl:output method="xml" />
      <xsl:namespace-alias stylesheet-prefix="xvxsl" result-prefix="xsl"/> ...
      <xvxsl:template mode="DisplayAs" match="{$xPath}">
      • how to debug XSL? 
      Currently the most convenient way is given by Visual Studio Pro edition. Trial available.


      Semantic Theming - indexed palette

      There are many articles on palette categorizations online, I would skip to semantic relation of palettes to UX elements. 

      Usually palette is selected from basic branded colors base. Usually 2 or 3 is sufficient, perhaps it relates to the heraldic symbols and colors. Remaining colors are chosen with keeping the base ones and emotional palette in mind. 

      There is a catch on selection enterprise and government designs are facing: color set should be "accessible" for various cohorts of people: color blind, light sensitive, etc. Adobe has given a nice tool to help with accessible palette creation. In regards to color "accessible" means that close colors should be distinctive enough even for people with color challenges or in applicable conditions of low/bright light.

      The palettes would have various colors but some of them have to be in straight color transition like bright to dim. Why you would need a color sequence? The answer resides in various states UX component are presented during interaction with UI. Those states are used in sequence: normal follows hovered, which followed "active"(pressed) , the disables should be least noticeable and resides in the end of color sequence. See Buttons and Actions states

      How many color sequences you would need? It depends on how many color variations your application supports: light, dark, high contrast for each, grayscale for ePaper devices, etc. Another factor is munber of variations for UX components. As in Buttons and Actions there are 5 variations proposed, will be more for other types of UX components. Each need to have own entry in one of indexed palettes. 

      While same palette could be reused for different UX components variations, it is better to choose a significantly distinctive different entry point in palette for inside of same color theme variation. 

      For UX components single palette is not sufficient. The indexed palettes usually come in more than one color per row. You would need to make colors as for background as foreground/text, for outline, and for other sub-elements. For action it would be 3 colors: background, text, outline/border. The 4rth is assumed to come from theme variation background which is a basis for selecting proper entry within indexed palette. In this sample you could see the need to alter the text color due to background change:

      Now to the meat of subject. The indexed palette become semantic when one of its entries is associated with one of semantic UX element variation.