<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Joris Gallot</title>
    <description>The latest articles on DEV Community by Joris Gallot (@joris-gallot).</description>
    <link>https://dev.to/joris-gallot</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F916419%2F0e4b1fb7-7acc-4e70-9980-a61a2eec2cef.png</url>
      <title>DEV Community: Joris Gallot</title>
      <link>https://dev.to/joris-gallot</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joris-gallot"/>
    <language>en</language>
    <item>
      <title>Tracking component health over time with Vitest browser mode and Storybook</title>
      <dc:creator>Joris Gallot</dc:creator>
      <pubDate>Sun, 11 Oct 2026 16:00:45 +0000</pubDate>
      <link>https://dev.to/joris-gallot/tracking-component-health-over-time-with-vitest-browser-mode-and-storybook-2o8</link>
      <guid>https://dev.to/joris-gallot/tracking-component-health-over-time-with-vitest-browser-mode-and-storybook-2o8</guid>
      <description>&lt;p&gt;Component tests have become real browser tests. Vitest browser mode runs them in Chromium through Playwright, and Storybook's Vitest addon turns every story into a test. They are fast, they render the real thing, and most design systems now have hundreds of them.&lt;/p&gt;

&lt;p&gt;What they still lack is memory.&lt;/p&gt;

&lt;p&gt;A run tells you that 3 tests failed out of 400. It does not tell you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which components are those 3 tests about?&lt;/li&gt;
&lt;li&gt;Was the &lt;code&gt;Select&lt;/code&gt; story already failing yesterday, or did it break with this pull request?&lt;/li&gt;
&lt;li&gt;Which stories fail once in a while and pass on retry?&lt;/li&gt;
&lt;li&gt;What did the component look like when the screenshot assertion failed in CI?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output is a list of tests. The thing you care about is a list of components.&lt;/p&gt;

&lt;h2&gt;
  
  
  A test is not a component
&lt;/h2&gt;

&lt;p&gt;Test runners report by file and by test title. That is the right unit for running tests, but not for reading the state of a design system.&lt;/p&gt;

&lt;p&gt;One story is often covered by several tests: a render check, an interaction, a visual assertion. One test file often covers several stories. When something fails, you have to map the test title back to a component in your head, then go look for the previous runs to know whether it is new.&lt;/p&gt;

&lt;p&gt;Storybook already gives you the right unit, the story. &lt;code&gt;Button/Primary&lt;/code&gt; means something to everyone on the team, designers included. So the useful question is simple: for each story, what happened in the last runs?&lt;/p&gt;

&lt;h2&gt;
  
  
  Sending Vitest and Storybook results to Kinora
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://kinora.dev" rel="noopener noreferrer"&gt;Kinora&lt;/a&gt; started as a dashboard for Playwright reports. It now takes Vitest runs too, through a reporter you add next to the default one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm add &lt;span class="nt"&gt;-D&lt;/span&gt; @kinora/vitest-reporter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// vitest.config.ts&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;reporters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kinora/vitest-reporter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;design-system&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}]],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run your tests with an API token in the environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;KINORA_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;token&amp;gt; npx vitest run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things are worth knowing about how it behaves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It uploads browser tests only, by default.&lt;/strong&gt; Node unit tests are usually thousands of fast, deterministic tests with no trace. They add little to a dashboard, so the reporter skips them unless you set &lt;code&gt;include: 'all'&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With Storybook's Vitest addon, there is nothing else to do.&lt;/strong&gt; Each story is already a Vitest test, and the reporter records which story each test renders, as &lt;code&gt;&amp;lt;Component&amp;gt;/&amp;lt;Story&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;An upload never fails your test run.&lt;/strong&gt; If the server is unreachable, your tests still pass or fail on their own merits.&lt;/p&gt;

&lt;h2&gt;
  
  
  One page per design system
&lt;/h2&gt;

&lt;p&gt;Once a run with stories is uploaded, the project gets a Components page. Stories are grouped by component, and each story shows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;its latest status&lt;/li&gt;
&lt;li&gt;a timeline over the last 20 runs&lt;/li&gt;
&lt;li&gt;the tests that render it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A story's status in a run is the worst status among its tests in that run. If the render check passes and the interaction test fails, the story is failing.&lt;/p&gt;

&lt;p&gt;The timeline is what changes the conversation. A story that is red in the latest run and green in the 19 before it is a regression, and the pull request is the suspect. A story that goes red every few runs is flaky, and the pull request is probably innocent. You can tell the two apart in a glance, without opening a single CI log.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it looked like when it failed
&lt;/h2&gt;

&lt;p&gt;History tells you when a story broke. You still need to see why.&lt;/p&gt;

&lt;p&gt;With the Playwright provider, Vitest browser mode can record a Playwright trace per test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;playwright&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitest/browser-playwright&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vitest/config&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;playwright&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="na"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;chromium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
      &lt;span class="na"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;retain-on-failure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reporter uploads the &lt;code&gt;trace.zip&lt;/code&gt; of each failing test, and Kinora opens it in its embedded trace viewer: DOM snapshots, console, network, right from the failed test. No artifact to download from CI.&lt;/p&gt;

