or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

decorators.mdhooks.mdindex.mdpreview-system.mdstory-composition.mdstory-store.mdtesting-simulation.md

testing-simulation.mddocs/

0

# Testing & Simulation

1

2

Tools for simulating DOM events, page lifecycle, and creating test utilities. These functions are essential for testing stories and addons in various environments, enabling comprehensive testing scenarios and cross-platform compatibility.

3

4

## Capabilities

5

6

### Page Lifecycle Simulation

7

8

Functions for simulating browser page lifecycle events in testing environments.

9

10

```typescript { .api }

11

/**

12

* Simulates complete page loading with script execution and DOM setup

13

* @param container - DOM element to simulate page load within

14

*/

15

function simulatePageLoad(container: Element): void;

16

17

/**

18

* Triggers DOMContentLoaded event for testing DOM-dependent code

19

*/

20

function simulateDOMContentLoaded(): void;

21

```

22

23

**Usage Examples:**

24

25

```typescript

26

import { simulatePageLoad, simulateDOMContentLoaded } from "@storybook/preview-api";

27

28

// Simulate page load in a container

29

test('component initializes after page load', () => {

30

const container = document.createElement('div');

31

document.body.appendChild(container);

32

33

// Add your component to the container

34

container.innerHTML = '<my-component></my-component>';

35

36

// Simulate page load to trigger initialization scripts

37

simulatePageLoad(container);

38

39

// Verify component initialized correctly

40

expect(container.querySelector('my-component')).toHaveClass('initialized');

41

});

42

43

// Simulate DOMContentLoaded for testing initialization

44

test('library initializes on DOMContentLoaded', () => {

45

const mockInit = jest.fn();

46

document.addEventListener('DOMContentLoaded', mockInit);

47

48

// Trigger the event

49

simulateDOMContentLoaded();

50

51

expect(mockInit).toHaveBeenCalled();

52

});

53

```

54

55

### Playwright Test Integration

56

57

Utilities for creating Playwright test fixtures with Storybook story mounting capabilities.

58

59

```typescript { .api }

60

/**

61

* Creates Playwright test utilities with story mounting support

62

* @param baseTest - Base Playwright test fixture

63

* @returns Extended test fixture with mount capabilities

64

*/

65

function createPlaywrightTest<TFixture>(baseTest: TFixture): PlaywrightTestExtended<TFixture>;

66

67

interface PlaywrightTestExtended<TFixture> extends TFixture {

68

/**

69

* Mount a composed story in the test page

70

* @param story - Composed story function

71

* @param options - Mounting options

72

* @returns Promise resolving to mounted component locator

73

*/

74

mount(story: ComposedStoryFn, options?: MountOptions): Promise<Locator>;

75

76

/**

77

* Mount JSX/React element in the test page

78

* @param component - React element to mount

79

* @param options - Mounting options

80

* @returns Promise resolving to mounted component locator

81

*/

82

mountComponent(component: ReactElement, options?: MountOptions): Promise<Locator>;

83

}

84

85

interface MountOptions {

86

/** Additional props to pass to the story/component */

87

props?: Record<string, any>;

88

/** Container selector or element */

89

container?: string | Element;

90

/** Wait for specific conditions after mounting */

91

waitFor?: () => Promise<void>;

92

}

93

```

94

95

**Usage Examples:**

96

97

```typescript

98

import { test, expect } from '@playwright/test';

99

import { createPlaywrightTest } from '@storybook/preview-api';

100

import { composeStory } from '@storybook/preview-api';

101

import * as ButtonStories from './Button.stories';

102

103

// Create extended test with story mounting

104

const storyTest = createPlaywrightTest(test);

105

106

// Compose story

107

const Primary = composeStory(ButtonStories.Primary, ButtonStories.default);

108

109

storyTest('Primary button is interactive', async ({ mount, page }) => {

110

// Mount the story

111

const component = await mount(Primary, {

112

props: { label: 'Test Button' }

113

});

114

115

// Test interactions

116

await expect(component).toBeVisible();

117

await component.click();

118

119

// Verify behavior

120

await expect(component).toHaveClass('clicked');

121

});

122

123

storyTest('Button with custom args', async ({ mount }) => {

124

// Mount with custom args

125

const component = await mount(Primary, {

126

props: {

127

label: 'Custom Label',

128

disabled: true,

129

variant: 'secondary'

130

}

131

});

132

133

await expect(component).toBeDisabled();

134

await expect(component).toHaveText('Custom Label');

135

});

136

```

