I don’t really get using percentages for font size. I haven’t used them much, but it’s interesting. I’ll have to play around with it more.
I don’t really get using percentages for font size. I haven’t used them much, but it’s interesting. I’ll have to play around with it more.
If you have low vision and a big monitor, you don’t want to zoom the whole page and end up with a mobile layout. You want that bird’s-eye view of the desktop page, just with bigger text. Use rems for scaling text, but stick with pixels for margins and padding so they don’t blow up too.
21/21 When teammates tried to contribute, different systems caused many test failures. To fix this, I limited tests to a single worker, raised the diff threshold to 0.4, and removed WebKit/Firefox tests. Despite some bumps, we now have a functional visual regression testing suite for our website!
19/21 Building this visual regression testing setup took up my entire two-week sprint. Everything was running smoothly—until I invited my teammates to contribute 😛. That’s when the real challenges began.
18/21 Because visual regression tests can be flaky, `continueOnError` was set to true. This way, engineers get warnings in Azure Pipelines but can still merge changes without blocking deployments.
17/21 Next, an artifact is created for Playwright’s HTML Report using `PublishBuildArtifact@1`. The pipeline then runs `PublishTestResults@2` with `JUnit`, allowing Azure to display a clean UI with test results—including screenshots of failed tests.
16/21 In the `azure-pipelines.yml` file, the first step runs `http-server` from the Storybook folder in the public directory. Then, `wait-on tcp` waits for the server, downloads screenshots from Blob Storage, and runs the Playwright test. `continueOnError` is true, and CI environment is enabled.
15/21 The next step was setting up Azure Pipelines. If someone forgot to run the tests locally, the pipeline would warn them of failures. Eventually, I’d like it to fail the build on visual diffs—but first, I had to prove this setup worked.
14/21 To update and publish snapshots in one command, I added `"snapshots:publish": "npm run snapshots:download && npm run snapshots:update && npm run snapshots:upload”`. This refreshed the ``__screenshots__` folder, ran tests, and uploaded the results to Azure Blob Storage.
13/21 This setup allowed engineers to run visual regression tests locally. Running: `"snapshots:update": "playwright test --update-snapshots --workers=1”` flagged any visual differences and added screenshots if they didn’t exist.
12/21 ”snapshots:upload”: “node scripts/publish-screenshots.mjs”` and another command for downloading screenshots was added to package.json. These scripts used multiple `try...catch` blocks and lots of `console.error()` logs for success, warnings, and errors—plus a few emojis to keep it fun!
11/21 I used the Azure Storage Blob client library from NPM to upload and download images. The script mostly consisted of using `path.resolve`, `fs.existSync`, `fs.readdirSync`, `path.join` and other built-in Node.js modules.
10/21 Even after creating a script to compress images, storing screenshots locally wasn’t sustainable. With seven breakpoints per section, storage size grew fast. Committing them to Git would slow down the repo over time. Instead, I offloaded them to Azure Blob Storage.
9/21 Screenshots are stored in the `__screenshots__` folder, which is ignored by .gitignore settings. The folder and file structure look like this: `/chromium/linux/visual.responsive.breakpoints.spec.ts/section-one-column-layout-hero-news-480px.png`.
8/21 The test loops through all stories, and for each one, it loops through all 7 breakpoints. It finds the `#storybook-root` element, calculates the section’s height, and captures a screenshot using: `await expect(page).toHaveScreenshot()`.
7/21 A new array is created with only the stories tagged as `visual:breakpoints`. Then, the `tailwind.config.js` file is imported, and its `screens` breakpoints are added to another array. I manually added a 320px breakpoint since many mobile users browse with zoom enabled.
6/21 Once the build is complete, `“storybook:build:preview”: “npx http-server ./public/storybook --port 6006 --silent”` starts a local server. The Playwright test fetches `/index.json` using Node’s `path.resolve()` method to find the stories.
5/21 Storybook provides an index of all stories at `/index.json`. Before running the test, the following command creates a stable environment to reduce test flakiness: `”storybook:build”: “storybook build -o public/storybook”`.
4/21 Each section is tagged with `tags: [visual:breakpoints]`. This way, the Playwright test file loops through all Storybook stories and runs tests only for those with this tag.
3/21 A section can include components like a button for the CTA. Capturing a screenshot of a button at every breakpoint didn’t add value since its appearance wouldn’t change. To speed up test runs, I excluded components and scoped the tests to full sections instead.
2/21 Sections of a webpage are broken into individual stories within Storybook. Imagine a two-column layout: an eyebrow, heading, paragraph, and CTA on the left, with a photo on the right. These sections became the focus of the visual tests.
1/21 I had the opportunity to build a visual regression toolset using Storybook, Playwright, Azure Blob Storage, and Azure Pipelines. It tests all breakpoints from the Tailwind config file. Here’s how it went. 🧵
20/21 To contribute, they branched off my feature branch, add `tags: [visual:breakpoints]` to a Storybook story, followed the README instructions, merged their branch, and ran the pipeline.
It wasn’t until after the PR was approved that I did some additional research. I learned that complex logic is best handled in the preprocessor, not in Twig. Wish I'd known that earlier, but this opens the door to revisiting it with a better approach down the road.
Creating the <picture> element in Twig took more than expected. Between the string replacements and for loops, I often found myself stuck. Despite searching, I couldn’t find helpful resources on implementing it in Twig—not even Google or AI had the answer.
For smaller viewports, the default <source> handles the 16:9 ratio and includes a set of responsive images, allowing the browser to choose the best one based on screen resolution and connection speed. An <img> element is available as a fallback.
The <picture> element was used for the hero section. Users on large screens saw the 5:2 aspect ratio. Inside the <picture> element, a <source> with a min-width query for the 5:2 ratio and srcset allows browsers to choose the best responsive image.
Updating the 2:3 and 1:2 ratios was similar to what I shared in the previous thread. I held off on tackling the 5:2 aspect ratio until the other two PRs were approved, as it involved the <picture> element and seemed more challenging to implement.
As part of the transition to serving images from Widen’s CDN (details here: bsky.app/profile/chee...), I found a way to divide the work between engineers based on image aspect ratios. I took on the 2:3, 1:2, and 5:2 ratios. Here’s what I learned along the way.
After reviewing the risks with security, we chose to protect user privacy by avoiding the widget. Instead, I proposed creating a custom, engaging review showcase on the microsite. While it requires more manual work from editors, it ensures users’ data remains safe.