Repository: styleguidist/react-styleguidist
Pull request #926 (2018-04-05 16:23:11)

WIP: Style guide for Styleguidist UI - issue #897
WIP for #897 

styleguidist-bot: 
<!--
  0 failure: 
  1 warning:  Changes were made...
  
  
  DangerID: danger-id-default;
-->


<table>
  <thead>
    <tr>
      <th width="50"></th>
      <th width="100%" data-danger-table="true">Warnings</th>
    </tr>
  </thead>
  <tbody><tr>
      <td>:warning:</td>
      <td>

  Changes were made to `package.json`, but not to `package-lock.json`.

Perhaps you need to run `npm install` and commit changes in package-lock.json. Make sure you’re using npm 5+.
  </td>
    </tr>
  </tbody>
</table>



<p align="right">
  Generated by :no_entry_sign: <a href="http://github.com/danger/danger-js/">dangerJS</a>
</p>

sapegin: Thanks for the pull request! I'll look into failing tests, I didn't expect that ;-£
sapegin: You can remove `defaultExample: true` — it will fix errors you see in the browsers console.
leahzxxz: @sapegin thanks! there was also a React error for getting the same key for an `li` element so i added `Math.random()` to the key, let me know if you prefer another way to do it :)  Thanks for all the instructions!

Regarding the `package-lock` warning, I tried removing and `npm install` again but there's nothing new to commit (I guess it's because I just added a start script and it didn't affect any versioning in `package-lock`). any idea on what to do here? thanks!
sapegin: > @sapegin thanks! there was also a React error for getting the same key for an li element so i added Math.random() to the key, let me know if you prefer another way to do it :) 

Please don't use random keys in React, this is much worse than using indexes as keys (which can be acceptable in rare cases): you're telling React that you have a new object every render, so React has remove a previous element, create and mount a new one, instead of updating an existing one (in case of changed props) or not doing anything at all. This is never what you want ;-) Could you try `filepath` instead of `name`?

> Regarding the package-lock warning, I tried removing and npm install again but there's nothing new to commit (I guess it's because I just added a start script and it didn't affect any versioning in package-lock).

Ignore that, we need to make the warning more clear ;-) You need to do that if you change any dependencies, which isn't the case here.

Patch:
diff --git a/.eslintrc b/.eslintrc
index 4b4c9b56..23b03a9e 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -7,7 +7,6 @@
   },
   "plugins": [
     "compat",
-    "es5",
     "import"
   ],
   "settings": {
diff --git a/bin/.eslintrc b/bin/.eslintrc
index b1ac0de2..3f2315df 100644
--- a/bin/.eslintrc
+++ b/bin/.eslintrc
@@ -2,10 +2,5 @@
 	"extends": "tamia",
 	"parserOptions": {
 		"sourceType": "script"
-	},
-	"rules": {
-		"es5/no-default-parameters": 2,
-		"es5/no-destructuring": 2,
-		"es5/no-spread": 2
 	}
 }
diff --git a/dangerfile.js b/dangerfile.js
index 4ddcea8f..2300aa83 100644
--- a/dangerfile.js
+++ b/dangerfile.js
@@ -7,7 +7,7 @@ const lockfileChanged = danger.git.modified_files.includes('package-lock.json');
 if (packageChanged && !lockfileChanged) {
 	warn(`Changes were made to \`package.json\`, but not to \`package-lock.json\`.
 
-Perhaps you need to run \`npm install\` and commit changes in package-lock.json. Make sure you’re using npm 5+.`);
+If you’ve changed any dependencies (added, removed or updated any packages), please run \`npm install\` and commit changes in package-lock.json file. Make sure you’re using npm 5+.`);
 }
 
 if (!packageChanged && lockfileChanged) {
diff --git a/docs/Thirdparties.md b/docs/Thirdparties.md
index ab5bf6a3..2576142f 100644
--- a/docs/Thirdparties.md
+++ b/docs/Thirdparties.md
@@ -219,7 +219,7 @@ This will automatically apply your theme to your styled-components. When you fir
 
 ### Fela
 
-Check out the [official example](https://github.com/rofrischmann/fela/tree/master/packages/example-with-styleguidist).
+Check out the [official example](https://github.com/rofrischmann/fela/tree/master/examples/example-with-styleguidist).
 
 ### CSS Modules with react-css-modules
 
diff --git a/loaders/.eslintrc b/loaders/.eslintrc
index 5d07fa2b..1d5f79c5 100644
--- a/loaders/.eslintrc
+++ b/loaders/.eslintrc
@@ -4,9 +4,6 @@
 		"sourceType": "script"
 	},
 	"rules": {
-		"no-invalid-this": 0,
-		"es5/no-default-parameters": 2,
-		"es5/no-destructuring": 2,
-		"es5/no-spread": 2
+		"no-invalid-this": 0
 	}
 }
diff --git a/package-lock.json b/package-lock.json
index 1a681878..ca9de5d1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4296,9 +4296,9 @@
       }
     },
     "eslint-plugin-es5": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-es5/-/eslint-plugin-es5-1.2.0.tgz",