137

138

### CSF Factory Utilities

139

140

Functions for extracting annotations and metadata from CSF stories for testing.

141

142

```typescript { .api }

143

/**

144

* Gets factory annotations for CSF story testing and composition

145

* @param story - Story object or annotations

146

* @param meta - Component meta annotations (optional)

147

* @param projectAnnotations - Project-level annotations (optional)

148

* @returns Combined annotations for story factory

149

*/

150

function getCsfFactoryAnnotations<TRenderer>(

151

story: StoryAnnotations<TRenderer> | Story<TRenderer>,

152

meta?: ComponentAnnotations<TRenderer>,

153

projectAnnotations?: ProjectAnnotations<TRenderer>

154

): FactoryAnnotations<TRenderer>;

155

156

interface FactoryAnnotations<TRenderer> {

157

/** Combined story parameters */

158

parameters: Parameters;

159

/** Combined decorators */

160

decorators: DecoratorFunction<TRenderer>[];

161

/** Combined args */

162

args: Args;

163

/** Combined arg types */

164

argTypes: ArgTypes;

165

/** Render function */

166

render?: Function;

167

/** Play function */

168

play?: Function;

169

}

170

```

171

172

**Usage Examples:**

173

174

```typescript

175

import { getCsfFactoryAnnotations } from "@storybook/preview-api";

176

import * as ButtonStories from './Button.stories';

177

178

// Extract annotations for testing

179

const annotations = getCsfFactoryAnnotations(

180

ButtonStories.Primary,

181

ButtonStories.default,

182

globalConfig

183

);

184

185

// Use annotations in test setup

186

test('story has correct parameters', () => {

187

expect(annotations.parameters.docs?.description?.story).toBeDefined();

188

expect(annotations.args.primary).toBe(true);

189

});

190

191

// Create test utilities from annotations

192

const createTestStory = (overrides = {}) => {

193

return {

194

...annotations,

195

args: { ...annotations.args, ...overrides }

196

};

197

};

198

```

199

200

### Mock Utilities

201

202

Testing utilities for mocking Storybook's communication system.

203

204

```typescript { .api }

205

/**

206

* Creates a mock communication channel for testing addons and decorators

207

* @returns Mock channel with event emission and subscription

208

*/

209

function mockChannel(): MockChannel;

210

211

interface MockChannel {

212

/**

213

* Emit an event with data

214

* @param eventId - Event identifier

215

* @param args - Event data

216

*/

217

emit(eventId: string, ...args: any[]): void;

218

219

/**

220

* Subscribe to events

221

* @param eventId - Event identifier

222

* @param listener - Event handler function

223

*/

224

on(eventId: string, listener: Function): void;

225

226

/**

227

* Unsubscribe from events

228

* @param eventId - Event identifier

229

* @param listener - Event handler function to remove

230

*/

231

off(eventId: string, listener: Function): void;

232

233

/**

234

* Get all emitted events (for testing)

235

* @returns Array of emitted events

236

*/

237

getEmittedEvents(): EmittedEvent[];

238

239

/**

240

* Clear all emitted events history

241

*/

242

clearEmittedEvents(): void;

243

}

244

245

interface EmittedEvent {

246

eventId: string;

247

args: any[];

248

timestamp: number;

249

}

250

```

251

252

**Usage Examples:**

253

254

