Skip to content

Commit

Permalink
add isTestRunner utility
Browse files Browse the repository at this point in the history
  • Loading branch information
yannbf committed Oct 6, 2022
1 parent 1742e05 commit d1bba72
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 6 deletions.
31 changes: 28 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ Storybook test runner turns all of your stories into executable tests.
- [DOM snapshot recipe](#dom-snapshot-recipe)
- [Image snapshot recipe](#image-snapshot-recipe)
- [Render lifecycle](#render-lifecycle)
- [Global utility functions](#global-utility-functions)
- [Utility functions](#utility-functions)
- [getStoryContext](#getstorycontext)
- [isTestRunner](#istestrunner)
- [Troubleshooting](#troubleshooting)
- [The error output in the CLI is too short](#the-error-output-in-the-cli-is-too-short)
- [The test runner seems flaky and keeps timing out](#the-test-runner-seems-flaky-and-keeps-timing-out)
Expand Down Expand Up @@ -475,7 +477,11 @@ it('button--basic', async () => {
});
```

### Global utility functions
### Utility functions

For more specific use cases, the test runner provides utility functions that could be useful to you.

#### getStoryContext

While running tests using the hooks, you might want to get information from a story, such as the parameters passed to it, or its args. The test runner now provides a `getStoryContext` utility function that fetches the story context for the current story:

Expand Down Expand Up @@ -506,7 +512,7 @@ module.exports = {
// Apply story-level a11y rules
await configureAxe(page, {
rules: storyContext.parameters?.a11y?.config?.rules,
})
});

// from Storybook 7.0 onwards, the selector should be #storybook-root
await checkA11y(page, '#root', {
Expand All @@ -521,6 +527,25 @@ module.exports = {
};
```
#### isTestRunner
The `isTestRunner` function can be used to determine if a story is rendering in the context of the test runner.
```js
import { isTestRunner } from '@storybook/test-runner/is-test-runner';
export const MyStory = () => (
<div>
<p>Is this story running in the test runner?</p>
<p>{isTestRunner() ? 'Yes' : 'No'}</p>
</div>
);
```
The result of `isTestRunner()` will be true in the following scenarios:
1. In the browser, when the story is rendered while running the test runner
2. In node, if you prepend your Storybook script with `STORYBOOK_TEST_RUNNER=true`
## Troubleshooting
#### The error output in the CLI is too short
Expand Down
2 changes: 1 addition & 1 deletion bin/test-storybook.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ const fs = require('fs');
const dedent = require('ts-dedent').default;
const path = require('path');
const tempy = require('tempy');
const semver = require('semver');
const { getCliOptions, getStorybookMetadata } = require('../dist/cjs/util');
const { transformPlaywrightJson } = require('../dist/cjs/playwright/transformPlaywrightJson');

// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.STORYBOOK_TEST_RUNNER = 'true';
process.env.PUBLIC_URL = '';

// Makes the script crash on unhandled rejections instead of silently
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
"jest-watch-typeahead": "^2.0.0",
"node-fetch": "^2",
"playwright": "^1.14.0",
"read-pkg-up": "^7.0.1",
"regenerator-runtime": "^0.13.9",
"semver": "^7.3.7",
"tempy": "^1.0.1",
Expand Down
13 changes: 13 additions & 0 deletions src/is-test-runner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Returns whether the story is rendering inside of the Storybook test runner.
*/
export function isTestRunner() {
const isTestRunnerInNode = process?.env?.STORYBOOK_TEST_RUNNER === 'true';
const isTestRunnerInBrowser = !!(
typeof window !== 'undefined' &&
window &&
window.navigator.userAgent.match(/StorybookTestRunner/)
);

return isTestRunnerInNode || isTestRunnerInBrowser;
}
18 changes: 16 additions & 2 deletions src/setup-page.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Page } from 'playwright';
import dedent from 'ts-dedent';
import readPackageUp from 'read-pkg-up';

const sanitizeURL = (url: string) => {
let finalURL = url;
Expand All @@ -25,8 +25,9 @@ const sanitizeURL = (url: string) => {
export const setupPage = async (page: Page) => {
const targetURL = new URL('iframe.html', process.env.TARGET_URL).toString();
const viewMode = process.env.VIEW_MODE || 'story';
const isCoverageMode = process.env.STORYBOOK_COLLECT_COVERAGE === 'true';
const renderedEvent = viewMode === 'docs' ? 'docsRendered' : 'storyRendered';
const { packageJson } = await readPackageUp();
const { version: testRunnerVersion } = packageJson;

const referenceURL = process.env.REFERENCE_URL && sanitizeURL(process.env.REFERENCE_URL);
const debugPrintLimit = process.env.DEBUG_PRINT_LIMIT
Expand Down Expand Up @@ -102,6 +103,17 @@ export const setupPage = async (page: Page) => {
return input;
}
function addToUserAgent(extra) {
const originalUserAgent = globalThis.navigator.userAgent;
if (!originalUserAgent.includes(extra)) {
Object.defineProperty(globalThis.navigator, 'userAgent', {
get: function () {
return [originalUserAgent, extra].join(' ');
},
});
}
};
class StorybookTestRunnerError extends Error {
constructor(storyId, errorMessage, logs) {
super(errorMessage);
Expand Down Expand Up @@ -166,6 +178,8 @@ export const setupPage = async (page: Page) => {
);
}
addToUserAgent(\`(StorybookTestRunner@${testRunnerVersion})\`);
// collect logs to show upon test error
let logs = [];
Expand Down

0 comments on commit d1bba72

Please sign in to comment.