-      "integrity": "sha512-mT2vXx1D7WriOIxKNB38hCSoMbJ6HW5GJNQ8zsR3eGysUPYgsv2+dr+Oo1Bx+MWm9GauHDvZv5fBNE3Pu5Qf5g==",
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-es5/-/eslint-plugin-es5-1.3.1.tgz",
+      "integrity": "sha512-2oq0R/3XoAsiMwllwsHmnk0gA7+KSvRHUAiJ7Pa/iKrClywVd1q/G7LDZHXU5YD+9kVNxlK155ElXrmX8uLW8A==",
       "dev": true
     },
     "eslint-plugin-import": {
@@ -8675,7 +8675,7 @@
         },
         "onetime": {
           "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
+          "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
           "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
           "dev": true
         },
@@ -8835,7 +8835,7 @@
         },
         "onetime": {
           "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
+          "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
           "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
           "dev": true
         },
@@ -8969,7 +8969,7 @@
         },
         "onetime": {
           "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
+          "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
           "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
           "dev": true
         },
diff --git a/package.json b/package.json
index 18c319bd..f2da0440 100644
--- a/package.json
+++ b/package.json
@@ -66,7 +66,7 @@
     "loader-utils": "^1.1.0",
     "lodash": "^4.17.5",
     "lowercase-keys": "^1.0.1",
-    "markdown-to-jsx": "^6.6.0",
+    "markdown-to-jsx": "^6.4.1",
     "mini-html-webpack-plugin": "^0.2.3",
     "minimist": "^1.2.0",
     "ora": "^2.0.0",
@@ -113,7 +113,7 @@
     "eslint": "^4.19.1",
     "eslint-config-tamia": "^5.0.1",
     "eslint-plugin-compat": "^2.2.0",
-    "eslint-plugin-es5": "^1.2.0",
+    "eslint-plugin-es5": "^1.3.1",
     "eslint-plugin-import": "^2.10.0",
     "eslint-plugin-react": "^7.7.0",
     "file-loader": "^1.1.11",
@@ -143,6 +143,7 @@
     "start": "node bin/styleguidist.js server --config examples/basic/styleguide.config.js",
     "start:customised": "node bin/styleguidist.js server --config examples/customised/styleguide.config.js",
     "start:sections": "node bin/styleguidist.js server --config examples/sections/styleguide.config.js",
+    "start:ui": "node bin/styleguidist.js server",
     "lint": "eslint . --cache --fix",
     "precompile": "rimraf lib/",
     "compile": "babel --ignore '*.spec.js' -d lib/ src/",
diff --git a/scripts/.eslintrc b/scripts/.eslintrc
index b1ac0de2..3f2315df 100644
--- a/scripts/.eslintrc
+++ b/scripts/.eslintrc
@@ -2,10 +2,5 @@
 	"extends": "tamia",
 	"parserOptions": {
 		"sourceType": "script"
-	},
-	"rules": {
-		"es5/no-default-parameters": 2,
-		"es5/no-destructuring": 2,
-		"es5/no-spread": 2
 	}
 }