```typescript

255

import { mockChannel } from "@storybook/preview-api";

256

257

// Create mock channel for testing

258

const channel = mockChannel();

259

260

// Test addon communication

261

test('addon emits correct events', () => {

262

const addon = new MyAddon(channel);

263

264

addon.doSomething();

265

266

const events = channel.getEmittedEvents();

267

expect(events).toHaveLength(1);

268

expect(events[0].eventId).toBe('addon-action');

269

expect(events[0].args[0]).toEqual({ type: 'success' });

270

});

271

272

// Test event subscriptions

273

test('addon responds to events', () => {

274

const mockHandler = jest.fn();

275

const addon = new MyAddon(channel);

276

277

channel.on('external-event', mockHandler);

278

channel.emit('external-event', { data: 'test' });

279

280

expect(mockHandler).toHaveBeenCalledWith({ data: 'test' });

281

});

282

```

283

284

### Testing Utilities for Stories

285

286

Helper functions for testing story behavior and composition.

287

288

```typescript { .api }

289

/**

290

* Create test harness for story testing

291

* @param story - Story to test

292

* @param options - Test configuration options

293

* @returns Test harness with utilities

294

*/

295

function createStoryTestHarness<TRenderer>(

296

story: Story<TRenderer>,

297

options?: TestHarnessOptions

298

): StoryTestHarness<TRenderer>;

299

300

/**

301

* Creates mock channel implementation for testing (moved from deprecated addon API)

302

* @returns Mock channel with event tracking

303

*/

304

function mockChannel(): MockChannel;

305

306

interface TestHarnessOptions {

307

/** Mock implementations for dependencies */

308

mocks?: Record<string, any>;

309

/** Custom render container */

310

container?: HTMLElement;

311

/** Global test configuration */

312

globals?: Args;

313

}

314

315

interface StoryTestHarness<TRenderer> {

316

/**

317

* Render the story with given args

318

* @param args - Args to pass to story

319

* @returns Promise resolving to rendered result

320

*/

321

render(args?: Args): Promise<any>;

322

323

/**

324

* Update story args and re-render

325

* @param newArgs - Args to update

326

*/

327

updateArgs(newArgs: Args): Promise<void>;

328

329

/**

330

* Execute story play function

331

* @returns Promise resolving when play function completes

332

*/

333

executePlay(): Promise<void>;

334

335

/**

336

* Get current story context

337

* @returns Current story context

338

*/

339

getContext(): StoryContext<TRenderer>;

340

341

/**

342

* Clean up test harness

343

*/

344

cleanup(): void;

345

}

346

```

347

348

## Types & Interfaces

349

350

```typescript { .api }

351

interface ComposedStoryFn<TRenderer = any, TArgs = any> {

352

/** Execute story with optional args override */

353

(args?: Partial<TArgs>): any;

354

/** Story metadata */

355

storyName?: string;

356

args?: TArgs;

357

parameters?: Parameters;

358

argTypes?: ArgTypes;

359

id?: string;

360

}

361

362

interface PlayFunctionContext<TRenderer = any, TArgs = any> {

363

/** Story args */

364

args: TArgs;

365

/** Canvas element for interactions */

366

canvasElement: HTMLElement;

367

/** Step function for organizing test steps */

368

step: (label: string, play: (context: PlayFunctionContext<TRenderer, TArgs>) => Promise<void> | void) => Promise<void>;

369

/** Global values */

370

globals: Args;

371

/** Hooks context */

372

hooks: HooksContext<TRenderer>;

373

}

374

375

interface StoryAnnotations<TRenderer = any, TArgs = any> {

376

args?: Partial<TArgs>;

377

argTypes?: ArgTypes;

378

parameters?: Parameters;

379

decorators?: DecoratorFunction<TRenderer>[];

380

render?: (args: TArgs, context: StoryContext<TRenderer>) => any;

381

play?: (context: PlayFunctionContext<TRenderer, TArgs>) => Promise<void> | void;

382

}

383

384

interface ComponentAnnotations<TRenderer = any, TArgs = any> {

385

title?: string;

386

component?: any;

387

args?: Partial<TArgs>;

388

argTypes?: ArgTypes;

389

parameters?: Parameters;

390

decorators?: DecoratorFunction<TRenderer>[];

391

render?: (args: TArgs, context: StoryContext<TRenderer>) => any;

392

}

393

```