From 3bec9f070fa0de5c749f91a9bcbf7a901135cb8f Mon Sep 17 00:00:00 2001 From: Andreas Svensson Date: Mon, 12 May 2014 22:25:57 +0200 Subject: [PATCH 001/480] Guard against contentEditable with children props --- src/browser/ui/ReactDOMComponent.js | 10 ++++++++++ .../ui/__tests__/ReactDOMComponent-test.js | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/browser/ui/ReactDOMComponent.js b/src/browser/ui/ReactDOMComponent.js index 6b65664e8673..8b5136c7fe09 100644 --- a/src/browser/ui/ReactDOMComponent.js +++ b/src/browser/ui/ReactDOMComponent.js @@ -58,6 +58,16 @@ function assertValidProps(props) { props.children == null || props.dangerouslySetInnerHTML == null, 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.' ); + if (__DEV__) { + if (props.contentEditable && props.children != null) { + console.warn( + 'A component is `contentEditable` and contains `children` managed by ' + + 'React. It is now your responsibility to guarantee that none of those '+ + 'nodes are unexpectedly modified or duplicated. This is probably not ' + + 'intentional.' + ); + } + } invariant( props.style == null || typeof props.style === 'object', 'The `style` prop expects a mapping from style properties to values, ' + diff --git a/src/browser/ui/__tests__/ReactDOMComponent-test.js b/src/browser/ui/__tests__/ReactDOMComponent-test.js index ccc279f2e29e..cdaf226c62a1 100644 --- a/src/browser/ui/__tests__/ReactDOMComponent-test.js +++ b/src/browser/ui/__tests__/ReactDOMComponent-test.js @@ -335,6 +335,13 @@ describe('ReactDOMComponent', function() { ); }); + it("should warn about contentEditable and children", function() { + spyOn(console, 'warn'); + mountComponent({ contentEditable: true, children: '' }); + expect(console.warn.argsForCall.length).toBe(1); + expect(console.warn.argsForCall[0][0]).toContain('contentEditable'); + }); + it("should validate against invalid styles", function() { expect(function() { mountComponent({ style: 'display: none' }); @@ -368,6 +375,16 @@ describe('ReactDOMComponent', function() { ); }); + it("should warn about contentEditable and children", function() { + spyOn(console, 'warn'); + React.renderComponent( +
, + container + ); + expect(console.warn.argsForCall.length).toBe(1); + expect(console.warn.argsForCall[0][0]).toContain('contentEditable'); + }); + it("should validate against invalid styles", function() { React.renderComponent(
, container); From 05fa75d395ba6a3caeeaf26f7da154a8787cd3db Mon Sep 17 00:00:00 2001 From: Andreas Svensson Date: Wed, 3 Sep 2014 15:30:23 +0200 Subject: [PATCH 002/480] IE8 does not have a setter for property "enctype" --- src/browser/ui/dom/HTMLDOMPropertyConfig.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/browser/ui/dom/HTMLDOMPropertyConfig.js b/src/browser/ui/dom/HTMLDOMPropertyConfig.js index 56e334bd0adb..6fdfc92ebbbe 100644 --- a/src/browser/ui/dom/HTMLDOMPropertyConfig.js +++ b/src/browser/ui/dom/HTMLDOMPropertyConfig.js @@ -176,7 +176,9 @@ var HTMLDOMPropertyConfig = { autoCorrect: 'autocorrect', autoFocus: 'autofocus', autoPlay: 'autoplay', - encType: 'enctype', + // `encoding` is equivalent to `enctype`, IE8 lacks an `enctype` setter. + // http://www.w3.org/TR/html5/forms.html#dom-fs-encoding + encType: 'encoding', hrefLang: 'hreflang', radioGroup: 'radiogroup', spellCheck: 'spellcheck', From 6294d7aacc85b4ddc8222e6b94855423a694c9a6 Mon Sep 17 00:00:00 2001 From: Cotton Hou Date: Fri, 5 Sep 2014 07:15:39 +0800 Subject: [PATCH 003/480] Reduce unnecessary warning while including JSX transformer in browser --- vendor/browser-transforms.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vendor/browser-transforms.js b/vendor/browser-transforms.js index c3783d085f87..3506a76934f0 100644 --- a/vendor/browser-transforms.js +++ b/vendor/browser-transforms.js @@ -312,6 +312,10 @@ function runScripts() { } } + if (jsxScripts.length < 1) { + return; + } + console.warn( 'You are using the in-browser JSX transformer. Be sure to precompile ' + 'your JSX for production - ' + From 802ad0bc00f60062a06c8e5a2f9cd3c5269161f3 Mon Sep 17 00:00:00 2001 From: Andreas Svensson Date: Wed, 17 Sep 2014 14:40:37 +0200 Subject: [PATCH 004/480] Remove non-attribute scrollLeft and scrollTop from HTMLDOMPropertyConfig --- src/browser/ui/dom/HTMLDOMPropertyConfig.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/browser/ui/dom/HTMLDOMPropertyConfig.js b/src/browser/ui/dom/HTMLDOMPropertyConfig.js index 52fbf32ecef4..fadea2ae090a 100644 --- a/src/browser/ui/dom/HTMLDOMPropertyConfig.js +++ b/src/browser/ui/dom/HTMLDOMPropertyConfig.js @@ -132,9 +132,7 @@ var HTMLDOMPropertyConfig = { rowSpan: null, sandbox: null, scope: null, - scrollLeft: MUST_USE_PROPERTY, scrolling: null, - scrollTop: MUST_USE_PROPERTY, seamless: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, selected: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, shape: null, From 94eac0b8facf04b8bbd145bc6c3cfadde7f5a057 Mon Sep 17 00:00:00 2001 From: Greg Hurrell Date: Thu, 18 Sep 2014 09:47:23 -0700 Subject: [PATCH 005/480] Fix a comment typo --- src/utils/adler32.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/adler32.js b/src/utils/adler32.js index 59f9f21d38f3..53ae7a7dfcd4 100644 --- a/src/utils/adler32.js +++ b/src/utils/adler32.js @@ -24,7 +24,7 @@ var MOD = 65521; // This is a clean-room implementation of adler32 designed for detecting // if markup is not what we expect it to be. It does not need to be -// cryptographically strong, only reasonable good at detecting if markup +// cryptographically strong, only reasonably good at detecting if markup // generated on the server is different than that on the client. function adler32(data) { var a = 1; From cf512bf60db42f4cfe023908912f83fb452c9197 Mon Sep 17 00:00:00 2001 From: Glen Mailer Date: Thu, 18 Sep 2014 22:48:35 +0100 Subject: [PATCH 006/480] [docs] Clarify wording on sub-tree reconciliation The previous wording could be interpreted to mean sub-trees moving from within one sibling to within another, rather than the shuffling of siblings on a single level as intended --- docs/docs/ref-08-reconciliation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/ref-08-reconciliation.md b/docs/docs/ref-08-reconciliation.md index 7332103dfba6..60f669caeab4 100644 --- a/docs/docs/ref-08-reconciliation.md +++ b/docs/docs/ref-08-reconciliation.md @@ -122,7 +122,7 @@ In practice, finding a key is not really hard. Most of the time, the element you It is important to remember that the reconciliation algorithm is an implementation detail. React could re-render the whole app on every action, the end-result would be the same. We are regularly refining the heuristics in order to make common use cases faster. -In the current implementation, you can express the fact that a sub-tree has been moved between siblings, but you cannot tell that it has moved somewhere else. The algorithm will re-render that full sub-tree. +In the current implementation, you can express the fact that a sub-tree has been moved amongst its siblings, but you cannot tell that it has moved somewhere else. The algorithm will re-render that full sub-tree. Because we rely on two heuristics, if the assumptions behind them are not met, performance will suffer. From 8882f19187df93551cf98a3c516754e3feb44894 Mon Sep 17 00:00:00 2001 From: Jacob Greenleaf Date: Thu, 18 Sep 2014 18:30:57 -0700 Subject: [PATCH 007/480] Fix typo in documentation in Flux Todo List --- docs/docs/flux-todo-list.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/flux-todo-list.md b/docs/docs/flux-todo-list.md index 0bdf3b7e7027..2f3e49531448 100644 --- a/docs/docs/flux-todo-list.md +++ b/docs/docs/flux-todo-list.md @@ -349,6 +349,7 @@ At a high level, the React component hierarchy of the app looks like this: + ``` From d06018cbacfe17876dea99e94bac770341495799 Mon Sep 17 00:00:00 2001 From: Oleg Date: Thu, 18 Sep 2014 21:34:47 -0700 Subject: [PATCH 008/480] Improved readability by removing semicolon The first sentence had an unnecessary semicolon which made the whole thing difficult to read. The new syntax is not only easier to read but also more exciting. --- starter/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/starter/README.md b/starter/README.md index 0c2734f66644..929eb4e10f13 100644 --- a/starter/README.md +++ b/starter/README.md @@ -1,6 +1,6 @@ # Welcome to React! -You've just downloaded the React starter kit; congratulations! +You've just downloaded the React starter kit...Congratulations! To begin, check out the `examples/` directory for a bunch of examples, or check out [Getting Started](http://facebook.github.io/react/docs/getting-started.html) for more information. @@ -8,4 +8,4 @@ In some browsers our examples won't work from the local file system; run `python Want to start your own app? Just copy `examples/basic-jsx-external` and start hacking! Remember: before launching you'll want to precompile your JSX code as we do in `examples/basic-jsx-precompiled`; this requires doing `npm install -g react-tools` and then running our `jsx` tool. See [Getting Started](http://facebook.github.io/react/docs/getting-started.html) for more information. -Happy hacking! +Happy Hacking! From 486c69b6de123312d8d67ac6251d3942d4d2f29e Mon Sep 17 00:00:00 2001 From: Pablo Lacerda de Miranda Date: Fri, 19 Sep 2014 16:03:41 -0700 Subject: [PATCH 009/480] extracts getMeasurementsSummaryMap from ReactDefaultPerf.printWasted --- src/test/ReactDefaultPerf.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/test/ReactDefaultPerf.js b/src/test/ReactDefaultPerf.js index e0a293c9cbfa..e866075f0d12 100644 --- a/src/test/ReactDefaultPerf.js +++ b/src/test/ReactDefaultPerf.js @@ -90,19 +90,23 @@ var ReactDefaultPerf = { ); }, - printWasted: function(measurements) { - measurements = measurements || ReactDefaultPerf._allMeasurements; + getMeasurementsSummaryMap: function(measurements){ var summary = ReactDefaultPerfAnalysis.getInclusiveSummary( measurements, true ); - console.table(summary.map(function(item) { + return summary.map(function(item) { return { 'Owner > component': item.componentName, 'Wasted time (ms)': item.time, 'Instances': item.count }; - })); + }); + }, + + printWasted: function(measurements) { + measurements = measurements || ReactDefaultPerf._allMeasurements; + console.table(ReactDefaultPerf.getMeasurementsSummaryMap(measurements)); console.log( 'Total time:', ReactDefaultPerfAnalysis.getTotalTime(measurements).toFixed(2) + ' ms' From 7597cfc5fba90b33d7191b53997cc772de31d426 Mon Sep 17 00:00:00 2001 From: Stefan Dombrowski Date: Sun, 21 Sep 2014 19:22:22 +0200 Subject: [PATCH 010/480] Add stripTypes option to npm docs --- npm-react-tools/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/npm-react-tools/README.md b/npm-react-tools/README.md index f2073866e87c..1ffd44069021 100644 --- a/npm-react-tools/README.md +++ b/npm-react-tools/README.md @@ -27,6 +27,7 @@ This package installs a `jsx` executable that can be used to transform JSX into --output-charset Charset of output (default: utf8) --harmony Turns on JS transformations such as ES6 Classes etc. --source-map-inline Embed inline sourcemap in transformed source + --strip-types Strips out type annotations ## API @@ -37,6 +38,7 @@ option | values | default `sourceMap` | `true`: append inline source map at the end of the transformed source | `false` `harmony` | `true`: enable ES6 features | `false` `filename` | the output filename for the source map | `"source.js"` +`stripTypes` | `true`: strips out type annotations | `false` ```js var reactTools = require('react-tools'); From 31090821446d0eb425bbddd7901c1040a4ceb3a1 Mon Sep 17 00:00:00 2001 From: Jesse Skinner Date: Sun, 21 Sep 2014 23:00:25 -0400 Subject: [PATCH 011/480] Fix inconsistency in mockComponent argument name The second argument of mockComponent was listed as tagName, but referred to in the description as mockTagName. I changed the first one to mockTagName to be consistent. --- docs/docs/09.4-test-utils.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/09.4-test-utils.md b/docs/docs/09.4-test-utils.md index 18c6349593b8..2eec1d23cd79 100644 --- a/docs/docs/09.4-test-utils.md +++ b/docs/docs/09.4-test-utils.md @@ -38,7 +38,7 @@ Render a component into a detached DOM node in the document. **This function req ### mockComponent ```javascript -object mockComponent(function componentClass, string? tagName) +object mockComponent(function componentClass, string? mockTagName) ``` Pass a mocked component module to this method to augment it with useful methods that allow it to be used as a dummy React component. Instead of rendering as usual, the component will become a simple `
` (or other tag if `mockTagName` is provided) containing any provided children. From 0e4e7ea7e197022f2be36053ecfafa856e3d3919 Mon Sep 17 00:00:00 2001 From: fisherwebdev Date: Fri, 19 Sep 2014 14:12:53 -0700 Subject: [PATCH 012/480] Acknowledge ProjectMoon for allowing us to use the flux name on npm --- docs/acknowledgements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/acknowledgements.md b/docs/acknowledgements.md index cf5495156028..98f7b8e0608c 100644 --- a/docs/acknowledgements.md +++ b/docs/acknowledgements.md @@ -16,4 +16,4 @@ We'd like to thank all of our contributors: {% endfor %}
-In addition, we're grateful to [Jeff Barczewski](https://github.com/jeffbski) for allowing us to use the [react](https://www.npmjs.org/package/react) package name on npm and to [Christopher Aue](http://christopheraue.net/) for letting us use the [reactjs.com](http://reactjs.com/) domain name and the [@reactjs](https://twitter.com/reactjs) username on Twitter. +In addition, we're grateful to [Jeff Barczewski](https://github.com/jeffbski) for allowing us to use the [react](https://www.npmjs.org/package/react) package name on npm and to [Christopher Aue](http://christopheraue.net/) for letting us use the [reactjs.com](http://reactjs.com/) domain name and the [@reactjs](https://twitter.com/reactjs) username on Twitter. We'd also like to thank [ProjectMoon](https://github.com/ProjectMoon) for letting us use the [flux](https://www.npmjs.org/package/flux) package name on npm. From 0ae09f4c70bd83483b242f3712a206d34da45bbc Mon Sep 17 00:00:00 2001 From: XuefengWu Date: Mon, 22 Sep 2014 20:10:34 +0800 Subject: [PATCH 013/480] add tip for the important jsx convention I missed the convention and wast hours to figure out what's wrong. Add this tip in the document for who would miss the importance comment. --- docs/docs/getting-started.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/getting-started.md b/docs/docs/getting-started.md index 36c3a59be0d7..049ece11530c 100644 --- a/docs/docs/getting-started.md +++ b/docs/docs/getting-started.md @@ -57,6 +57,8 @@ React.renderComponent( document.getElementById('example') ); ``` +> ```/** @jsx React.DOM */``` is must, or jsx would not convert. + Then reference it from `helloworld.html`: ```html{10} From 14ba6ee78807b1a64d09b86a39e0125ebbf4f7eb Mon Sep 17 00:00:00 2001 From: Andreas Svensson Date: Sun, 25 May 2014 11:19:03 +0200 Subject: [PATCH 014/480] Un-mixin ReactBrowserComponentMixin from ReactTextComponent --- src/browser/ReactTextComponent.js | 1 - .../__tests__/ReactMultiChildText-test.js | 24 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/browser/ReactTextComponent.js b/src/browser/ReactTextComponent.js index e04fca6d26fa..ce4222c51fc8 100644 --- a/src/browser/ReactTextComponent.js +++ b/src/browser/ReactTextComponent.js @@ -47,7 +47,6 @@ var ReactTextComponent = function(props) { }; mixInto(ReactTextComponent, ReactComponent.Mixin); -mixInto(ReactTextComponent, ReactBrowserComponentMixin); mixInto(ReactTextComponent, { /** diff --git a/src/core/__tests__/ReactMultiChildText-test.js b/src/core/__tests__/ReactMultiChildText-test.js index d77c697409c2..01fa1d99e26e 100644 --- a/src/core/__tests__/ReactMultiChildText-test.js +++ b/src/core/__tests__/ReactMultiChildText-test.js @@ -58,8 +58,9 @@ var updateChildren = function(d, children) { }; var expectChildren = function(d, children) { + var textNode; if (typeof children === 'string') { - var textNode = d.getDOMNode().firstChild; + textNode = d.getDOMNode().firstChild; if (children === '') { expect(textNode != null).toBe(false); @@ -75,13 +76,20 @@ var expectChildren = function(d, children) { var child = children[i]; if (typeof child === 'string') { - var textWrapperNode = - reactComponentExpect(d) - .expectRenderedChildAt(i) - .toBeTextComponent() - .instance(); - - expectChildren(textWrapperNode, child); + reactComponentExpect(d) + .expectRenderedChildAt(i) + .toBeTextComponent() + .instance(); + + textNode = d.getDOMNode().childNodes[i].firstChild; + + if (child === '') { + expect(textNode != null).toBe(false); + } else { + expect(textNode != null).toBe(true); + expect(textNode.nodeType).toBe(3); + expect(textNode.data).toBe('' + child); + } } else { var elementDOMNode = reactComponentExpect(d) From 8cd460ce244cbeb707e02382f90fe5c114a96d46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Mon, 22 Sep 2014 14:29:39 -0700 Subject: [PATCH 015/480] Move examples from the website to the wiki. --- docs/docs/examples.md | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/docs/docs/examples.md b/docs/docs/examples.md index 2ab644ee29df..2143742d7a89 100644 --- a/docs/docs/examples.md +++ b/docs/docs/examples.md @@ -5,25 +5,4 @@ permalink: examples.html prev: complementary-tools.html --- -### Production Apps - -* **[Instagram.com](http://instagram.com/)** is 100% built on React, both public site and internal tools. -* **[Facebook.com](http://www.facebook.com/)**'s commenting interface, business management tools, [Lookback video editor](http://facebook.com/lookback/edit), page insights, and most, if not all, new JS development. -* **[Khan Academy](http://khanacademy.org/)** uses React for most new JS development. -* **[Sberbank](http://sberbank.ru/moscow/ru/person/)**, Russia's number one bank, is built with React. -* **[The New York Times's 2014 Red Carpet Project](http://www.nytimes.com/interactive/2014/02/02/fashion/red-carpet-project.html?_r=0)** is built with React. -* **[The Scribbler](http://scribbler.co)**, is 100% built on React, both on the server and client side. - -### Sample Code - -* **[React starter kit](/react/downloads.html)** Includes several examples which you can [view online in our GitHub repository](https://github.com/facebook/react/tree/master/examples/). -* **[React one-hour email](https://github.com/petehunt/react-one-hour-email/commits/master)** Goes step-by-step from a static HTML mock to an interactive email reader, written in just one hour! -* **[React server rendering example](https://github.com/mhart/react-server-example)** Demonstrates how to use React's server rendering capabilities. - -### Open-Source Demos - -* **[TodoMVC](https://github.com/tastejs/todomvc/tree/gh-pages/architecture-examples/react/js)** -* **[Khan Academy question editor](https://github.com/khan/perseus)** (Browse their GitHub account for many more production apps!) -* **[github-issue-viewer](https://github.com/jaredly/github-issues-viewer)** -* **[hn-react](https://github.com/prabirshrestha/hn-react)** Dead-simple Hacker News client. -* **[2048-react](https://github.com/IvanVergiliev/2048-react)** A clone of the 2048 game. +This page has moved to the [GitHub wiki](https://github.com/facebook/react/wiki/Examples). From eafe786aeff8bddca71ce09c3712588ca69fb801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Thu, 11 Sep 2014 10:31:29 -0700 Subject: [PATCH 016/480] Reword Component API intro Fixes #2179 --- docs/docs/ref-02-component-api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/ref-02-component-api.md b/docs/docs/ref-02-component-api.md index 41cb101b246f..39ed1f834e91 100644 --- a/docs/docs/ref-02-component-api.md +++ b/docs/docs/ref-02-component-api.md @@ -8,7 +8,7 @@ next: component-specs.html ## ReactComponent -Component classes created by `React.createClass()` return instances of `ReactComponent` when called. Most of the time when you're using React you're either creating or consuming these component objects. +Instances of a React Component are created internally in React when rendering. These instances are reused in subsequent renders, and can be accessed in your component methods as `this`. The only way to get a handle to a React Component instance outside of React is by storing the return value of `React.renderComponent`. Inside other Components, you may use [refs](/react/docs/more-about-refs.html) to achieve the same result. ### setState From e7299f60393f95b346285181c6ca8e09d8edea1b Mon Sep 17 00:00:00 2001 From: Isaac Salier-Hellendag Date: Mon, 22 Sep 2014 15:01:59 -0700 Subject: [PATCH 017/480] Prefer window.getSelection for IE IE9+ supports `window.getSelection()` but `SelectEventPlugin` gives precedence to `document.selection` instead. `document.selection` is still available in later versions of IE, but the modern Selection object is preferable. Swap the two. --- src/browser/eventPlugins/SelectEventPlugin.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/browser/eventPlugins/SelectEventPlugin.js b/src/browser/eventPlugins/SelectEventPlugin.js index 542dbe5b3927..3cfcc020bac8 100644 --- a/src/browser/eventPlugins/SelectEventPlugin.js +++ b/src/browser/eventPlugins/SelectEventPlugin.js @@ -69,6 +69,14 @@ function getSelection(node) { start: node.selectionStart, end: node.selectionEnd }; + } else if (window.getSelection) { + var selection = window.getSelection(); + return { + anchorNode: selection.anchorNode, + anchorOffset: selection.anchorOffset, + focusNode: selection.focusNode, + focusOffset: selection.focusOffset + }; } else if (document.selection) { var range = document.selection.createRange(); return { @@ -77,14 +85,6 @@ function getSelection(node) { top: range.boundingTop, left: range.boundingLeft }; - } else { - var selection = window.getSelection(); - return { - anchorNode: selection.anchorNode, - anchorOffset: selection.anchorOffset, - focusNode: selection.focusNode, - focusOffset: selection.focusOffset - }; } } From f04d6488889b0379173d6dde0d7306f146f68342 Mon Sep 17 00:00:00 2001 From: XuefengWu Date: Tue, 23 Sep 2014 15:22:11 +0800 Subject: [PATCH 018/480] Update getting-started.md merge the warn and explain for the @jsx --- docs/docs/getting-started.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/docs/getting-started.md b/docs/docs/getting-started.md index 049ece11530c..b6574b5a296d 100644 --- a/docs/docs/getting-started.md +++ b/docs/docs/getting-started.md @@ -57,7 +57,11 @@ React.renderComponent( document.getElementById('example') ); ``` -> ```/** @jsx React.DOM */``` is must, or jsx would not convert. + +> Note: +> +> ```/** @jsx React.DOM */``` is *must*, which is jsx convention. The comment parser is very strict right now; in order for it to pick up the `@jsx` modifier, two conditions are required. The `@jsx` comment block must be the first comment on the file. The comment must start with `/**` (`/*` and `//` will not work). If the parser can't find the `@jsx` comment, it will output the file without transforming it. + Then reference it from `helloworld.html`: @@ -90,9 +94,6 @@ React.renderComponent( ); ``` -> Note: -> -> The comment parser is very strict right now; in order for it to pick up the `@jsx` modifier, two conditions are required. The `@jsx` comment block must be the first comment on the file. The comment must start with `/**` (`/*` and `//` will not work). If the parser can't find the `@jsx` comment, it will output the file without transforming it. Update your HTML file as below: From 86287bffd4ed4e29bda8df9c4a6acb85c574efaf Mon Sep 17 00:00:00 2001 From: Oleg Date: Tue, 23 Sep 2014 17:01:23 -0700 Subject: [PATCH 019/480] Add space after ellipses --- starter/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/starter/README.md b/starter/README.md index 929eb4e10f13..773bc17b716f 100644 --- a/starter/README.md +++ b/starter/README.md @@ -1,6 +1,6 @@ # Welcome to React! -You've just downloaded the React starter kit...Congratulations! +You've just downloaded the React starter kit... Congratulations! To begin, check out the `examples/` directory for a bunch of examples, or check out [Getting Started](http://facebook.github.io/react/docs/getting-started.html) for more information. From b9f32a829569c7e5bac9c12268ff8be16051899a Mon Sep 17 00:00:00 2001 From: XuefengWu Date: Wed, 24 Sep 2014 08:26:10 +0800 Subject: [PATCH 020/480] Update getting-started.md fix grammar --- docs/docs/getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/getting-started.md b/docs/docs/getting-started.md index b6574b5a296d..01a4c301325f 100644 --- a/docs/docs/getting-started.md +++ b/docs/docs/getting-started.md @@ -60,7 +60,7 @@ React.renderComponent( > Note: > -> ```/** @jsx React.DOM */``` is *must*, which is jsx convention. The comment parser is very strict right now; in order for it to pick up the `@jsx` modifier, two conditions are required. The `@jsx` comment block must be the first comment on the file. The comment must start with `/**` (`/*` and `//` will not work). If the parser can't find the `@jsx` comment, it will output the file without transforming it. +> ```/** @jsx React.DOM */``` is *required*. The comment parser is very strict right now; in order for it to pick up the `@jsx` modifier, two conditions are required. The `@jsx` comment block must be the first comment on the file. The comment must start with `/**` (`/*` and `//` will not work). If the parser can't find the `@jsx` comment, it will output the file without transforming it. Then reference it from `helloworld.html`: From 792b84c94be293240feac87db47fcc7fd17097e3 Mon Sep 17 00:00:00 2001 From: Pablo Lacerda de Miranda Date: Tue, 23 Sep 2014 18:50:18 -0700 Subject: [PATCH 021/480] fixes ReactDefaultPerf.getMeasurementsSummaryMap format style --- src/test/ReactDefaultPerf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ReactDefaultPerf.js b/src/test/ReactDefaultPerf.js index e866075f0d12..e3287f42a51a 100644 --- a/src/test/ReactDefaultPerf.js +++ b/src/test/ReactDefaultPerf.js @@ -90,7 +90,7 @@ var ReactDefaultPerf = { ); }, - getMeasurementsSummaryMap: function(measurements){ + getMeasurementsSummaryMap: function(measurements) { var summary = ReactDefaultPerfAnalysis.getInclusiveSummary( measurements, true From 9952a54026cbc0f60879d3f13e80141b65c04328 Mon Sep 17 00:00:00 2001 From: fisherwebdev Date: Wed, 24 Sep 2014 12:09:50 -0700 Subject: [PATCH 022/480] [blog] testing flux applications --- .../2014-09-24-testing-flux-applications.md | 323 ++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 docs/_posts/2014-09-24-testing-flux-applications.md diff --git a/docs/_posts/2014-09-24-testing-flux-applications.md b/docs/_posts/2014-09-24-testing-flux-applications.md new file mode 100644 index 000000000000..34fb5b59814a --- /dev/null +++ b/docs/_posts/2014-09-24-testing-flux-applications.md @@ -0,0 +1,323 @@ +--- +title: "Testing Flux Applications" +author: Bill Fisher +--- + +[Flux](http://facebook.github.io/flux/) is the application architecture that Facebook uses to build web applications with [React](http://facebook.github.io/react/). It's based on a unidirectional data flow. In previous blog posts and documentation articles, we've shown the [basic structure and data flow](http://facebook.github.io/flux/docs/overview.html), more closely examined the [dispatcher and action creators](http://facebook.github.io/react/blog/2014/07/30/flux-actions-and-the-dispatcher.html), and shown how to put it all together with a [tutorial](http://facebook.github.io/flux/docs/todo-list.html). Now let's look at how to do formal unit testing of Flux applications with [Jest](http://facebook.github.io/jest/), Facebook's auto-mocking testing framework. + + +Testing with Jest +----------------- + +For a unit test to operate on a truly isolated _unit_ of the application, we need to mock every module except the one we are testing. Jest makes the mocking of other parts of a Flux application trivial. To illustrate testing with Jest, we'll return to our [example TodoMVC application](https://github.com/facebook/flux/tree/master/examples/flux-todomvc). + +The first steps toward working with Jest are as follows: + +1. Get the module depencies for the application installed by running `npm install`. +2. Create a directory `__tests__/` with a test file, in this case TodoStore-test.js +3. Run `npm install jest-cli —save-dev` +4. Add the following to your package.json + +```javascript +{ + ... + "scripts": { + "test": "jest" + } + ... +} +``` + +Now you're ready to run your tests from the command line with `npm test`. + +By default, all modules are mocked, so the only boilerplate we need in TodoStore-test.js is a declarative call to Jest's `dontMock()` method. + +```javascript +jest.dontMock('TodoStore'); +``` + +This tells Jest to let TodoStore be a real object with real, live methods. Jest will mock all other objects involved with the test. + + +Testing Stores +-------------- + +At Facebook, Flux stores often receive a great deal of formal unit test coverage, as this is where the application state and logic lives. Stores are arguably the most important place in a Flux application to provide coverage, but at first glance, it's not entirely obvious how to test them. + +By design, stores can't be modified from the outside. They have no setters. The only way new data can enter a store is through the callback it registers with the dispatcher. + +We therefore need to simulate the Flux data flow with this _one weird trick_. + +```javascript +var mockRegister = MyDispatcher.register; +var mockRegisterInfo = mockRegister.mock; +var callsToRegister = mockRegisterInfo.calls; +var firstCall = callsToRegister[0]; +var firstArgument = firstCall[0]; +var callback = firstArgument; +``` + +We now have the store's registered callback, the sole mechanism by which data can enter the store. + +For folks new to Jest, or mocks in general, it might not be entirely obvious what is happening in that code block, so let's look at each part of it a bit more closely. We start out by looking at the `register()` method of our application's dispatcher — the method that the store uses to register its callback with the dispatcher. The dispatcher has been thoroughly mocked automatically by Jest, so we can get a reference to the mocked version of the `register()` method just as we would normally refer to that method in our production code. But we can get additional information about that method with the `mock` _property_ of that method. We don't often think of methods having properties, but in Jest, this idea is vital. Every method of a mocked object has this property, and it allows us to examine how the method is being called during the test. A chronologically ordered list of calls to `register()` is available with the `calls` property of `mock`, and each of these calls has a list of the arguments that were used in each method call. + +So in this code, we are really saying, "Give me a reference to the first argument of the first call to MyDispatcher's `register()` method." That first argument is the store's callback, so now we have all we need to start testing. But first, we can save ourselves some semicolons and roll all of this into a single line: + +```javascript +callback = MyDispatcher.register.mock.calls[0][0]; +``` + +We can invoke that callback whenever we like, independent of our application's dispatcher or action creators. We will, in fact, fake the behavior of the dispatcher and action creators by invoking the callback with an action that we'll create directly in our test. + +```javascript +var payload = { + source: 'VIEW_ACTION', + action: { + actionType: TodoConstants.TODO_CREATE, + text: 'foo' + } +}; +callback(payload); +var all = TodoStore.getAll(); +var keys = Object.keys(all); +expect(all[keys[0]].text).toEqual('foo'); +``` + +Puting it All Together +---------------------- + +The example Flux TodoMVC application has been updated with an example test for the TodoStore, but lets's look at an abbreviated version of the entire test. The most important things to notice in this test are how we keep a reference to the store's registered callback in the closure of the test, and how we recreate the store before every test so that we clear the state of the store entirely. + +```javascript +jest.dontMock('../TodoStore'); +jest.dontMock('react/lib/merge'); + +describe('TodoStore', function() { + + var TodoConstants = require('../../constants/TodoConstants'); + + // mock actions inside dispatch payloads + var actionTodoCreate = { + source: 'VIEW_ACTION', + action: { + actionType: TodoConstants.TODO_CREATE, + text: 'foo' + } + }; + var actionTodoDestroy = { + source: 'VIEW_ACTION', + action: { + actionType: TodoConstants.TODO_DESTROY, + id: 'replace me in test' + } + }; + + var AppDispatcher; + var TodoStore; + var callback; + + beforeEach(function() { + AppDispatcher = require('../../dispatcher/AppDispatcher'); + TodoStore = require('../TodoStore'); + callback = AppDispatcher.register.mock.calls[0][0]; + }); + + it('registers a callback with the dispatcher', function() { + expect(AppDispatcher.register.mock.calls.length).toBe(1); + }); + + it('initializes with no to-do items', function() { + var all = TodoStore.getAll(); + expect(all).toEqual({}); + }); + + it('creates a to-do item', function() { + callback(actionTodoCreate); + var all = TodoStore.getAll(); + var keys = Object.keys(all); + expect(keys.length).toBe(1); + expect(all[keys[0]].text).toEqual('foo'); + }); + + it('destroys a to-do item', function() { + callback(actionTodoCreate); + var all = TodoStore.getAll(); + var keys = Object.keys(all); + expect(keys.length).toBe(1); + actionTodoDestroy.action.id = keys[0]; + callback(actionTodoDestroy); + expect(all[keys[0]]).toBeUndefined(); + }); + +}); +``` + +You can take a look at all this code in the [TodoStore's tests on GitHub](https://github.com/facebook/flux/tree/master/examples/flux-todomvc/js/stores/__tests__/TodoStore-test.js) as well. + + +Mocking Data Derived from Other Stores +-------------------------------------- + +Sometimes our stores rely on data from other stores. Because all of our modules are mocked, we'll need to simulate the data that comes from the other store. We can do this by retrieving the mock function and adding a custom return value to it. + +```javascript +var MyOtherStore = require('../MyOtherStore'); +MyOtherStore.getState.mockReturnValue({ + '123': { + id: '123', + text: 'foo' + }, + '456': { + id: '456', + text: 'bar' + } +}); +``` + +Now we have a collection of objects that will come back from MyOtherStore whenever we call MyOtherStore.getState() in our tests. Any application state can be simulated with a combination of these custom return values and the previously shown technique of working with the store's registered callback. + +A brief example of this technique is up on GitHub within the Flux Chat example's [UnreadThreadStore-test.js](https://github.com/facebook/flux/tree/master/examples/flux-chat/js/stores/__tests__/UnreadThreadStore-test.js). + +For more information about the `mock` property of mocked methods or Jest's ability to provide custom mock values, see Jest's documentation on [mock functions](http://facebook.github.io/jest/docs/mock-functions.html). + + +Moving Logic from React to Stores +--------------------------------- + +What often starts as a little piece of seemingly benign logic in our React components often presents a problem while creating unit tests. We want to be able to write tests that read like a specification for our application's behavior, and when application logic slips into our view layer, this becomes more difficult. + +For example, when a user has marked each of their to-do items as complete, the TodoMVC specification dictates that we should also change the status of the "Mark all as complete" checkbox automatically. To create that logic, we might be tempted to write code like this in our MainSection's `render()` method: + +```javascript +var allTodos = this.props.allTodos; +var allChecked = true; +for (var id in allTodos) { + if (!allTodos[id].complete) { + allChecked = false; + break; + } +} +... + +return ( +
+ + ... +
+); +``` + +While this seems like an easy, normal thing to do, this is an example of application logic slipping into the views, and it can't be described in our spec-style TodoStore test. Let's take that logic and move it to the store. First, we'll create a public method on the store that will encapsulate that logic: + +```javascript +areAllComplete: function() { + for (var id in _todos) { + if (!_todos[id].complete) { + return false; + } + } + return true; +}, +``` + +Now we have the application logic where it belongs, and we can write the following test: + +```javascript +it('determines whether all to-do items are complete', function() { + var i = 0; + for (; i < 3; i++) { + callback(mockTodoCreate); + } + expect(TodoStore.areAllComplete()).toBe(false); + + var all = TodoStore.getAll(); + for (key in all) { + callback({ + source: 'VIEW_ACTION', + action: { + actionType: TodoConstants.TODO_COMPLETE, + id: key + } + }); + } + expect(TodoStore.areAllComplete()).toBe(true); + + callback({ + source: 'VIEW_ACTION', + action: { + actionType: TodoConstants.TODO_UNDO_COMPLETE, + id: key + } + }); + expect(TodoStore.areAllComplete()).toBe(false); +}); +``` + +Finally, we revise our view layer. We'll call for that data in the controller-view, TodoApp.js, and pass it down to the MainSection component. + +```javascript +function getTodoState() { + return { + allTodos: TodoStore.getAll(), + areAllComplete: TodoStore.areAllComplete() + }; +} + +var TodoApp = React.createClass({ +... + + /** + * @return {object} + */ + render: function() { + return ( + ... + + ... + ); + }, + + /** + * Event handler for 'change' events coming from the TodoStore + */ + _onChange: function() { + this.setState(getTodoState()); + } + +}); +``` + +And then we'll utilize that property for the rendering of the checkbox. + +```javascript +render: function() { + ... + + return ( +
+ + ... +
+ ); +}, +``` + +To learn how to test React components themselves, check out the [Jest tutorial for React](http://facebook.github.io/jest/docs/tutorial-react.html) and the [ReactTestUtils documenation](http://facebook.github.io/react/docs/test-utils.html). + + +Further Reading +--------------- + +- [Mocks Aren't Stubs](http://martinfowler.com/articles/mocksArentStubs.html) by Martin Fowler +- [Jest API Reference](http://facebook.github.io/jest/docs/api.html) From 5493b63b44e82ba6976d84aa4e189ef327afbfd1 Mon Sep 17 00:00:00 2001 From: Oleksii Markhovskyi Date: Thu, 25 Sep 2014 09:54:35 +0200 Subject: [PATCH 023/480] fix typos --- docs/_posts/2014-09-24-testing-flux-applications.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/_posts/2014-09-24-testing-flux-applications.md b/docs/_posts/2014-09-24-testing-flux-applications.md index 34fb5b59814a..22637b36fab9 100644 --- a/docs/_posts/2014-09-24-testing-flux-applications.md +++ b/docs/_posts/2014-09-24-testing-flux-applications.md @@ -13,7 +13,7 @@ For a unit test to operate on a truly isolated _unit_ of the application, we nee The first steps toward working with Jest are as follows: -1. Get the module depencies for the application installed by running `npm install`. +1. Get the module dependencies for the application installed by running `npm install`. 2. Create a directory `__tests__/` with a test file, in this case TodoStore-test.js 3. Run `npm install jest-cli —save-dev` 4. Add the following to your package.json @@ -86,7 +86,7 @@ expect(all[keys[0]].text).toEqual('foo'); Puting it All Together ---------------------- -The example Flux TodoMVC application has been updated with an example test for the TodoStore, but lets's look at an abbreviated version of the entire test. The most important things to notice in this test are how we keep a reference to the store's registered callback in the closure of the test, and how we recreate the store before every test so that we clear the state of the store entirely. +The example Flux TodoMVC application has been updated with an example test for the TodoStore, but let's look at an abbreviated version of the entire test. The most important things to notice in this test are how we keep a reference to the store's registered callback in the closure of the test, and how we recreate the store before every test so that we clear the state of the store entirely. ```javascript jest.dontMock('../TodoStore'); @@ -313,7 +313,7 @@ render: function() { }, ``` -To learn how to test React components themselves, check out the [Jest tutorial for React](http://facebook.github.io/jest/docs/tutorial-react.html) and the [ReactTestUtils documenation](http://facebook.github.io/react/docs/test-utils.html). +To learn how to test React components themselves, check out the [Jest tutorial for React](http://facebook.github.io/jest/docs/tutorial-react.html) and the [ReactTestUtils documentation](http://facebook.github.io/react/docs/test-utils.html). Further Reading From cac45631c35217e930c38750a0fa1dd20858543c Mon Sep 17 00:00:00 2001 From: Andreas Svensson Date: Thu, 25 Sep 2014 10:46:29 +0200 Subject: [PATCH 024/480] Remove superfluous classID from DOMAttributeNames --- src/browser/ui/dom/HTMLDOMPropertyConfig.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/browser/ui/dom/HTMLDOMPropertyConfig.js b/src/browser/ui/dom/HTMLDOMPropertyConfig.js index 52fbf32ecef4..76886c755975 100644 --- a/src/browser/ui/dom/HTMLDOMPropertyConfig.js +++ b/src/browser/ui/dom/HTMLDOMPropertyConfig.js @@ -168,7 +168,6 @@ var HTMLDOMPropertyConfig = { property: null // Supports OG in meta tags }, DOMAttributeNames: { - classID: 'classid', className: 'class', htmlFor: 'for', httpEquiv: 'http-equiv' From 1b6a3d521508d1480538505e624df40668935754 Mon Sep 17 00:00:00 2001 From: Christian Alfoni Date: Thu, 25 Sep 2014 11:54:52 +0200 Subject: [PATCH 025/480] Update flux-todo-list.md You have to instantiate a Dispatcher to use it, not just grab the prototype or it will fail when trying to grab instance properties like: this.$Dispatcher._callbacks. --- docs/docs/flux-todo-list.md | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/docs/docs/flux-todo-list.md b/docs/docs/flux-todo-list.md index 2f3e49531448..463c56cdd6a1 100644 --- a/docs/docs/flux-todo-list.md +++ b/docs/docs/flux-todo-list.md @@ -147,23 +147,19 @@ Now we are all set to create a dispatcher that is more specific to our app, whic ```javascript var Dispatcher = require('./Dispatcher'); -var merge = require('react/lib/merge'); - -var AppDispatcher = merge(Dispatcher.prototype, { +var AppDispatcher = new Dispatcher(); - /** +/** * A bridge function between the views and the dispatcher, marking the action * as a view action. Another variant here could be handleServerAction. * @param {object} action The data coming from the view. */ - handleViewAction: function(action) { - this.dispatch({ - source: 'VIEW_ACTION', - action: action - }); - } - -}); +AppDispatcher.handleViewAction = function(action) { + this.dispatch({ + source: 'VIEW_ACTION', + action: action + }); +}; module.exports = AppDispatcher; ``` From 6c19040d24223a2c98953ad85d318657504ce874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20O=E2=80=99Shannessy?= Date: Wed, 24 Sep 2014 16:49:27 -0700 Subject: [PATCH 026/480] Point to Flux site for Flux docs This doesn't actually remove the pages, just the main content. Sidebar items now link offsite. The pages doesn't automatically redirect, but we could do that if we really wanted. Fixes #2229 --- docs/_data/nav_docs.yml | 2 + docs/_includes/nav_docs.html | 8 +- docs/_plugins/sidebar_item.rb | 14 + docs/_posts/2014-05-06-flux.md | 2 +- docs/docs/flux-overview.md | 92 +---- docs/docs/flux-todo-list.md | 667 +-------------------------------- 6 files changed, 21 insertions(+), 764 deletions(-) create mode 100644 docs/_plugins/sidebar_item.rb diff --git a/docs/_data/nav_docs.yml b/docs/_data/nav_docs.yml index 7eb71491c8d4..e7c71b68d5ab 100644 --- a/docs/_data/nav_docs.yml +++ b/docs/_data/nav_docs.yml @@ -81,5 +81,7 @@ items: - id: flux-overview title: Flux Overview + href: http://facebook.github.io/flux/docs/overview.html - id: flux-todo-list title: Flux TodoMVC Tutorial + href: http://facebook.github.io/flux/docs/todo-list.html diff --git a/docs/_includes/nav_docs.html b/docs/_includes/nav_docs.html index a66b822bcea7..1f33076ee585 100644 --- a/docs/_includes/nav_docs.html +++ b/docs/_includes/nav_docs.html @@ -6,16 +6,12 @@

{{ section.title }}