diff --git a/scripts/config.js b/scripts/config.js
index d6d2d079..1bd0d750 100644
--- a/scripts/config.js
+++ b/scripts/config.js
@@ -2,6 +2,7 @@ const fs = require('fs');
 const path = require('path');
 const findup = require('findup');
 const isString = require('lodash/isString');
+const isPlainObject = require('lodash/isPlainObject');
 const StyleguidistError = require('./utils/error');
 const sanitizeConfig = require('./utils/sanitizeConfig');
 const schema = require('./schemas/config');
@@ -16,8 +17,6 @@ const CONFIG_FILENAME = 'styleguide.config.js';
  * @returns {object}
  */
 function getConfig(config, update) {
-	config = config || {};
-
 	let configFilepath;
 	if (isString(config)) {
 		// Load config from a given file
@@ -26,9 +25,10 @@ function getConfig(config, update) {
 			throw new StyleguidistError('Styleguidist config not found: ' + configFilepath + '.');
 		}
 		config = {};
-	} else {
+	} else if (!isPlainObject(config)) {
 		// Try to read config options from a file
 		configFilepath = findConfigFile();
+		config = {};
 	}
 
 	if (configFilepath) {
diff --git a/scripts/schemas/config.js b/scripts/schemas/config.js
index 9a42224e..1d94f6f9 100644
--- a/scripts/schemas/config.js
+++ b/scripts/schemas/config.js
@@ -267,7 +267,7 @@ module.exports = {
 			if (val) {
 				return val;
 			}
-			const name = getUserPackageJson().name;
+			const name = getUserPackageJson().name || '';
 			return `${startCase(name)} Style Guide`;
 		},
 		example: 'My Style Guide',
diff --git a/scripts/utils/getUserPackageJson.js b/scripts/utils/getUserPackageJson.js
index 15a05f13..1b46d6be 100644
--- a/scripts/utils/getUserPackageJson.js
+++ b/scripts/utils/getUserPackageJson.js
@@ -6,5 +6,9 @@ const path = require('path');
  * @return {object}
  */
 module.exports = function getUserPackageJson() {
-	return require(path.resolve(process.cwd(), 'package.json'));
+	try {
+		return require(path.resolve(process.cwd(), 'package.json'));
+	} catch (err) {
+		return {};
+	}
 };
diff --git a/src/rsg-components/ComponentsList/ComponentsListRenderer.js b/src/rsg-components/ComponentsList/ComponentsListRenderer.js
index 4b376a22..e4e6032e 100644
--- a/src/rsg-components/ComponentsList/ComponentsListRenderer.js
+++ b/src/rsg-components/ComponentsList/ComponentsListRenderer.js
@@ -45,7 +45,7 @@ export function ComponentsListRenderer({ classes, items }) {
 			{items.map(({ heading, name, href, content }) => (
 				<li
 					className={cx(classes.item, (!content || !content.props.items.length) && classes.isChild)}
-					key={name}
+					key={href}
 				>
 					<Link className={cx(heading && classes.heading)} href={href}>
 						{name}
diff --git a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap
index 8eb43c4a..291827f8 100644
--- a/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap
+++ b/src/rsg-components/ComponentsList/__snapshots__/ComponentsList.spec.js.snap
@@ -4,7 +4,7 @@ exports[`should ignore items without name 1`] = `
 <ul>
   <li
     className=""
-    key="Button"
+    key="#button"
   >
     <Styled(Link)
       className=""
@@ -20,7 +20,7 @@ exports[`should render sections with nested components 1`] = `
 <ul>
   <li
     className=""
-    key="Button"
+    key="#button"
   >
     <Styled(Link)
       className=""
@@ -31,7 +31,7 @@ exports[`should render sections with nested components 1`] = `
   </li>
   <li
     className=""
-    key="Input"
+    key="#input"
   >
     <Styled(Link)
       className=""
diff --git a/styleguide.config.js b/styleguide.config.js
new file mode 100644
index 00000000..c8ede797
--- /dev/null
+++ b/styleguide.config.js
@@ -0,0 +1,18 @@
+module.exports = {
+	components: 'src/rsg-components/**/[A-Z]*.js',
+	webpackConfig: {
+		module: {
+			rules: [
+				{
+					test: /\.jsx?$/,
+					exclude: /node_modules/,
+					loader: 'babel-loader',
+				},
+				{
+					test: /\.css$/,
+					loader: 'style-loader!css-loader',
+				},
+			],
+		},
+	},
+};


Test patch:
diff --git a/loaders/__tests__/styleguide-loader.spec.js b/loaders/__tests__/styleguide-loader.spec.js
index 2b2d6a86..7ee45826 100644
--- a/loaders/__tests__/styleguide-loader.spec.js
+++ b/loaders/__tests__/styleguide-loader.spec.js
@@ -4,17 +4,18 @@ import { readFileSync } from 'fs';
 import styleguideLoader from '../styleguide-loader';
 import getConfig from '../../scripts/config';
 
-const file = './test/components/Button/Button.js';
-
 /* eslint-disable quotes */
 
+const file = path.resolve(__dirname, '../../test/components/Button/Button.js');
+const configDir = path.resolve(__dirname, '../../test');
+
 it('should return valid, parsable JS', () => {
 	const result = styleguideLoader.pitch.call(
 		{
 			request: file,
 			_styleguidist: {
-				sections: [{ components: '../../test/components/**/*.js' }],
-				configDir: __dirname,
+				sections: [{ components: 'components/**/*.js' }],
+				configDir,
 				getExampleFilename: () => 'Readme.md',
 				getComponentPathLine: filepath => filepath,
 			},
@@ -31,8 +32,7 @@ it('should return correct component paths: default glob pattern', () => {
 		{
 			request: file,
 			_styleguidist: {
-				...getConfig(),
-				configDir: path.resolve(__dirname, '../../examples/cra'),
+				...getConfig(path.resolve(__dirname, '../../test/apps/defaults/styleguide.config.js')),
 			},
 			addContextDependency: () => {},
 		},
@@ -42,7 +42,6 @@ it('should return correct component paths: default glob pattern', () => {
 	expect(() => new vm.Script(result)).not.toThrow();
 	expect(result).toMatch(`'filepath': 'src/components/Button.js'`);
 	expect(result).toMatch(`'filepath': 'src/components/Placeholder.js'`);
-	expect(result).toMatch(`'filepath': 'src/components/RandomButton.js'`);
 });
 
 it('should return correct component paths: glob', () => {
@@ -51,7 +50,7 @@ it('should return correct component paths: glob', () => {
 			request: file,
 			_styleguidist: {
 				sections: [{ components: 'components/**/*.js' }],
-				configDir: path.resolve(__dirname, '../../test'),
+				configDir,
 				getExampleFilename: () => 'Readme.md',
 				getComponentPathLine: filepath => filepath,
 			},
@@ -74,12 +73,12 @@ it('should return correct component paths: function returning absolute paths', (
 				sections: [
 					{
 						components: () => [
-							`${__dirname}/components/Button/Button.js`,
-							`${__dirname}/components/Placeholder/Placeholder.js`,
+							`${configDir}/components/Button/Button.js`,
+							`${configDir}/components/Placeholder/Placeholder.js`,
 						],
 					},
 				],
-				configDir: __dirname,
+				configDir,
 				getExampleFilename: () => 'Readme.md',
 				getComponentPathLine: filepath => filepath,
 			},
@@ -107,7 +106,7 @@ it('should return correct component paths: function returning relative paths', (
 						],
 					},
 				],
-				configDir: __dirname,
+				configDir,
 				getExampleFilename: () => 'Readme.md',
 				getComponentPathLine: filepath => filepath,
 			},
@@ -132,7 +131,7 @@ it('should return correct component paths: array of of relative paths', () => {
 						components: ['components/Button/Button.js', 'components/Placeholder/Placeholder.js'],
 					},
 				],
-				configDir: __dirname,
+				configDir,
 				getExampleFilename: () => 'Readme.md',
 				getComponentPathLine: filepath => filepath,
 			},
@@ -159,7 +158,7 @@ it('should filter out components without examples if skipComponentsWithoutExampl
 						],
 					},
 				],
-				configDir: path.resolve(__dirname, '../../test'),
+				configDir,
 				skipComponentsWithoutExample: true,
 				getExampleFilename: componentPath => path.join(path.dirname(componentPath), 'Readme.md'),
 				getComponentPathLine: filepath => filepath,
@@ -182,7 +181,9 @@ it('should add context dependencies to webpack from contextDependencies config o
 			request: file,
 			_styleguidist: {
 				sections: [{ components: 'components/**/*.js' }],
-				configDir: __dirname,
+				configDir,
+				getExampleFilename: () => 'Readme.md',
+				getComponentPathLine: filepath => filepath,
 				contextDependencies,
 			},
 			addContextDependency,
@@ -201,7 +202,7 @@ it('should add common parent folder of all components to context dependencies',
 			request: file,
 			_styleguidist: {
 				sections: [{ components: 'components/**/*.js' }],
-				configDir: path.resolve(__dirname, '../../test'),
+				configDir,
 				getExampleFilename: () => 'Readme.md',
 				getComponentPathLine: filepath => filepath,
 			},
diff --git a/scripts/__tests__/config.spec.js b/scripts/__tests__/config.spec.js
index c72eadec..02713352 100644
--- a/scripts/__tests__/config.spec.js
+++ b/scripts/__tests__/config.spec.js
@@ -3,17 +3,21 @@ import path from 'path';
 import getConfig from '../config';
 
 const cwd = process.cwd();
-afterEach(() => {
+const configDir = path.resolve(__dirname, '../../test/apps/defaults');
+beforeEach(() => {
+	process.chdir(configDir);
+});
+afterAll(() => {
 	process.chdir(cwd);
 });
 
 it('should read a config file', () => {
-	const result = getConfig('./test/data/styleguide.config.js');
+	const result = getConfig('../basic/styleguide.config.js');
 	expect(result).toMatchObject({ title: 'React Style Guide Example' });
 });
 
 it('should accept absolute path', () => {
-	const result = getConfig(path.join(__dirname, '../../test/data/styleguide.config.js'));
+	const result = getConfig(path.join(__dirname, '../../test/apps/basic/styleguide.config.js'));
 	expect(result).toMatchObject({ title: 'React Style Guide Example' });
 });
 
@@ -23,8 +27,8 @@ it('should throw when passed config file not found', () => {
 });
 
 it('should find config file automatically', () => {
-	process.chdir('test/apps/basic');
-	const result = getConfig({});
+	process.chdir('../basic');
+	const result = getConfig();
 	expect(result).toMatchObject({ title: 'React Style Guide Example' });
 });
 
@@ -62,23 +66,26 @@ it('should have default getExampleFilename implementation', () => {
 });
 
 it('default getExampleFilename should return Readme.md path if it exists', () => {
+	process.chdir('../..');
 	const result = getConfig();
-	expect(result.getExampleFilename(path.resolve('test/components/Button/Button.js'))).toEqual(
-		path.resolve('test/components/Button/Readme.md')
+	expect(result.getExampleFilename(path.resolve('components/Button/Button.js'))).toEqual(
+		path.resolve('components/Button/Readme.md')
 	);
 });
 
 it('default getExampleFilename should return Component.md path if it exists', () => {
+	process.chdir('../..');
 	const result = getConfig();
-	expect(
-		result.getExampleFilename(path.resolve('test/components/Placeholder/Placeholder.js'))
-	).toEqual(path.resolve('test/components/Placeholder/Placeholder.md'));
+	expect(result.getExampleFilename(path.resolve('components/Placeholder/Placeholder.js'))).toEqual(
+		path.resolve('components/Placeholder/Placeholder.md')
+	);
 });
 
 it('default getExampleFilename should return false if no examples file found', () => {
+	process.chdir('../..');
 	const result = getConfig();
 	expect(
-		result.getExampleFilename(path.resolve('test/components/RandomButton/RandomButton.js'))
+		result.getExampleFilename(path.resolve('components/RandomButton/RandomButton.js'))
 	).toBeFalsy();
 });
 
@@ -90,14 +97,12 @@ it('should have default getComponentPathLine implementation', () => {
 
 it('should have default title based on package.json name', () => {
 	const result = getConfig();
-	expect(result.title).toEqual('React Styleguidist Style Guide');
+	expect(result.title).toEqual('Pizza Style Guide');
 });
 
 it('configDir option should be a directory of a passed config', () => {
-	const dir = path.resolve('test/apps/basic');
-	process.chdir(dir);
-	const result = getConfig(path.join(dir, 'styleguide.config.js'));
-	expect(result).toMatchObject({ configDir: dir });
+	const result = getConfig(path.join(configDir, 'styleguide.config.js'));
+	expect(result).toMatchObject({ configDir });
 });
 
 it('configDir option should be a current directory if the config was passed as an object', () => {
@@ -106,10 +111,11 @@ it('configDir option should be a current directory if the config was passed as a
 });
 
 it('should absolutize assetsDir if it exists', () => {
+	const assetsDir = 'src/components';
 	const result = getConfig({
-		assetsDir: 'scripts/__tests__',
+		assetsDir,
 	});
-	expect(result.assetsDir).toEqual(__dirname);
+	expect(result.assetsDir).toEqual(path.join(configDir, assetsDir));
 });
 
 it('should throw if assetsDir does not exist', () => {
@@ -130,7 +136,7 @@ it('should use embedded default example template if defaultExample=true', () =>
 
 it('should absolutize defaultExample if it is a string', () => {
 	const result = getConfig({
-		defaultExample: 'test/components/Button/Readme.md',
+		defaultExample: 'src/components/Button.md',
 	});
 	expect(result.defaultExample[0]).toEqual('/');
 });
@@ -144,7 +150,7 @@ it('should throw if defaultExample does not exist', () => {
 });
 
 it('should use components option as the first sections if there’s no sections option', () => {
-	const components = 'test/components/*/*.js';
+	const components = 'components/*/*.js';
 	const result = getConfig({
 		components,
 	});
@@ -159,9 +165,9 @@ it('should use default components option both components and sections options we
 });
 
 it('should ignore components option there’s sections options', () => {
-	const components = 'test/components/*/*.js';
+	const components = 'components/*/*.js';
 	const result = getConfig({
-		components: 'test/components/Button/*.js',
+		components: 'components/Button/*.js',
 		sections: [
 			{
 				components,
@@ -181,7 +187,7 @@ it('should return webpackConfig option as is', () => {
 });
 
 it('should return webpackConfig with user webpack config', () => {
-	process.chdir('test/apps/basic');
+	process.chdir('../basic');
 	const result = getConfig();
 	expect(result.webpackConfig).toEqual(
 		expect.objectContaining({
@@ -193,7 +199,7 @@ it('should return webpackConfig with user webpack config', () => {
 });
 
 it('should allow no webpack config', () => {
-	process.chdir('test/apps/no-webpack');
+	process.chdir('../no-webpack');
 	const fn = () => getConfig();
 	expect(fn).not.toThrow();
 });
diff --git a/test/apps/defaults/package.json b/test/apps/defaults/package.json
new file mode 100644
index 00000000..d7695f6a
--- /dev/null
+++ b/test/apps/defaults/package.json
@@ -0,0 +1,3 @@
+{
+  "name": "Pizza"
+}
diff --git a/test/apps/defaults/src/components/Button.js b/test/apps/defaults/src/components/Button.js
new file mode 100644
index 00000000..e69de29b
diff --git a/test/apps/defaults/src/components/Button.md b/test/apps/defaults/src/components/Button.md
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/test/apps/defaults/src/components/Button.md
@@ -0,0 +1,1 @@
+
diff --git a/test/apps/defaults/src/components/Placeholder.js b/test/apps/defaults/src/components/Placeholder.js
new file mode 100644
index 00000000..e69de29b
diff --git a/test/apps/defaults/styleguide.config.js b/test/apps/defaults/styleguide.config.js
new file mode 100644
index 00000000..f053ebf7
--- /dev/null
+++ b/test/apps/defaults/styleguide.config.js
@@ -0,0 +1,1 @@
+module.exports = {};