diff --git a/craft/src/components/tokenDefaults.harness.test.tsx b/craft/src/components/tokenDefaults.harness.test.tsx
new file mode 100644
index 0000000..13527e1
--- /dev/null
+++ b/craft/src/components/tokenDefaults.harness.test.tsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import { describe, test, expect, afterEach } from 'vitest';
+import { renderEditorHarness, EditorHarness } from '../test-utils/editorHarness';
+import { ButtonLink } from './basic/ButtonLink';
+import { Icon } from './basic/Icon';
+import { FormButton } from './forms/FormButton';
+import { SubscribeForm } from './forms/SubscribeForm';
+import { ContactForm } from './forms/ContactForm';
+import { HeroSimple } from './sections/HeroSimple';
+import { PricingTable } from './sections/PricingTable';
+import { Tabs } from './sections/Tabs';
+import { NumberCounter } from './sections/NumberCounter';
+import { Section } from './layout/Section';
+
+let h: EditorHarness;
+afterEach(() => {
+ h?.unmount();
+ document.body.innerHTML = '';
+});
+
+/** Drop a fresh node onto the real editor canvas and return the serialized
+ * doc, i.e. what is persisted for a NEW block. */
+function dropAndSerialize(element: React.ReactElement): string {
+ h = renderEditorHarness();
+ h.act(() => {
+ const tree = h.query.parseReactElement(element).toNodeTree();
+ h.actions.addNodeTree(tree, 'ROOT');
+ });
+ return h.getSerialized();
+}
+
+describe('new blocks take their colour defaults from the site palette tokens', () => {
+ test.each([
+ ['ButtonLink', () => , '"backgroundColor":"var(--wsb-primary)"'],
+ ['Icon', () => , '"color":"var(--wsb-primary)"'],
+ ['FormButton', () => , '"backgroundColor":"var(--wsb-primary)"'],
+ ['SubscribeForm', () => , '"buttonColor":"var(--wsb-primary)"'],
+ ['ContactForm', () => , '"submitColor":"var(--wsb-primary)"'],
+ ['HeroSimple', () => , '"buttonBgColor":"var(--wsb-primary)"'],
+ ['PricingTable', () => , '"featuredBg":"var(--wsb-primary)"'],
+ ['Tabs', () => , '"activeTabBg":"var(--wsb-primary)"'],
+ ['NumberCounter', () => , '"numberColor":"var(--wsb-primary)"'],
+ ['NumberCounter', () => , '"labelColor":"var(--wsb-muted)"'],
+ ['Section', () => , '"backgroundColor":"var(--wsb-bg)"'],
+ ['Section', () => , '"topDividerColor":"var(--wsb-bg)"'],
+ ['Section', () => , '"bottomDividerColor":"var(--wsb-bg)"'],
+ ] as [string, () => React.ReactElement, string][])('%s default is a token', (_name, make, expected) => {
+ expect(dropAndSerialize(make())).toContain(expected);
+ });
+});