&lt;p&gt;Visual assertions get the same treatment. A failing &lt;code&gt;toMatchScreenshot&lt;/code&gt; uploads its reference, actual and diff images, and the run page shows them as a screenshot comparison. You see the two pixels of padding that moved before you even check out the branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not on Vitest? Playwright component tests work too
&lt;/h2&gt;

&lt;p&gt;If your component tests run on Playwright's own &lt;code&gt;mount&lt;/code&gt; fixture, they already upload like any other Playwright test. The only missing piece is which story a test mounted, and one import records it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@kinora/reporter/ct&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;disabled button is disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;mount&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Button/Disabled&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBeDisabled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Stories from both paths land on the same Components page. This is the setup I use for Kinora's own design system, and the &lt;a href="https://docs.kinora.dev/guides/component-testing/" rel="noopener noreferrer"&gt;component testing guide&lt;/a&gt; has the full Vue and Vite example to copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two limits to know about
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A test that renders several stories counts for each of them.&lt;/strong&gt; Kinora knows which stories a test mounted, not which one an assertion failed on. A failure marks all of them as failing. Keep one story per test when you want precise attribution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Storybook &lt;code&gt;play&lt;/code&gt; functions are not Playwright actions.&lt;/strong&gt; The trace of a Storybook test shows the rendered story, not each interaction step.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asking an agent instead of reading the page
&lt;/h2&gt;

&lt;p&gt;The same data is available to coding agents through Kinora's MCP server. Its &lt;code&gt;component_health&lt;/code&gt; tool answers questions like "which stories of &lt;code&gt;Dialog&lt;/code&gt; are failing or flaky, and which tests render them?". That is a much better starting point for an agent than a raw test log.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;If you already run Vitest in browser mode or Storybook tests in CI, the setup is one dependency and one line in your config.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.kinora.dev/guides/vitest/" rel="noopener noreferrer"&gt;Vitest and Storybook guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.kinora.dev/guides/component-testing/" rel="noopener noreferrer"&gt;Component testing guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://demo.kinora.dev" rel="noopener noreferrer"&gt;Open the live demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kinora-dev/kinora" rel="noopener noreferrer"&gt;Star the project on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>vitest</category>
      <category>testing</category>
      <category>playwright</category>
      <category>storybook</category>
    </item>
    <item>
      <title>Introducing Kinora: a Playwright test dashboard with history, flaky tracking, and traces</title>
      <dc:creator>Joris Gallot</dc:creator>
      <pubDate>Mon, 05 Oct 2026 17:38:23 +0000</pubDate>
      <link>https://dev.to/joris-gallot/introducing-kinora-a-playwright-test-dashboard-with-history-flaky-tracking-and-traces-j1i</link>
      <guid>https://dev.to/joris-gallot/introducing-kinora-a-playwright-test-dashboard-with-history-flaky-tracking-and-traces-j1i</guid>
      <description>&lt;p&gt;Playwright gives you an excellent HTML report for a single test run. You can open a failed test, inspect screenshots, read errors, and launch the trace viewer when you need the full story.&lt;/p&gt;

&lt;p&gt;That works great when you are looking at one run.&lt;/p&gt;

&lt;p&gt;It gets harder when your team wants to answer questions across many runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is this failure new, or has it been failing for days?&lt;/li&gt;
&lt;li&gt;Which tests are flaky across branches and projects?&lt;/li&gt;
&lt;li&gt;Did the pass rate improve after the last fix?&lt;/li&gt;
&lt;li&gt;Where is the trace for the CI failure someone reported yesterday?&lt;/li&gt;
&lt;li&gt;Can everyone on the team debug from the same place without downloading artifacts?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why I built Kinora.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Kinora?
&lt;/h2&gt;

&lt;p&gt;Kinora is a dashboard for Playwright test reports across projects and over time.&lt;/p&gt;

&lt;p&gt;CI runs push their results to Kinora. The dashboard keeps the history, tracks pass rates and trends, surfaces flaky tests, and lets you open the full Playwright trace inline from a failed test.&lt;/p&gt;

&lt;p&gt;The goal is not to replace Playwright's report. The goal is to keep the useful parts of every report after CI finishes and make them searchable, comparable, and easier to debug as a team.&lt;/p&gt;

&lt;p&gt;You can use Kinora in two ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Self-host it for free with Docker Compose.&lt;/li&gt;
&lt;li&gt;Use the hosted Kinora cloud when you do not want to run the infrastructure yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The source is available on &lt;a href="https://github.com/Kinora-dev/kinora" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, with MIT-licensed embeddable packages and fair-source app packages.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just use the Playwright HTML report?
&lt;/h2&gt;

