From 99bfa2892b1c2843d6a23b520f735925967d1a46 Mon Sep 17 00:00:00 2001 From: Brandon Dail Date: Tue, 3 Jan 2017 17:28:00 -0600 Subject: [PATCH] Use create-react-app for fixtures application This moves the current fixture architecture to one based around create-react-app. There are a few important things to note: * The react-loader.js script is always loaded before the bundle and will populate React and ReactDOM on the window. It is then read from the window by all components. * The UI for the "React Sandbox" or "React Fixtures App" is also rendered with whatever version of React the user has selected. This means we dont have to deal with iframes or worry about multiple versions of React potentially interferring. But it also means that all components must be written using createClass to be fully backwards compatable. I tested back to 0.13.1 and it works fine. --- fixtures/.gitignore | 15 + fixtures/README.md | 17 +- fixtures/package.json | 19 + fixtures/public/favicon.ico | Bin 0 -> 24838 bytes fixtures/public/index.html | 32 + fixtures/{ => public}/react-loader.js | 8 +- fixtures/range-inputs/index.html | 82 - fixtures/selects/index.html | 84 - fixtures/src/components/App.js | 19 + fixtures/src/components/Header.js | 68 + fixtures/src/components/RangeInputs.js | 28 + fixtures/src/components/TextInputs.js | 67 + fixtures/src/components/fixtures/index.js | 28 + .../fixtures}/range-inputs/README.md | 0 .../components/fixtures/range-inputs/index.js | 28 + .../components/fixtures}/selects/README.md | 0 .../src/components/fixtures/selects/index.js | 37 + .../fixtures}/text-inputs/README.md | 0 .../components/fixtures/text-inputs/index.js | 67 + .../components/fixtures}/textareas/README.md | 0 .../components/fixtures/textareas/index.js | 33 + fixtures/src/index.js | 8 + fixtures/src/styles/App.css | 94 + fixtures/src/styles/TextInputs.css | 36 + fixtures/test.html | 182 - fixtures/text-inputs/index.html | 120 - fixtures/textareas/index.html | 89 - fixtures/yarn.lock | 5283 +++++++++++++++++ 28 files changed, 5868 insertions(+), 576 deletions(-) create mode 100644 fixtures/.gitignore create mode 100644 fixtures/package.json create mode 100644 fixtures/public/favicon.ico create mode 100644 fixtures/public/index.html rename fixtures/{ => public}/react-loader.js (89%) delete mode 100644 fixtures/range-inputs/index.html delete mode 100644 fixtures/selects/index.html create mode 100644 fixtures/src/components/App.js create mode 100644 fixtures/src/components/Header.js create mode 100644 fixtures/src/components/RangeInputs.js create mode 100644 fixtures/src/components/TextInputs.js create mode 100644 fixtures/src/components/fixtures/index.js rename fixtures/{ => src/components/fixtures}/range-inputs/README.md (100%) create mode 100644 fixtures/src/components/fixtures/range-inputs/index.js rename fixtures/{ => src/components/fixtures}/selects/README.md (100%) create mode 100644 fixtures/src/components/fixtures/selects/index.js rename fixtures/{ => src/components/fixtures}/text-inputs/README.md (100%) create mode 100644 fixtures/src/components/fixtures/text-inputs/index.js rename fixtures/{ => src/components/fixtures}/textareas/README.md (100%) create mode 100644 fixtures/src/components/fixtures/textareas/index.js create mode 100644 fixtures/src/index.js create mode 100644 fixtures/src/styles/App.css create mode 100644 fixtures/src/styles/TextInputs.css delete mode 100644 fixtures/test.html delete mode 100644 fixtures/text-inputs/index.html delete mode 100644 fixtures/textareas/index.html create mode 100644 fixtures/yarn.lock diff --git a/fixtures/.gitignore b/fixtures/.gitignore new file mode 100644 index 0000000000000..6c96c5cff1242 --- /dev/null +++ b/fixtures/.gitignore @@ -0,0 +1,15 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# dependencies +node_modules + +# testing +coverage + +# production +build + +# misc +.DS_Store +.env +npm-debug.log diff --git a/fixtures/README.md b/fixtures/README.md index e421c3ebcbe28..fd2bf68fe076b 100644 --- a/fixtures/README.md +++ b/fixtures/README.md @@ -1,16 +1 @@ -# Browser Fixtures - -This folder contains tools to assist in the testing of browser quirks. - -Each document is browsable without setting up a static file server. Just open -the test case in a browser. - -## Browser Targets - -React 15+ supports all ES5 compliant browsers: - -https://facebook.github.io/react/docs/react-dom.html#browser-support - -### IE8 Support - -React 0.14 and lower support IE8 after including several required shims. +# React Fixtures (TODO) \ No newline at end of file diff --git a/fixtures/package.json b/fixtures/package.json new file mode 100644 index 0000000000000..d8154e046e9df --- /dev/null +++ b/fixtures/package.json @@ -0,0 +1,19 @@ +{ + "name": "_fixtures", + "version": "0.1.0", + "private": true, + "devDependencies": { + "react-scripts": "0.8.4" + }, + "dependencies": { + "query-string": "^4.2.3", + "react": "^15.4.1", + "react-dom": "^15.4.1" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test --env=jsdom", + "eject": "react-scripts eject" + } +} diff --git a/fixtures/public/favicon.ico b/fixtures/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5c125de5d897c1ff5692a656485b3216123dcd89 GIT binary patch literal 24838 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 + + + + + + + React App + + + +
+ + + diff --git a/fixtures/react-loader.js b/fixtures/public/react-loader.js similarity index 89% rename from fixtures/react-loader.js rename to fixtures/public/react-loader.js index 3f47f3ff211c3..aadc7e68431f9 100644 --- a/fixtures/react-loader.js +++ b/fixtures/public/react-loader.js @@ -7,8 +7,8 @@ * (Loads React 15.4.1) */ -var REACT_PATH = '../../build/react.js'; -var DOM_PATH = '../../build/react-dom.js'; +var REACT_PATH = 'react.js'; +var DOM_PATH = 'react-dom.js'; var BABEL_PATH = 'https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.19.0/babel.js'; function parseQuery(qstr) { @@ -25,9 +25,11 @@ function parseQuery(qstr) { return query; } -var query = parseQuery(window.location.search.slice(1)); +var query = parseQuery(window.location.search); var version = query.version || 'local'; +console.log(query) + if (version !== 'local') { REACT_PATH = 'https://unpkg.com/react@' + version + '/dist/react.min.js'; DOM_PATH = 'https://unpkg.com/react-dom@' + version + '/dist/react-dom.min.js'; diff --git a/fixtures/range-inputs/index.html b/fixtures/range-inputs/index.html deleted file mode 100644 index f8bd4c85881ee..0000000000000 --- a/fixtures/range-inputs/index.html +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - Range Inputs - - - - -
Loading...
- - - - - - diff --git a/fixtures/selects/index.html b/fixtures/selects/index.html deleted file mode 100644 index 4f2812ebf7e9a..0000000000000 --- a/fixtures/selects/index.html +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - Selects - - - - -
Loading...
- - - - - - diff --git a/fixtures/src/components/App.js b/fixtures/src/components/App.js new file mode 100644 index 0000000000000..7d6f04b143b6c --- /dev/null +++ b/fixtures/src/components/App.js @@ -0,0 +1,19 @@ +const React = window.React; +import Header from './Header'; +import Fixtures from './fixtures'; +import '../styles/App.css'; + +const App = React.createClass({ + render() { + return ( +
+
+
+ +
+
+ ); + }, +}); + +export default App; diff --git a/fixtures/src/components/Header.js b/fixtures/src/components/Header.js new file mode 100644 index 0000000000000..c93a5150729fc --- /dev/null +++ b/fixtures/src/components/Header.js @@ -0,0 +1,68 @@ +import { parse, stringify } from 'query-string'; +const React = window.React; + +const Header = React.createClass({ + getInitialState() { + const query = parse(window.location.search); + const version = query.version || 'local'; + const versions = [version]; + return { version, versions }; + }, + componentWillMount() { + fetch('http://api.github.com/repos/facebook/react/tags') + .then(res => res.json()) + .then(tags => { + let versions = tags.map(tag => tag.name.slice(1)); + versions = ['local', ...versions]; + this.setState({ versions }); + }); + }, + handleVersionChange(event) { + const query = parse(window.location.search); + query.version = event.target.value; + if (query.version === 'local') { + delete query.version; + } + window.location.search = stringify(query); + }, + handleFixtureChange(event) { + window.location.pathname = event.target.value; + }, + render() { + return ( +
+
+ + + React Sandbox (v{React.version}) + + +
+ + +
+
+
+ ); + }, +}); + +export default Header; diff --git a/fixtures/src/components/RangeInputs.js b/fixtures/src/components/RangeInputs.js new file mode 100644 index 0000000000000..eea1f996d6ed3 --- /dev/null +++ b/fixtures/src/components/RangeInputs.js @@ -0,0 +1,28 @@ +const React = window.React; + +const RangeInputs = React.createClass({ + getInitialState() { + return { value: 0.5 }; + }, + onChange(event) { + this.setState({ value: event.target.value }); + }, + render() { + return ( +
+
+ Controlled + + Value: {this.state.value} +
+ +
+ Uncontrolled + +
+
+ ); + }, +}); + +export default RangeInputs; diff --git a/fixtures/src/components/TextInputs.js b/fixtures/src/components/TextInputs.js new file mode 100644 index 0000000000000..62d16187c93b4 --- /dev/null +++ b/fixtures/src/components/TextInputs.js @@ -0,0 +1,67 @@ +const React = window.React; +import '../styles/TextInputs.css'; + +const TextInputFixtures = React.createClass({ + getInitialState() { + return { + color: '#ffaaee', + }; + }, + + renderControlled(type) { + let id = `controlled_${type}`; + + let onChange = e => { + let value = e.target.value; + if (type === 'number') { + value = value === '' ? '' : parseFloat(value, 10) || 0 + } + this.setState({ + [type] : value, + }); + }; + + let state = this.state[type] || ''; + + return ( +
+ + +   → {JSON.stringify(state)} +
+ ); + }, + + renderUncontrolled(type) { + let id = `uncontrolled_${type}`; + return ( +
+ + +
+ ); + }, + + render() { + // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input + let types = [ + 'text', 'email', 'number', 'url', 'tel', + 'color', 'date', 'datetime-local', + 'time', 'month', 'week', 'range', 'password', + ]; + return ( +
event.preventDefault()}> +
+ Controlled + {types.map(this.renderControlled)} +
+
+ Uncontrolled + {types.map(this.renderUncontrolled)} +
+
+ ); + }, +}); + +module.exports = TextInputFixtures; diff --git a/fixtures/src/components/fixtures/index.js b/fixtures/src/components/fixtures/index.js new file mode 100644 index 0000000000000..763939d28ff2c --- /dev/null +++ b/fixtures/src/components/fixtures/index.js @@ -0,0 +1,28 @@ +const React = window.React; +import RangeInputFixtures from './range-inputs'; +import TextInputFixtures from './text-inputs'; +import SelectFixtures from './selects'; +import TextAreaFixtures from './textareas/'; + +/** + * A simple routing component that renders the appropriate + * fixture based on the location pathname. + */ +const FixturesPage = React.createClass({ + render() { + switch (window.location.pathname) { + case '/text-inputs': + return ; + case '/range-inputs': + return ; + case '/selects': + return ; + case '/textareas': + return ; + default: + return ; + } + }, +}); + +module.exports = FixturesPage; diff --git a/fixtures/range-inputs/README.md b/fixtures/src/components/fixtures/range-inputs/README.md similarity index 100% rename from fixtures/range-inputs/README.md rename to fixtures/src/components/fixtures/range-inputs/README.md diff --git a/fixtures/src/components/fixtures/range-inputs/index.js b/fixtures/src/components/fixtures/range-inputs/index.js new file mode 100644 index 0000000000000..eea1f996d6ed3 --- /dev/null +++ b/fixtures/src/components/fixtures/range-inputs/index.js @@ -0,0 +1,28 @@ +const React = window.React; + +const RangeInputs = React.createClass({ + getInitialState() { + return { value: 0.5 }; + }, + onChange(event) { + this.setState({ value: event.target.value }); + }, + render() { + return ( +
+
+ Controlled + + Value: {this.state.value} +
+ +
+ Uncontrolled + +
+
+ ); + }, +}); + +export default RangeInputs; diff --git a/fixtures/selects/README.md b/fixtures/src/components/fixtures/selects/README.md similarity index 100% rename from fixtures/selects/README.md rename to fixtures/src/components/fixtures/selects/README.md diff --git a/fixtures/src/components/fixtures/selects/index.js b/fixtures/src/components/fixtures/selects/index.js new file mode 100644 index 0000000000000..3b170b24f54f1 --- /dev/null +++ b/fixtures/src/components/fixtures/selects/index.js @@ -0,0 +1,37 @@ +const React = window.React; + +const SelectFixture = React.createClass({ + getInitialState() { + return { value: '' }; + }, + onChange(event) { + this.setState({ value: event.target.value }) + }, + render() { + return ( +
+
+ Controlled + + Value: {this.state.value} +
+
+ Uncontrolled + +
+
+ ); + }, +}); + +export default SelectFixture; diff --git a/fixtures/text-inputs/README.md b/fixtures/src/components/fixtures/text-inputs/README.md similarity index 100% rename from fixtures/text-inputs/README.md rename to fixtures/src/components/fixtures/text-inputs/README.md diff --git a/fixtures/src/components/fixtures/text-inputs/index.js b/fixtures/src/components/fixtures/text-inputs/index.js new file mode 100644 index 0000000000000..904a8bdc3bfe3 --- /dev/null +++ b/fixtures/src/components/fixtures/text-inputs/index.js @@ -0,0 +1,67 @@ +const React = window.React; +import '../../../styles/TextInputs.css'; + +const TextInputFixtures = React.createClass({ + getInitialState() { + return { + color: '#ffaaee', + }; + }, + + renderControlled(type) { + let id = `controlled_${type}`; + + let onChange = e => { + let value = e.target.value; + if (type === 'number') { + value = value === '' ? '' : parseFloat(value, 10) || 0 + } + this.setState({ + [type] : value, + }); + }; + + let state = this.state[type] || ''; + + return ( +
+ + +   → {JSON.stringify(state)} +
+ ); + }, + + renderUncontrolled(type) { + let id = `uncontrolled_${type}`; + return ( +
+ + +
+ ); + }, + + render() { + // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input + let types = [ + 'text', 'email', 'number', 'url', 'tel', + 'color', 'date', 'datetime-local', + 'time', 'month', 'week', 'range', 'password', + ]; + return ( +
event.preventDefault()}> +
+ Controlled + {types.map(this.renderControlled)} +
+
+ Uncontrolled + {types.map(this.renderUncontrolled)} +
+
+ ); + }, +}); + +module.exports = TextInputFixtures; diff --git a/fixtures/textareas/README.md b/fixtures/src/components/fixtures/textareas/README.md similarity index 100% rename from fixtures/textareas/README.md rename to fixtures/src/components/fixtures/textareas/README.md diff --git a/fixtures/src/components/fixtures/textareas/index.js b/fixtures/src/components/fixtures/textareas/index.js new file mode 100644 index 0000000000000..f500e679daef1 --- /dev/null +++ b/fixtures/src/components/fixtures/textareas/index.js @@ -0,0 +1,33 @@ +const React = window.React; + +const TextAreaFixtures = React.createClass({ + getInitialState() { + return { value: '' }; + }, + onChange(event) { + this.setState({ value: event.target.value }) + }, + render() { + return ( +
+
+
+ Controlled +