&lt;p&gt;The Playwright HTML report is optimized for one run. That is the right default.&lt;/p&gt;

&lt;p&gt;But CI test debugging often needs a longer memory.&lt;/p&gt;

&lt;p&gt;A single report can tell you that a test failed. It does not naturally tell you that the same test failed three times this week, passed on &lt;code&gt;main&lt;/code&gt;, failed only on Chromium, or started getting slow after a specific change.&lt;/p&gt;

&lt;p&gt;Teams usually fill that gap with a mix of CI artifacts, screenshots, Slack messages, local downloads, and tribal knowledge.&lt;/p&gt;

&lt;p&gt;Kinora keeps the run data in one place so you can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run history by project&lt;/li&gt;
&lt;li&gt;pass rate trends&lt;/li&gt;
&lt;li&gt;failed and flaky tests&lt;/li&gt;
&lt;li&gt;retries and durations&lt;/li&gt;
&lt;li&gt;git and CI metadata&lt;/li&gt;
&lt;li&gt;trace.zip artifacts attached to failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That context makes triage faster because the first question is no longer "where is the report?". It becomes "what changed?".&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;A typical setup looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the Kinora reporter to your Playwright config, or upload a &lt;code&gt;results.json&lt;/code&gt; file with the CLI.&lt;/li&gt;
&lt;li&gt;Run Playwright in CI like you already do.&lt;/li&gt;
&lt;li&gt;Kinora normalizes the report and uploads the run through a simple REST API.&lt;/li&gt;
&lt;li&gt;The dashboard stores the run, tests, metadata, and trace artifacts.&lt;/li&gt;
&lt;li&gt;Your team opens Kinora to review the current run or compare it with history.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The important part is stable test identity.&lt;/p&gt;

&lt;p&gt;Kinora derives a cross-run key from the test file, title path, and project name. That means the same test can be tracked over time even when it is uploaded from different CI jobs or ingestion paths.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging failures with traces inline
&lt;/h2&gt;

&lt;p&gt;Playwright traces are one of the best parts of the Playwright ecosystem. They let you replay actions, inspect DOM snapshots, view network requests, and understand what happened before a failure.&lt;/p&gt;

&lt;p&gt;But traces are often trapped inside CI artifacts.&lt;/p&gt;

&lt;p&gt;Kinora keeps the trace attached to the failed test. From the dashboard, you can open it directly in the embedded trace viewer without downloading the zip or switching tools.&lt;/p&gt;

&lt;p&gt;That makes traces part of the team workflow instead of a local debugging afterthought.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding flaky tests over time
&lt;/h2&gt;

&lt;p&gt;A flaky test is rarely obvious from a single run.&lt;/p&gt;

&lt;p&gt;You need history to see that a test passes most of the time, fails sometimes, retries successfully, or fails only under one browser or CI condition.&lt;/p&gt;

&lt;p&gt;Kinora keeps that history so flaky tests can be investigated as a pattern, not as isolated failures.&lt;/p&gt;

&lt;p&gt;The dashboard helps you spot tests that repeatedly move between passed, failed, and flaky states. From there, you can open the run, inspect the trace, and decide whether the problem is test code, app behavior, infrastructure, or timing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built for CI, self-hosting, and teams
&lt;/h2&gt;

&lt;p&gt;Kinora is CI-agnostic. Anything that can run Playwright and send an HTTP request can publish a run.&lt;/p&gt;

&lt;p&gt;The reporter is convenient for Playwright projects. The CLI is useful when you already generate a report and want to upload it as a separate step.&lt;/p&gt;

&lt;p&gt;For deployment, there are two paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Self-hosted: run the server, web app, Postgres, and artifact storage on your own infrastructure.&lt;/li&gt;
&lt;li&gt;Cloud: use Kinora without managing the stack.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Self-hosting matters because test reports can include sensitive URLs, logs, screenshots, traces, and environment metadata. If you want that data to stay on your infrastructure, it can.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is next?
&lt;/h2&gt;

&lt;p&gt;Kinora already covers the core workflow: ingest Playwright runs, keep history, surface failures and flaky tests, and open traces inline.&lt;/p&gt;

&lt;p&gt;The next steps are about making that workflow even more useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better artifact previews for screenshots and videos&lt;/li&gt;
&lt;li&gt;richer local desktop workflows around traces and failed tests&lt;/li&gt;
&lt;li&gt;stronger integrations with alerts, pull requests, and agents&lt;/li&gt;
&lt;li&gt;more content and guides around Playwright reporting best practices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are using Playwright in CI and want a persistent dashboard for your test history, Kinora is available now.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://app.kinora.dev/signup" rel="noopener noreferrer"&gt;Try the hosted app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://demo.kinora.dev" rel="noopener noreferrer"&gt;Open the live demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.kinora.dev" rel="noopener noreferrer"&gt;Read the docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Kinora-dev/kinora" rel="noopener noreferrer"&gt;Star the project on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>playwright</category>
      <category>testing</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
