├── .babelrc.js ├── .circleci └── config.yml ├── .eslintignore ├── .eslintrc ├── .flowconfig ├── .gitignore ├── .prettierrc ├── .stubs ├── component.js ├── raw.js └── readme-text.js ├── CONTRIBUTING.md ├── CREDITS.md ├── LICENSE ├── README.md ├── TODO.md ├── WHATSTHIS.md ├── flow-typed └── npm │ ├── express_v4.16.x.js │ └── jest_v23.x.x.js ├── package.json ├── screenshot2.png ├── tests ├── jest-enzyme │ ├── README.md │ ├── click-callback │ │ ├── README.md │ │ └── test.js │ ├── enzyme.setup.js │ ├── fetch │ │ ├── README.md │ │ └── test.js │ ├── jest.config.js │ ├── local-state │ │ ├── README.md │ │ └── test.js │ ├── localstorage │ │ ├── README.md │ │ └── test.js │ ├── order.js │ ├── react-router │ │ ├── README.md │ │ └── test.js │ ├── redux │ │ ├── README.md │ │ ├── reducer.js │ │ └── test.js │ ├── render-text │ │ ├── README.md │ │ └── test.js │ ├── styled-components │ │ ├── README.md │ │ └── test.js │ └── xhr │ │ ├── README.md │ │ └── test.js ├── jest-interactor │ ├── README.md │ ├── click-callback │ │ ├── README.md │ │ └── test.js │ ├── counter-interactor.js │ ├── fetch │ │ ├── README.md │ │ └── test.js │ ├── jest.config.js │ ├── local-state │ │ ├── README.md │ │ └── test.js │ ├── localstorage │ │ ├── README.md │ │ └── test.js │ ├── order.js │ ├── react-router │ │ ├── README.md │ │ └── test.js │ ├── redux │ │ ├── README.md │ │ ├── reducer.js │ │ └── test.js │ ├── render-text │ │ ├── README.md │ │ └── test.js │ ├── styled-components │ │ ├── README.md │ │ └── test.js │ └── xhr │ │ ├── README.md │ │ └── test.js ├── jest-rtl │ ├── README.md │ ├── click-callback │ │ ├── README.md │ │ └── test.js │ ├── fetch │ │ ├── README.md │ │ └── test.js │ ├── jest.config.js │ ├── local-state │ │ ├── README.md │ │ └── test.js │ ├── localstorage │ │ ├── README.md │ │ └── test.js │ ├── order.js │ ├── react-router │ │ ├── README.md │ │ └── test.js │ ├── redux │ │ ├── README.md │ │ ├── reducer.js │ │ └── test.js │ ├── render-text │ │ ├── README.md │ │ └── test.js │ ├── rtl.setup.js │ ├── styled-components │ │ ├── README.md │ │ └── test.js │ └── xhr │ │ ├── README.md │ │ └── test.js └── shared │ ├── components │ ├── Button.js │ ├── HelloMessage.js │ ├── HelloMessageStyled.js │ ├── PersistentForm.js │ ├── ReduxCounter.js │ ├── ServerFetchCounter.js │ ├── ServerXhrCounter.js │ ├── StatefulCounter.js │ └── UserWithRouter.js │ └── theme.js ├── ui ├── components │ ├── AboutModal.js │ ├── App.fixture.js │ ├── App.js │ ├── File │ │ ├── Code │ │ │ ├── __fixtures__ │ │ │ │ └── xhr.js │ │ │ ├── index.js │ │ │ ├── shared.js │ │ │ └── style.js │ │ ├── FileActions.js │ │ ├── FileHeader.js │ │ ├── index.js │ │ └── shared.js │ ├── Footer.js │ ├── Header │ │ ├── AboutButton.js │ │ ├── Checkbox.js │ │ ├── GithubLink.js │ │ ├── SearchBox.js │ │ ├── TestKindSelect.js │ │ ├── index.js │ │ └── styles.js │ ├── Section │ │ ├── Readme.js │ │ ├── TitleLink.js │ │ ├── __fixtures__ │ │ │ └── index.js │ │ └── index.js │ ├── SectionList │ │ ├── ToggleButton.js │ │ ├── ToggleShow.js │ │ ├── fixtures.js │ │ ├── img │ │ │ └── thinkin.png │ │ └── index.js │ └── shared │ │ ├── FuzzyHighlighter.js │ │ ├── SectionLink.js │ │ ├── WindowKeyListener.js │ │ └── styles.js ├── contexts.js ├── cosmos-proxies │ ├── globalStyle.js │ └── next.js ├── cosmos.config.js ├── cosmos.proxies.js ├── global-style.js ├── global.js ├── import-files.js ├── jest.config.js ├── next.config.js ├── pages │ ├── _app.js │ ├── _document.js │ ├── about.js │ └── index.js ├── search.js ├── server │ ├── start-dev.js │ └── testFiles.js ├── shared │ ├── section.js │ └── testKinds.js ├── static │ └── favicon.ico ├── svg │ ├── chevron-left.svg │ ├── clippy.svg │ ├── info.svg │ ├── link-external.svg │ ├── link.svg │ ├── mark-github.svg │ ├── question.svg │ ├── settings.svg │ └── triangle-down.svg ├── types.js ├── webpack-loaders │ ├── import-tests-loader.js │ ├── import-tests-loader.test.js │ ├── readme-text-loader.js │ └── readme-text-loader.test.js └── webpack.extend.js └── yarn.lock /.babelrc.js: -------------------------------------------------------------------------------- 1 | const testSharedAlias = { 2 | root: ['./tests'], 3 | alias: { 4 | shared: './tests/shared' 5 | } 6 | }; 7 | 8 | module.exports = { 9 | presets: ['next/babel', '@babel/preset-flow'], 10 | plugins: [ 11 | ['babel-plugin-inline-import-data-uri', { extensions: ['.png', '.svg'] }], 12 | ['styled-components', { ssr: true, displayName: true, preprocess: false }], 13 | ['module-resolver', testSharedAlias], 14 | ['@babel/plugin-proposal-decorators', { decoratorsBeforeExport: true }] 15 | ], 16 | env: { 17 | test: { 18 | // Jest runs in Node and needs CommonJS modules. So does SSR, but Next 19 | // runs webpack on the server as well nowadays 20 | presets: [['next/babel', { 'preset-env': { modules: 'commonjs' } }]] 21 | } 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/node:8 11 | # Specify service dependencies here if necessary 12 | # CircleCI maintains a library of pre-built images 13 | # documented at https://circleci.com/docs/2.0/circleci-images/ 14 | # - image: circleci/mongo:3.4.4 15 | 16 | working_directory: ~/repo 17 | 18 | steps: 19 | - checkout 20 | 21 | # Download and cache dependencies 22 | - restore_cache: 23 | keys: 24 | - v1-dependencies-{{ checksum "package.json" }} 25 | # fallback to using the latest cache if no exact match is found 26 | - v1-dependencies- 27 | 28 | - run: yarn install 29 | 30 | - save_cache: 31 | paths: 32 | - node_modules 33 | key: v1-dependencies-{{ checksum "package.json" }} 34 | 35 | # Check code 36 | - run: yarn lint 37 | - run: yarn flow 38 | 39 | # Test code 40 | - run: yarn test:ci 41 | # The resource_class feature allows configuring CPU and RAM resources for each job. Different resource classes are available for different executors. https://circleci.com/docs/2.0/configuration-reference/#resourceclass 42 | resource_class: large 43 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | flow-typed 2 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": [ 4 | "eslint:recommended", 5 | "plugin:import/errors", 6 | "plugin:import/warnings", 7 | "plugin:flowtype/recommended" 8 | ], 9 | "plugins": ["react", "flowtype"], 10 | "env": { 11 | "es6": true, 12 | "shared-node-browser": true 13 | }, 14 | "settings": { 15 | "import/resolver": { 16 | "babel-module": {} 17 | } 18 | }, 19 | "rules": { 20 | "react/jsx-uses-react": "error", 21 | "react/jsx-uses-vars": "error" 22 | }, 23 | "overrides": [ 24 | { 25 | "files": [ 26 | "babel.config.js", 27 | "jest.config.js", 28 | "cosmos.config.js", 29 | "next.config.js", 30 | "webpack.extend.js", 31 | "ui/webpack-loaders/**/*.js", 32 | "ui/server/**/*.js" 33 | ], 34 | "env": { 35 | "node": true 36 | }, 37 | "rules": { 38 | "no-console": "off" 39 | } 40 | }, 41 | { 42 | "files": ["**/test.js", "**/*.test.js"], 43 | "env": { 44 | "jest": true 45 | } 46 | }, 47 | { 48 | "files": ["**/localstorage/test.js"], 49 | "env": { 50 | "browser": true 51 | } 52 | } 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | 5 | [libs] 6 | flow-typed 7 | 8 | [lints] 9 | 10 | [options] 11 | module.name_mapper='^!raw-loader!.+$' -> '/.stubs/raw.js' 12 | module.name_mapper='^!.+\/readme-text-loader!.+$' -> '/.stubs/readme-text.js' 13 | module.name_mapper='^.+\/README\.md$' -> '/.stubs/component.js' 14 | module.name_mapper='^.+\/SETUP\.md$' -> '/.stubs/component.js' 15 | module.name_mapper='^.+\/WHATSTHIS\.md$' -> '/.stubs/component.js' 16 | module.name_mapper='^.+\/CREDITS\.md$' -> '/.stubs/component.js' 17 | 18 | [strict] 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn-error.log 3 | .next 4 | .export 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.stubs/component.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | export default () => null; 4 | -------------------------------------------------------------------------------- /.stubs/raw.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | module.exports = 'raw file contents'; 4 | -------------------------------------------------------------------------------- /.stubs/readme-text.js: -------------------------------------------------------------------------------- 1 | /* @flow */ 2 | 3 | module.exports = { title: 'Title', body: [] }; 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing guide 2 | 3 | First make sure you understand [what these examples focus on](https://github.com/skidding/react-testing-examples/blob/master/WHATSTHIS.md#whats-the-focus). Then make the examples as **concise** as possible. Finally, try to communicate your intentions. 4 | 5 | ### How to add a test 6 | 7 | Here are the required steps for adding a _foobar_ example in the `jest-enzyme` collection. 8 | 9 | - Put test(s) in `tests/jest-enzyme/foobar/test.js` 10 | - Put description in `tests/jest-enzyme/foobar/README.md` 11 | 12 | Get inspired from existing examples. 13 | 14 | ### How to add a test collection (ie. a new toolchain) 15 | 16 | > This one's a big deal so you want to start a conversation before jumping into it. 17 | 18 | Copy one of the dirs from [tests](tests) (eg. `jest-rtl`) to get started. You don't have to mirror tests from existing collections. At least one test example is enough to create a new collection. 19 | 20 | A few more steps required before deploying a new collection: 21 | 22 | - Add a label [here](https://github.com/skidding/react-testing-examples/blob/bd01b2e8a2a5f9fd7446e781f2026e191326afcf/ui/shared/testKinds.js#L8-L9) 23 | - Add test commands [here](https://github.com/skidding/react-testing-examples/blob/master/package.json#L4-L7) 24 | -------------------------------------------------------------------------------- /CREDITS.md: -------------------------------------------------------------------------------- 1 | Tests powered by [Jest](https://jestjs.io/) [react-mock](https://github.com/skidding/react-mock) [Enzyme](https://airbnb.io/enzyme/) [react-testing-library](https://github.com/kentcdodds/react-testing-library) and [@bigtest/interactor](https://github.com/bigtestjs/interactor). Website powered by [Babel](https://babeljs.io/) [Cosmos](https://github.com/react-cosmos/react-cosmos) [MDX](https://mdxjs.com/) [Next.js](https://nextjs.org/) [Prism](https://prismjs.com/) [styled-components](https://www.styled-components.com/) [webpack](https://webpack.js.org/) and many more. 2 | 3 | Finally, [React](https://reactjs.org/) makes it all possible! 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Ovidiu Cherecheș 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Testing Examples 2 | 3 | [CircleCI](https://circleci.com/gh/skidding/react-testing-examples) 4 | 5 | Searchable library of React testing examples 6 | 7 | - **[Open the library](https://react-testing-examples.netlify.app)** 8 | - [Read about the project](https://react-testing-examples.netlify.app/about) 9 | - [Browse test files](tests) 10 | - [Read contributing guide](CONTRIBUTING.md) 11 | 12 | [Screenshot of React Testing Examples](https://react-testing-examples.netlify.app) 13 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ## Second version 2 | 3 | > Started on Oct 16, 2018 4 | 5 | - [x] Use react-mock in tests 6 | - [x] Remove hoisted vars and before/after cases 7 | - [x] Refactor code preview component 8 | - [x] Try react-testing-library 9 | - [x] Split tests between RTL and Enzyme 10 | - [x] Remove Cosmos fixture tests (superseded by react-mock) 11 | - [x] Refactor styled-components test 12 | - [x] Add URL for each test kind 13 | - [x] Add URL for each test 14 | - [x] Update project description 15 | - [x] Update README 16 | - [x] Visual facelift 17 | - [x] Header 18 | - [x] Remove file visibility toggling 19 | - [x] Tweak file actions 20 | - [x] Footer 21 | - [x] Links to tech used 22 | - [x] Update responsive breakpoints 23 | - [x] Replace file system sorting 24 | - [x] Make Next.js components load in Cosmos 25 | - [ ] Optimize search perf 26 | 27 | ## First version 28 | 29 | > Started on Apr 24, 2018 30 | 31 | - [x] Add "Click callback" tests 32 | - [x] Add "Render text" tests 33 | - [x] Add "Local state" tests 34 | - [x] Add "Redux" tests 35 | - [x] Add "React Router" tests 36 | - [x] Add "XHR" tests 37 | - [x] Add "Fetch" tests 38 | - [x] Add "LocalStorage" tests 39 | - [x] Add "styled-components" tests 40 | - [ ] Add "Context" tests 41 | - [x] Colocate components with tests 42 | - [x] Add ESLint 43 | - [x] Config CircleCI 44 | - [x] Colocate Cosmos proxies with tests 45 | - [x] Add Flow 46 | - [x] Create UI 47 | - [x] Syntax highlight (with line highlight) 48 | - [x] Sticky header 49 | - [x] Highlight and create fixtures for all tests 50 | - [x] Implement search 51 | - [x] Add toggle between 'Plain Enzyme' and 'Cosmos & Enzyme' 52 | - [x] Improve search 53 | - [x] Keyboard shortcuts 54 | - [x] No results screen 55 | - [x] Show best matches first 56 | - [x] Add links next to section titles 57 | - [x] Add file actions to copy and open code in GH 58 | - [x] Create About modal 59 | - [x] Footer 60 | - [x] Design no results screen 61 | - [x] Adapt header design on mobile 62 | - [x] Tweak colors 63 | - [x] Load test title & description from README pages 64 | - [x] Write copy 65 | - [x] Info overlay 66 | - [x] Opinionated test style (integration / abstract libs) 67 | - [x] Cosmos vs non-Cosmos 68 | - [x] Test READMEs 69 | - [x] Create build script 70 | - [x] Add Next.js 71 | - [x] Reconcile Babel config between Next, Cosmos and Jest 72 | - [x] Reconcile webpack config between Next and Cosmos 73 | - [x] Restructure files for more clarity 74 | - [x] Read tests from disk at compile time 75 | - [x] Point to latest commit SHA 76 | - [x] PUBLISH 77 | - [x] Create fixtures for UI components 78 | - [ ] Config Playground for tests 79 | -------------------------------------------------------------------------------- /WHATSTHIS.md: -------------------------------------------------------------------------------- 1 | ## Dear friend, 2 | 3 | Presenting these examples took work. I hope they'll make your life easier! 4 | 5 | ### Why put this together? 6 | 7 | There's a lot of wisdom that goes into writing clean tests. With every project I learn something new. I wanted to document my latest testing style and use it as a go-to resource for future projects. 8 | 9 | ### How does it work? 10 | 11 | The test examples are up to date and run in [CircleCI](https://circleci.com/gh/skidding/react-testing-examples). This searchable library is generated from README and test files [available on GitHub](https://github.com/skidding/react-testing-examples/tree/master/tests). 12 | 13 | ### Is this useful to you? 14 | 15 | The testing examples are _opinionated_. They aim to mimic user behavior and avoid testing abstract components. But you're free to disagree with [my testing philosophy](https://medium.com/@skidding/testing-react-components-30516bc6a1b3). The examples also feature modern libraries and agnostic testing techniques. 16 | 17 | ### What's the focus? 18 | 19 | _The component setup_. Performing actions and assertions is already well documented by the tools that handle event simulation and/or expectations. The examples here focus on how to wire up various component types for testing. 20 | 21 | ### Want to contribute? 22 | 23 | Let's harness our collective knowledge to create a great resource for testing React components! 24 | 25 | Best,
26 | [Ovidiu](https://twitter.com/skidding) 27 | -------------------------------------------------------------------------------- /flow-typed/npm/express_v4.16.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 164dcf1c9105e51cb17a374a807146a7 2 | // flow-typed version: c7f4cf7a4d/express_v4.16.x/flow_>=v0.93.x 3 | 4 | import * as http from "http"; 5 | import type { Socket } from "net"; 6 | 7 | declare type express$RouterOptions = { 8 | caseSensitive?: boolean, 9 | mergeParams?: boolean, 10 | strict?: boolean 11 | }; 12 | 13 | declare class express$RequestResponseBase { 14 | app: express$Application; 15 | get(field: string): string | void; 16 | } 17 | 18 | declare type express$RequestParams = { 19 | [param: string]: string 20 | }; 21 | 22 | declare class express$Request extends http$IncomingMessage mixins express$RequestResponseBase { 23 | baseUrl: string; 24 | body: mixed; 25 | cookies: { [cookie: string]: string }; 26 | connection: Socket; 27 | fresh: boolean; 28 | hostname: string; 29 | ip: string; 30 | ips: Array; 31 | method: string; 32 | originalUrl: string; 33 | params: express$RequestParams; 34 | path: string; 35 | protocol: "https" | "http"; 36 | query: { [name: string]: string | Array }; 37 | route: string; 38 | secure: boolean; 39 | signedCookies: { [signedCookie: string]: string }; 40 | stale: boolean; 41 | subdomains: Array; 42 | xhr: boolean; 43 | accepts(types: string): string | false; 44 | accepts(types: Array): string | false; 45 | acceptsCharsets(...charsets: Array): string | false; 46 | acceptsEncodings(...encoding: Array): string | false; 47 | acceptsLanguages(...lang: Array): string | false; 48 | header(field: string): string | void; 49 | is(type: string): boolean; 50 | param(name: string, defaultValue?: string): string | void; 51 | } 52 | 53 | declare type express$CookieOptions = { 54 | domain?: string, 55 | encode?: (value: string) => string, 56 | expires?: Date, 57 | httpOnly?: boolean, 58 | maxAge?: number, 59 | path?: string, 60 | secure?: boolean, 61 | signed?: boolean 62 | }; 63 | 64 | declare type express$Path = string | RegExp; 65 | 66 | declare type express$RenderCallback = ( 67 | err: Error | null, 68 | html?: string 69 | ) => mixed; 70 | 71 | declare type express$SendFileOptions = { 72 | maxAge?: number, 73 | root?: string, 74 | lastModified?: boolean, 75 | headers?: { [name: string]: string }, 76 | dotfiles?: "allow" | "deny" | "ignore" 77 | }; 78 | 79 | declare class express$Response extends http$ServerResponse mixins express$RequestResponseBase { 80 | headersSent: boolean; 81 | locals: { [name: string]: mixed }; 82 | append(field: string, value?: string): this; 83 | attachment(filename?: string): this; 84 | cookie(name: string, value: string, options?: express$CookieOptions): this; 85 | clearCookie(name: string, options?: express$CookieOptions): this; 86 | download( 87 | path: string, 88 | filename?: string, 89 | callback?: (err?: ?Error) => void 90 | ): this; 91 | format(typesObject: { [type: string]: Function }): this; 92 | json(body?: mixed): this; 93 | jsonp(body?: mixed): this; 94 | links(links: { [name: string]: string }): this; 95 | location(path: string): this; 96 | redirect(url: string, ...args: Array): this; 97 | redirect(status: number, url: string, ...args: Array): this; 98 | render( 99 | view: string, 100 | locals?: { [name: string]: mixed }, 101 | callback?: express$RenderCallback 102 | ): this; 103 | send(body?: mixed): this; 104 | sendFile( 105 | path: string, 106 | options?: express$SendFileOptions, 107 | callback?: (err?: ?Error) => mixed 108 | ): this; 109 | sendStatus(statusCode: number): this; 110 | header(field: string, value?: string): this; 111 | header(headers: { [name: string]: string }): this; 112 | set(field: string, value?: string | string[]): this; 113 | set(headers: { [name: string]: string }): this; 114 | status(statusCode: number): this; 115 | type(type: string): this; 116 | vary(field: string): this; 117 | req: express$Request; 118 | } 119 | 120 | declare type express$NextFunction = (err?: ?Error | "route") => mixed; 121 | declare type express$Middleware = 122 | | (( 123 | req: $Subtype, 124 | res: express$Response, 125 | next: express$NextFunction 126 | ) => mixed) 127 | | (( 128 | error: Error, 129 | req: $Subtype, 130 | res: express$Response, 131 | next: express$NextFunction 132 | ) => mixed); 133 | declare interface express$RouteMethodType { 134 | (middleware: express$Middleware): T; 135 | (...middleware: Array): T; 136 | ( 137 | path: express$Path | express$Path[], 138 | ...middleware: Array 139 | ): T; 140 | } 141 | declare class express$Route { 142 | all: express$RouteMethodType; 143 | get: express$RouteMethodType; 144 | post: express$RouteMethodType; 145 | put: express$RouteMethodType; 146 | head: express$RouteMethodType; 147 | delete: express$RouteMethodType; 148 | options: express$RouteMethodType; 149 | trace: express$RouteMethodType; 150 | copy: express$RouteMethodType; 151 | lock: express$RouteMethodType; 152 | mkcol: express$RouteMethodType; 153 | move: express$RouteMethodType; 154 | purge: express$RouteMethodType; 155 | propfind: express$RouteMethodType; 156 | proppatch: express$RouteMethodType; 157 | unlock: express$RouteMethodType; 158 | report: express$RouteMethodType; 159 | mkactivity: express$RouteMethodType; 160 | checkout: express$RouteMethodType; 161 | merge: express$RouteMethodType; 162 | 163 | // @TODO Missing 'm-search' but get flow illegal name error. 164 | 165 | notify: express$RouteMethodType; 166 | subscribe: express$RouteMethodType; 167 | unsubscribe: express$RouteMethodType; 168 | patch: express$RouteMethodType; 169 | search: express$RouteMethodType; 170 | connect: express$RouteMethodType; 171 | } 172 | 173 | declare class express$Router extends express$Route { 174 | constructor(options?: express$RouterOptions): void; 175 | route(path: string): express$Route; 176 | static (options?: express$RouterOptions): express$Router; 177 | use(middleware: express$Middleware): this; 178 | use(...middleware: Array): this; 179 | use( 180 | path: express$Path | express$Path[], 181 | ...middleware: Array 182 | ): this; 183 | use(path: string, router: express$Router): this; 184 | handle( 185 | req: http$IncomingMessage<>, 186 | res: http$ServerResponse, 187 | next: express$NextFunction 188 | ): void; 189 | param( 190 | param: string, 191 | callback: ( 192 | req: $Subtype, 193 | res: express$Response, 194 | next: express$NextFunction, 195 | id: string 196 | ) => mixed 197 | ): void; 198 | ( 199 | req: http$IncomingMessage<>, 200 | res: http$ServerResponse, 201 | next?: ?express$NextFunction 202 | ): void; 203 | } 204 | 205 | /* 206 | With flow-bin ^0.59, express app.listen() is deemed to return any and fails flow type coverage. 207 | Which is ironic because https://github.com/facebook/flow/blob/master/Changelog.md#misc-2 (release notes for 0.59) 208 | says "Improves typings for Node.js HTTP server listen() function." See that? IMPROVES! 209 | To work around this issue, we changed Server to ?Server here, so that our invocations of express.listen() will 210 | not be deemed to lack type coverage. 211 | */ 212 | 213 | declare class express$Application extends express$Router mixins events$EventEmitter { 214 | constructor(): void; 215 | locals: { [name: string]: mixed }; 216 | mountpath: string; 217 | listen( 218 | port: number, 219 | hostname?: string, 220 | backlog?: number, 221 | callback?: (err?: ?Error) => mixed 222 | ): ?http.Server; 223 | listen( 224 | port: number, 225 | hostname?: string, 226 | callback?: (err?: ?Error) => mixed 227 | ): ?http.Server; 228 | listen(port: number, callback?: (err?: ?Error) => mixed): ?http.Server; 229 | listen(path: string, callback?: (err?: ?Error) => mixed): ?http.Server; 230 | listen(handle: Object, callback?: (err?: ?Error) => mixed): ?http.Server; 231 | disable(name: string): void; 232 | disabled(name: string): boolean; 233 | enable(name: string): express$Application; 234 | enabled(name: string): boolean; 235 | engine(name: string, callback: Function): void; 236 | /** 237 | * Mixed will not be taken as a value option. Issue around using the GET http method name and the get for settings. 238 | */ 239 | // get(name: string): mixed; 240 | set(name: string, value: mixed): mixed; 241 | render( 242 | name: string, 243 | optionsOrFunction: { [name: string]: mixed }, 244 | callback: express$RenderCallback 245 | ): void; 246 | handle( 247 | req: http$IncomingMessage<>, 248 | res: http$ServerResponse, 249 | next?: ?express$NextFunction 250 | ): void; 251 | // callable signature is not inherited 252 | ( 253 | req: http$IncomingMessage<>, 254 | res: http$ServerResponse, 255 | next?: ?express$NextFunction 256 | ): void; 257 | } 258 | 259 | declare type JsonOptions = { 260 | inflate?: boolean, 261 | limit?: string | number, 262 | reviver?: (key: string, value: mixed) => mixed, 263 | strict?: boolean, 264 | type?: string | Array | ((req: express$Request) => boolean), 265 | verify?: ( 266 | req: express$Request, 267 | res: express$Response, 268 | buf: Buffer, 269 | encoding: string 270 | ) => mixed 271 | }; 272 | 273 | declare type express$UrlEncodedOptions = { 274 | extended?: boolean, 275 | inflate?: boolean, 276 | limit?: string | number, 277 | parameterLimit?: number, 278 | type?: string | Array | ((req: express$Request) => boolean), 279 | verify?: ( 280 | req: express$Request, 281 | res: express$Response, 282 | buf: Buffer, 283 | encoding: string 284 | ) => mixed, 285 | } 286 | 287 | declare module "express" { 288 | declare export type RouterOptions = express$RouterOptions; 289 | declare export type CookieOptions = express$CookieOptions; 290 | declare export type Middleware = express$Middleware; 291 | declare export type NextFunction = express$NextFunction; 292 | declare export type RequestParams = express$RequestParams; 293 | declare export type $Response = express$Response; 294 | declare export type $Request = express$Request; 295 | declare export type $Application = express$Application; 296 | 297 | declare module.exports: { 298 | (): express$Application, // If you try to call like a function, it will use this signature 299 | json: (opts: ?JsonOptions) => express$Middleware, 300 | static: (root: string, options?: Object) => express$Middleware, // `static` property on the function 301 | Router: typeof express$Router, // `Router` property on the function 302 | urlencoded: (opts: ?express$UrlEncodedOptions) => express$Middleware, 303 | }; 304 | } 305 | -------------------------------------------------------------------------------- /flow-typed/npm/jest_v23.x.x.js: -------------------------------------------------------------------------------- 1 | // flow-typed signature: 0f67472200deae3d6dc3a941ed8a54b6 2 | // flow-typed version: 393032fc51/jest_v23.x.x/flow_>=v0.39.x 3 | 4 | type JestMockFn, TReturn> = { 5 | (...args: TArguments): TReturn, 6 | /** 7 | * An object for introspecting mock calls 8 | */ 9 | mock: { 10 | /** 11 | * An array that represents all calls that have been made into this mock 12 | * function. Each call is represented by an array of arguments that were 13 | * passed during the call. 14 | */ 15 | calls: Array, 16 | /** 17 | * An array that contains all the object instances that have been 18 | * instantiated from this mock function. 19 | */ 20 | instances: Array, 21 | /** 22 | * An array that contains all the object results that have been 23 | * returned by this mock function call 24 | */ 25 | results: Array<{ isThrow: boolean, value: TReturn }> 26 | }, 27 | /** 28 | * Resets all information stored in the mockFn.mock.calls and 29 | * mockFn.mock.instances arrays. Often this is useful when you want to clean 30 | * up a mock's usage data between two assertions. 31 | */ 32 | mockClear(): void, 33 | /** 34 | * Resets all information stored in the mock. This is useful when you want to 35 | * completely restore a mock back to its initial state. 36 | */ 37 | mockReset(): void, 38 | /** 39 | * Removes the mock and restores the initial implementation. This is useful 40 | * when you want to mock functions in certain test cases and restore the 41 | * original implementation in others. Beware that mockFn.mockRestore only 42 | * works when mock was created with jest.spyOn. Thus you have to take care of 43 | * restoration yourself when manually assigning jest.fn(). 44 | */ 45 | mockRestore(): void, 46 | /** 47 | * Accepts a function that should be used as the implementation of the mock. 48 | * The mock itself will still record all calls that go into and instances 49 | * that come from itself -- the only difference is that the implementation 50 | * will also be executed when the mock is called. 51 | */ 52 | mockImplementation( 53 | fn: (...args: TArguments) => TReturn 54 | ): JestMockFn, 55 | /** 56 | * Accepts a function that will be used as an implementation of the mock for 57 | * one call to the mocked function. Can be chained so that multiple function 58 | * calls produce different results. 59 | */ 60 | mockImplementationOnce( 61 | fn: (...args: TArguments) => TReturn 62 | ): JestMockFn, 63 | /** 64 | * Accepts a string to use in test result output in place of "jest.fn()" to 65 | * indicate which mock function is being referenced. 66 | */ 67 | mockName(name: string): JestMockFn, 68 | /** 69 | * Just a simple sugar function for returning `this` 70 | */ 71 | mockReturnThis(): void, 72 | /** 73 | * Accepts a value that will be returned whenever the mock function is called. 74 | */ 75 | mockReturnValue(value: TReturn): JestMockFn, 76 | /** 77 | * Sugar for only returning a value once inside your mock 78 | */ 79 | mockReturnValueOnce(value: TReturn): JestMockFn, 80 | /** 81 | * Sugar for jest.fn().mockImplementation(() => Promise.resolve(value)) 82 | */ 83 | mockResolvedValue(value: TReturn): JestMockFn>, 84 | /** 85 | * Sugar for jest.fn().mockImplementationOnce(() => Promise.resolve(value)) 86 | */ 87 | mockResolvedValueOnce(value: TReturn): JestMockFn>, 88 | /** 89 | * Sugar for jest.fn().mockImplementation(() => Promise.reject(value)) 90 | */ 91 | mockRejectedValue(value: TReturn): JestMockFn>, 92 | /** 93 | * Sugar for jest.fn().mockImplementationOnce(() => Promise.reject(value)) 94 | */ 95 | mockRejectedValueOnce(value: TReturn): JestMockFn> 96 | }; 97 | 98 | type JestAsymmetricEqualityType = { 99 | /** 100 | * A custom Jasmine equality tester 101 | */ 102 | asymmetricMatch(value: mixed): boolean 103 | }; 104 | 105 | type JestCallsType = { 106 | allArgs(): mixed, 107 | all(): mixed, 108 | any(): boolean, 109 | count(): number, 110 | first(): mixed, 111 | mostRecent(): mixed, 112 | reset(): void 113 | }; 114 | 115 | type JestClockType = { 116 | install(): void, 117 | mockDate(date: Date): void, 118 | tick(milliseconds?: number): void, 119 | uninstall(): void 120 | }; 121 | 122 | type JestMatcherResult = { 123 | message?: string | (() => string), 124 | pass: boolean 125 | }; 126 | 127 | type JestMatcher = (actual: any, expected: any) => 128 | | JestMatcherResult 129 | | Promise; 130 | 131 | type JestPromiseType = { 132 | /** 133 | * Use rejects to unwrap the reason of a rejected promise so any other 134 | * matcher can be chained. If the promise is fulfilled the assertion fails. 135 | */ 136 | rejects: JestExpectType, 137 | /** 138 | * Use resolves to unwrap the value of a fulfilled promise so any other 139 | * matcher can be chained. If the promise is rejected the assertion fails. 140 | */ 141 | resolves: JestExpectType 142 | }; 143 | 144 | /** 145 | * Jest allows functions and classes to be used as test names in test() and 146 | * describe() 147 | */ 148 | type JestTestName = string | Function; 149 | 150 | /** 151 | * Plugin: jest-styled-components 152 | */ 153 | 154 | type JestStyledComponentsMatcherValue = 155 | | string 156 | | JestAsymmetricEqualityType 157 | | RegExp 158 | | typeof undefined; 159 | 160 | type JestStyledComponentsMatcherOptions = { 161 | media?: string; 162 | modifier?: string; 163 | supports?: string; 164 | } 165 | 166 | type JestStyledComponentsMatchersType = { 167 | toHaveStyleRule( 168 | property: string, 169 | value: JestStyledComponentsMatcherValue, 170 | options?: JestStyledComponentsMatcherOptions 171 | ): void, 172 | }; 173 | 174 | /** 175 | * Plugin: jest-enzyme 176 | */ 177 | type EnzymeMatchersType = { 178 | // 5.x 179 | toBeEmpty(): void, 180 | toBePresent(): void, 181 | // 6.x 182 | toBeChecked(): void, 183 | toBeDisabled(): void, 184 | toBeEmptyRender(): void, 185 | toContainMatchingElement(selector: string): void; 186 | toContainMatchingElements(n: number, selector: string): void; 187 | toContainExactlyOneMatchingElement(selector: string): void; 188 | toContainReact(element: React$Element): void, 189 | toExist(): void, 190 | toHaveClassName(className: string): void, 191 | toHaveHTML(html: string): void, 192 | toHaveProp: ((propKey: string, propValue?: any) => void) & ((props: Object) => void), 193 | toHaveRef(refName: string): void, 194 | toHaveState: ((stateKey: string, stateValue?: any) => void) & ((state: Object) => void), 195 | toHaveStyle: ((styleKey: string, styleValue?: any) => void) & ((style: Object) => void), 196 | toHaveTagName(tagName: string): void, 197 | toHaveText(text: string): void, 198 | toHaveValue(value: any): void, 199 | toIncludeText(text: string): void, 200 | toMatchElement( 201 | element: React$Element, 202 | options?: {| ignoreProps?: boolean, verbose?: boolean |}, 203 | ): void, 204 | toMatchSelector(selector: string): void, 205 | // 7.x 206 | toHaveDisplayName(name: string): void, 207 | }; 208 | 209 | // DOM testing library extensions https://github.com/kentcdodds/dom-testing-library#custom-jest-matchers 210 | type DomTestingLibraryType = { 211 | toBeInTheDOM(): void, 212 | toHaveTextContent(content: string): void, 213 | toHaveAttribute(name: string, expectedValue?: string): void 214 | }; 215 | 216 | // Jest JQuery Matchers: https://github.com/unindented/custom-jquery-matchers 217 | type JestJQueryMatchersType = { 218 | toExist(): void, 219 | toHaveLength(len: number): void, 220 | toHaveId(id: string): void, 221 | toHaveClass(className: string): void, 222 | toHaveTag(tag: string): void, 223 | toHaveAttr(key: string, val?: any): void, 224 | toHaveProp(key: string, val?: any): void, 225 | toHaveText(text: string | RegExp): void, 226 | toHaveData(key: string, val?: any): void, 227 | toHaveValue(val: any): void, 228 | toHaveCss(css: {[key: string]: any}): void, 229 | toBeChecked(): void, 230 | toBeDisabled(): void, 231 | toBeEmpty(): void, 232 | toBeHidden(): void, 233 | toBeSelected(): void, 234 | toBeVisible(): void, 235 | toBeFocused(): void, 236 | toBeInDom(): void, 237 | toBeMatchedBy(sel: string): void, 238 | toHaveDescendant(sel: string): void, 239 | toHaveDescendantWithText(sel: string, text: string | RegExp): void 240 | }; 241 | 242 | 243 | // Jest Extended Matchers: https://github.com/jest-community/jest-extended 244 | type JestExtendedMatchersType = { 245 | /** 246 | * Note: Currently unimplemented 247 | * Passing assertion 248 | * 249 | * @param {String} message 250 | */ 251 | // pass(message: string): void; 252 | 253 | /** 254 | * Note: Currently unimplemented 255 | * Failing assertion 256 | * 257 | * @param {String} message 258 | */ 259 | // fail(message: string): void; 260 | 261 | /** 262 | * Use .toBeEmpty when checking if a String '', Array [] or Object {} is empty. 263 | */ 264 | toBeEmpty(): void; 265 | 266 | /** 267 | * Use .toBeOneOf when checking if a value is a member of a given Array. 268 | * @param {Array.<*>} members 269 | */ 270 | toBeOneOf(members: any[]): void; 271 | 272 | /** 273 | * Use `.toBeNil` when checking a value is `null` or `undefined`. 274 | */ 275 | toBeNil(): void; 276 | 277 | /** 278 | * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`. 279 | * @param {Function} predicate 280 | */ 281 | toSatisfy(predicate: (n: any) => boolean): void; 282 | 283 | /** 284 | * Use `.toBeArray` when checking if a value is an `Array`. 285 | */ 286 | toBeArray(): void; 287 | 288 | /** 289 | * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x. 290 | * @param {Number} x 291 | */ 292 | toBeArrayOfSize(x: number): void; 293 | 294 | /** 295 | * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set. 296 | * @param {Array.<*>} members 297 | */ 298 | toIncludeAllMembers(members: any[]): void; 299 | 300 | /** 301 | * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set. 302 | * @param {Array.<*>} members 303 | */ 304 | toIncludeAnyMembers(members: any[]): void; 305 | 306 | /** 307 | * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array. 308 | * @param {Function} predicate 309 | */ 310 | toSatisfyAll(predicate: (n: any) => boolean): void; 311 | 312 | /** 313 | * Use `.toBeBoolean` when checking if a value is a `Boolean`. 314 | */ 315 | toBeBoolean(): void; 316 | 317 | /** 318 | * Use `.toBeTrue` when checking a value is equal (===) to `true`. 319 | */ 320 | toBeTrue(): void; 321 | 322 | /** 323 | * Use `.toBeFalse` when checking a value is equal (===) to `false`. 324 | */ 325 | toBeFalse(): void; 326 | 327 | /** 328 | * Use .toBeDate when checking if a value is a Date. 329 | */ 330 | toBeDate(): void; 331 | 332 | /** 333 | * Use `.toBeFunction` when checking if a value is a `Function`. 334 | */ 335 | toBeFunction(): void; 336 | 337 | /** 338 | * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`. 339 | * 340 | * Note: Required Jest version >22 341 | * Note: Your mock functions will have to be asynchronous to cause the timestamps inside of Jest to occur in a differentJS event loop, otherwise the mock timestamps will all be the same 342 | * 343 | * @param {Mock} mock 344 | */ 345 | toHaveBeenCalledBefore(mock: JestMockFn): void; 346 | 347 | /** 348 | * Use `.toBeNumber` when checking if a value is a `Number`. 349 | */ 350 | toBeNumber(): void; 351 | 352 | /** 353 | * Use `.toBeNaN` when checking a value is `NaN`. 354 | */ 355 | toBeNaN(): void; 356 | 357 | /** 358 | * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`. 359 | */ 360 | toBeFinite(): void; 361 | 362 | /** 363 | * Use `.toBePositive` when checking if a value is a positive `Number`. 364 | */ 365 | toBePositive(): void; 366 | 367 | /** 368 | * Use `.toBeNegative` when checking if a value is a negative `Number`. 369 | */ 370 | toBeNegative(): void; 371 | 372 | /** 373 | * Use `.toBeEven` when checking if a value is an even `Number`. 374 | */ 375 | toBeEven(): void; 376 | 377 | /** 378 | * Use `.toBeOdd` when checking if a value is an odd `Number`. 379 | */ 380 | toBeOdd(): void; 381 | 382 | /** 383 | * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive). 384 | * 385 | * @param {Number} start 386 | * @param {Number} end 387 | */ 388 | toBeWithin(start: number, end: number): void; 389 | 390 | /** 391 | * Use `.toBeObject` when checking if a value is an `Object`. 392 | */ 393 | toBeObject(): void; 394 | 395 | /** 396 | * Use `.toContainKey` when checking if an object contains the provided key. 397 | * 398 | * @param {String} key 399 | */ 400 | toContainKey(key: string): void; 401 | 402 | /** 403 | * Use `.toContainKeys` when checking if an object has all of the provided keys. 404 | * 405 | * @param {Array.} keys 406 | */ 407 | toContainKeys(keys: string[]): void; 408 | 409 | /** 410 | * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys. 411 | * 412 | * @param {Array.} keys 413 | */ 414 | toContainAllKeys(keys: string[]): void; 415 | 416 | /** 417 | * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys. 418 | * 419 | * @param {Array.} keys 420 | */ 421 | toContainAnyKeys(keys: string[]): void; 422 | 423 | /** 424 | * Use `.toContainValue` when checking if an object contains the provided value. 425 | * 426 | * @param {*} value 427 | */ 428 | toContainValue(value: any): void; 429 | 430 | /** 431 | * Use `.toContainValues` when checking if an object contains all of the provided values. 432 | * 433 | * @param {Array.<*>} values 434 | */ 435 | toContainValues(values: any[]): void; 436 | 437 | /** 438 | * Use `.toContainAllValues` when checking if an object only contains all of the provided values. 439 | * 440 | * @param {Array.<*>} values 441 | */ 442 | toContainAllValues(values: any[]): void; 443 | 444 | /** 445 | * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values. 446 | * 447 | * @param {Array.<*>} values 448 | */ 449 | toContainAnyValues(values: any[]): void; 450 | 451 | /** 452 | * Use `.toContainEntry` when checking if an object contains the provided entry. 453 | * 454 | * @param {Array.} entry 455 | */ 456 | toContainEntry(entry: [string, string]): void; 457 | 458 | /** 459 | * Use `.toContainEntries` when checking if an object contains all of the provided entries. 460 | * 461 | * @param {Array.>} entries 462 | */ 463 | toContainEntries(entries: [string, string][]): void; 464 | 465 | /** 466 | * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries. 467 | * 468 | * @param {Array.>} entries 469 | */ 470 | toContainAllEntries(entries: [string, string][]): void; 471 | 472 | /** 473 | * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries. 474 | * 475 | * @param {Array.>} entries 476 | */ 477 | toContainAnyEntries(entries: [string, string][]): void; 478 | 479 | /** 480 | * Use `.toBeExtensible` when checking if an object is extensible. 481 | */ 482 | toBeExtensible(): void; 483 | 484 | /** 485 | * Use `.toBeFrozen` when checking if an object is frozen. 486 | */ 487 | toBeFrozen(): void; 488 | 489 | /** 490 | * Use `.toBeSealed` when checking if an object is sealed. 491 | */ 492 | toBeSealed(): void; 493 | 494 | /** 495 | * Use `.toBeString` when checking if a value is a `String`. 496 | */ 497 | toBeString(): void; 498 | 499 | /** 500 | * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings. 501 | * 502 | * @param {String} string 503 | */ 504 | toEqualCaseInsensitive(string: string): void; 505 | 506 | /** 507 | * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix. 508 | * 509 | * @param {String} prefix 510 | */ 511 | toStartWith(prefix: string): void; 512 | 513 | /** 514 | * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix. 515 | * 516 | * @param {String} suffix 517 | */ 518 | toEndWith(suffix: string): void; 519 | 520 | /** 521 | * Use `.toInclude` when checking if a `String` includes the given `String` substring. 522 | * 523 | * @param {String} substring 524 | */ 525 | toInclude(substring: string): void; 526 | 527 | /** 528 | * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times. 529 | * 530 | * @param {String} substring 531 | * @param {Number} times 532 | */ 533 | toIncludeRepeated(substring: string, times: number): void; 534 | 535 | /** 536 | * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings. 537 | * 538 | * @param {Array.} substring 539 | */ 540 | toIncludeMultiple(substring: string[]): void; 541 | }; 542 | 543 | interface JestExpectType { 544 | not: 545 | & JestExpectType 546 | & EnzymeMatchersType 547 | & DomTestingLibraryType 548 | & JestJQueryMatchersType 549 | & JestStyledComponentsMatchersType 550 | & JestExtendedMatchersType, 551 | /** 552 | * If you have a mock function, you can use .lastCalledWith to test what 553 | * arguments it was last called with. 554 | */ 555 | lastCalledWith(...args: Array): void, 556 | /** 557 | * toBe just checks that a value is what you expect. It uses === to check 558 | * strict equality. 559 | */ 560 | toBe(value: any): void, 561 | /** 562 | * Use .toBeCalledWith to ensure that a mock function was called with 563 | * specific arguments. 564 | */ 565 | toBeCalledWith(...args: Array): void, 566 | /** 567 | * Using exact equality with floating point numbers is a bad idea. Rounding 568 | * means that intuitive things fail. 569 | */ 570 | toBeCloseTo(num: number, delta: any): void, 571 | /** 572 | * Use .toBeDefined to check that a variable is not undefined. 573 | */ 574 | toBeDefined(): void, 575 | /** 576 | * Use .toBeFalsy when you don't care what a value is, you just want to 577 | * ensure a value is false in a boolean context. 578 | */ 579 | toBeFalsy(): void, 580 | /** 581 | * To compare floating point numbers, you can use toBeGreaterThan. 582 | */ 583 | toBeGreaterThan(number: number): void, 584 | /** 585 | * To compare floating point numbers, you can use toBeGreaterThanOrEqual. 586 | */ 587 | toBeGreaterThanOrEqual(number: number): void, 588 | /** 589 | * To compare floating point numbers, you can use toBeLessThan. 590 | */ 591 | toBeLessThan(number: number): void, 592 | /** 593 | * To compare floating point numbers, you can use toBeLessThanOrEqual. 594 | */ 595 | toBeLessThanOrEqual(number: number): void, 596 | /** 597 | * Use .toBeInstanceOf(Class) to check that an object is an instance of a 598 | * class. 599 | */ 600 | toBeInstanceOf(cls: Class<*>): void, 601 | /** 602 | * .toBeNull() is the same as .toBe(null) but the error messages are a bit 603 | * nicer. 604 | */ 605 | toBeNull(): void, 606 | /** 607 | * Use .toBeTruthy when you don't care what a value is, you just want to 608 | * ensure a value is true in a boolean context. 609 | */ 610 | toBeTruthy(): void, 611 | /** 612 | * Use .toBeUndefined to check that a variable is undefined. 613 | */ 614 | toBeUndefined(): void, 615 | /** 616 | * Use .toContain when you want to check that an item is in a list. For 617 | * testing the items in the list, this uses ===, a strict equality check. 618 | */ 619 | toContain(item: any): void, 620 | /** 621 | * Use .toContainEqual when you want to check that an item is in a list. For 622 | * testing the items in the list, this matcher recursively checks the 623 | * equality of all fields, rather than checking for object identity. 624 | */ 625 | toContainEqual(item: any): void, 626 | /** 627 | * Use .toEqual when you want to check that two objects have the same value. 628 | * This matcher recursively checks the equality of all fields, rather than 629 | * checking for object identity. 630 | */ 631 | toEqual(value: any): void, 632 | /** 633 | * Use .toHaveBeenCalled to ensure that a mock function got called. 634 | */ 635 | toHaveBeenCalled(): void, 636 | toBeCalled(): void; 637 | /** 638 | * Use .toHaveBeenCalledTimes to ensure that a mock function got called exact 639 | * number of times. 640 | */ 641 | toHaveBeenCalledTimes(number: number): void, 642 | toBeCalledTimes(number: number): void; 643 | /** 644 | * 645 | */ 646 | toHaveBeenNthCalledWith(nthCall: number, ...args: Array): void; 647 | nthCalledWith(nthCall: number, ...args: Array): void; 648 | /** 649 | * 650 | */ 651 | toHaveReturned(): void; 652 | toReturn(): void; 653 | /** 654 | * 655 | */ 656 | toHaveReturnedTimes(number: number): void; 657 | toReturnTimes(number: number): void; 658 | /** 659 | * 660 | */ 661 | toHaveReturnedWith(value: any): void; 662 | toReturnWith(value: any): void; 663 | /** 664 | * 665 | */ 666 | toHaveLastReturnedWith(value: any): void; 667 | lastReturnedWith(value: any): void; 668 | /** 669 | * 670 | */ 671 | toHaveNthReturnedWith(nthCall: number, value: any): void; 672 | nthReturnedWith(nthCall: number, value: any): void; 673 | /** 674 | * Use .toHaveBeenCalledWith to ensure that a mock function was called with 675 | * specific arguments. 676 | */ 677 | toHaveBeenCalledWith(...args: Array): void, 678 | toBeCalledWith(...args: Array): void, 679 | /** 680 | * Use .toHaveBeenLastCalledWith to ensure that a mock function was last called 681 | * with specific arguments. 682 | */ 683 | toHaveBeenLastCalledWith(...args: Array): void, 684 | lastCalledWith(...args: Array): void, 685 | /** 686 | * Check that an object has a .length property and it is set to a certain 687 | * numeric value. 688 | */ 689 | toHaveLength(number: number): void, 690 | /** 691 | * 692 | */ 693 | toHaveProperty(propPath: string, value?: any): void, 694 | /** 695 | * Use .toMatch to check that a string matches a regular expression or string. 696 | */ 697 | toMatch(regexpOrString: RegExp | string): void, 698 | /** 699 | * Use .toMatchObject to check that a javascript object matches a subset of the properties of an object. 700 | */ 701 | toMatchObject(object: Object | Array): void, 702 | /** 703 | * Use .toStrictEqual to check that a javascript object matches a subset of the properties of an object. 704 | */ 705 | toStrictEqual(value: any): void, 706 | /** 707 | * This ensures that an Object matches the most recent snapshot. 708 | */ 709 | toMatchSnapshot(propertyMatchers?: any, name?: string): void, 710 | /** 711 | * This ensures that an Object matches the most recent snapshot. 712 | */ 713 | toMatchSnapshot(name: string): void, 714 | 715 | toMatchInlineSnapshot(snapshot?: string): void, 716 | toMatchInlineSnapshot(propertyMatchers?: any, snapshot?: string): void, 717 | /** 718 | * Use .toThrow to test that a function throws when it is called. 719 | * If you want to test that a specific error gets thrown, you can provide an 720 | * argument to toThrow. The argument can be a string for the error message, 721 | * a class for the error, or a regex that should match the error. 722 | * 723 | * Alias: .toThrowError 724 | */ 725 | toThrow(message?: string | Error | Class | RegExp): void, 726 | toThrowError(message?: string | Error | Class | RegExp): void, 727 | /** 728 | * Use .toThrowErrorMatchingSnapshot to test that a function throws a error 729 | * matching the most recent snapshot when it is called. 730 | */ 731 | toThrowErrorMatchingSnapshot(): void, 732 | toThrowErrorMatchingInlineSnapshot(snapshot?: string): void, 733 | } 734 | 735 | type JestObjectType = { 736 | /** 737 | * Disables automatic mocking in the module loader. 738 | * 739 | * After this method is called, all `require()`s will return the real 740 | * versions of each module (rather than a mocked version). 741 | */ 742 | disableAutomock(): JestObjectType, 743 | /** 744 | * An un-hoisted version of disableAutomock 745 | */ 746 | autoMockOff(): JestObjectType, 747 | /** 748 | * Enables automatic mocking in the module loader. 749 | */ 750 | enableAutomock(): JestObjectType, 751 | /** 752 | * An un-hoisted version of enableAutomock 753 | */ 754 | autoMockOn(): JestObjectType, 755 | /** 756 | * Clears the mock.calls and mock.instances properties of all mocks. 757 | * Equivalent to calling .mockClear() on every mocked function. 758 | */ 759 | clearAllMocks(): JestObjectType, 760 | /** 761 | * Resets the state of all mocks. Equivalent to calling .mockReset() on every 762 | * mocked function. 763 | */ 764 | resetAllMocks(): JestObjectType, 765 | /** 766 | * Restores all mocks back to their original value. 767 | */ 768 | restoreAllMocks(): JestObjectType, 769 | /** 770 | * Removes any pending timers from the timer system. 771 | */ 772 | clearAllTimers(): void, 773 | /** 774 | * The same as `mock` but not moved to the top of the expectation by 775 | * babel-jest. 776 | */ 777 | doMock(moduleName: string, moduleFactory?: any): JestObjectType, 778 | /** 779 | * The same as `unmock` but not moved to the top of the expectation by 780 | * babel-jest. 781 | */ 782 | dontMock(moduleName: string): JestObjectType, 783 | /** 784 | * Returns a new, unused mock function. Optionally takes a mock 785 | * implementation. 786 | */ 787 | fn, TReturn>( 788 | implementation?: (...args: TArguments) => TReturn 789 | ): JestMockFn, 790 | /** 791 | * Determines if the given function is a mocked function. 792 | */ 793 | isMockFunction(fn: Function): boolean, 794 | /** 795 | * Given the name of a module, use the automatic mocking system to generate a 796 | * mocked version of the module for you. 797 | */ 798 | genMockFromModule(moduleName: string): any, 799 | /** 800 | * Mocks a module with an auto-mocked version when it is being required. 801 | * 802 | * The second argument can be used to specify an explicit module factory that 803 | * is being run instead of using Jest's automocking feature. 804 | * 805 | * The third argument can be used to create virtual mocks -- mocks of modules 806 | * that don't exist anywhere in the system. 807 | */ 808 | mock( 809 | moduleName: string, 810 | moduleFactory?: any, 811 | options?: Object 812 | ): JestObjectType, 813 | /** 814 | * Returns the actual module instead of a mock, bypassing all checks on 815 | * whether the module should receive a mock implementation or not. 816 | */ 817 | requireActual(moduleName: string): any, 818 | /** 819 | * Returns a mock module instead of the actual module, bypassing all checks 820 | * on whether the module should be required normally or not. 821 | */ 822 | requireMock(moduleName: string): any, 823 | /** 824 | * Resets the module registry - the cache of all required modules. This is 825 | * useful to isolate modules where local state might conflict between tests. 826 | */ 827 | resetModules(): JestObjectType, 828 | /** 829 | * Exhausts the micro-task queue (usually interfaced in node via 830 | * process.nextTick). 831 | */ 832 | runAllTicks(): void, 833 | /** 834 | * Exhausts the macro-task queue (i.e., all tasks queued by setTimeout(), 835 | * setInterval(), and setImmediate()). 836 | */ 837 | runAllTimers(): void, 838 | /** 839 | * Exhausts all tasks queued by setImmediate(). 840 | */ 841 | runAllImmediates(): void, 842 | /** 843 | * Executes only the macro task queue (i.e. all tasks queued by setTimeout() 844 | * or setInterval() and setImmediate()). 845 | */ 846 | advanceTimersByTime(msToRun: number): void, 847 | /** 848 | * Executes only the macro task queue (i.e. all tasks queued by setTimeout() 849 | * or setInterval() and setImmediate()). 850 | * 851 | * Renamed to `advanceTimersByTime`. 852 | */ 853 | runTimersToTime(msToRun: number): void, 854 | /** 855 | * Executes only the macro-tasks that are currently pending (i.e., only the 856 | * tasks that have been queued by setTimeout() or setInterval() up to this 857 | * point) 858 | */ 859 | runOnlyPendingTimers(): void, 860 | /** 861 | * Explicitly supplies the mock object that the module system should return 862 | * for the specified module. Note: It is recommended to use jest.mock() 863 | * instead. 864 | */ 865 | setMock(moduleName: string, moduleExports: any): JestObjectType, 866 | /** 867 | * Indicates that the module system should never return a mocked version of 868 | * the specified module from require() (e.g. that it should always return the 869 | * real module). 870 | */ 871 | unmock(moduleName: string): JestObjectType, 872 | /** 873 | * Instructs Jest to use fake versions of the standard timer functions 874 | * (setTimeout, setInterval, clearTimeout, clearInterval, nextTick, 875 | * setImmediate and clearImmediate). 876 | */ 877 | useFakeTimers(): JestObjectType, 878 | /** 879 | * Instructs Jest to use the real versions of the standard timer functions. 880 | */ 881 | useRealTimers(): JestObjectType, 882 | /** 883 | * Creates a mock function similar to jest.fn but also tracks calls to 884 | * object[methodName]. 885 | */ 886 | spyOn(object: Object, methodName: string, accessType?: "get" | "set"): JestMockFn, 887 | /** 888 | * Set the default timeout interval for tests and before/after hooks in milliseconds. 889 | * Note: The default timeout interval is 5 seconds if this method is not called. 890 | */ 891 | setTimeout(timeout: number): JestObjectType 892 | }; 893 | 894 | type JestSpyType = { 895 | calls: JestCallsType 896 | }; 897 | 898 | /** Runs this function after every test inside this context */ 899 | declare function afterEach( 900 | fn: (done: () => void) => ?Promise, 901 | timeout?: number 902 | ): void; 903 | /** Runs this function before every test inside this context */ 904 | declare function beforeEach( 905 | fn: (done: () => void) => ?Promise, 906 | timeout?: number 907 | ): void; 908 | /** Runs this function after all tests have finished inside this context */ 909 | declare function afterAll( 910 | fn: (done: () => void) => ?Promise, 911 | timeout?: number 912 | ): void; 913 | /** Runs this function before any tests have started inside this context */ 914 | declare function beforeAll( 915 | fn: (done: () => void) => ?Promise, 916 | timeout?: number 917 | ): void; 918 | 919 | /** A context for grouping tests together */ 920 | declare var describe: { 921 | /** 922 | * Creates a block that groups together several related tests in one "test suite" 923 | */ 924 | (name: JestTestName, fn: () => void): void, 925 | 926 | /** 927 | * Only run this describe block 928 | */ 929 | only(name: JestTestName, fn: () => void): void, 930 | 931 | /** 932 | * Skip running this describe block 933 | */ 934 | skip(name: JestTestName, fn: () => void): void, 935 | 936 | /** 937 | * each runs this test against array of argument arrays per each run 938 | * 939 | * @param {table} table of Test 940 | */ 941 | each( 942 | ...table: Array | mixed> | [Array, string] 943 | ): ( 944 | name: JestTestName, 945 | fn?: (...args: Array) => ?Promise, 946 | timeout?: number 947 | ) => void, 948 | }; 949 | 950 | /** An individual test unit */ 951 | declare var it: { 952 | /** 953 | * An individual test unit 954 | * 955 | * @param {JestTestName} Name of Test 956 | * @param {Function} Test 957 | * @param {number} Timeout for the test, in milliseconds. 958 | */ 959 | ( 960 | name: JestTestName, 961 | fn?: (done: () => void) => ?Promise, 962 | timeout?: number 963 | ): void, 964 | 965 | /** 966 | * Only run this test 967 | * 968 | * @param {JestTestName} Name of Test 969 | * @param {Function} Test 970 | * @param {number} Timeout for the test, in milliseconds. 971 | */ 972 | only( 973 | name: JestTestName, 974 | fn?: (done: () => void) => ?Promise, 975 | timeout?: number 976 | ): { 977 | each( 978 | ...table: Array | mixed> | [Array, string] 979 | ): ( 980 | name: JestTestName, 981 | fn?: (...args: Array) => ?Promise, 982 | timeout?: number 983 | ) => void, 984 | }, 985 | 986 | /** 987 | * Skip running this test 988 | * 989 | * @param {JestTestName} Name of Test 990 | * @param {Function} Test 991 | * @param {number} Timeout for the test, in milliseconds. 992 | */ 993 | skip( 994 | name: JestTestName, 995 | fn?: (done: () => void) => ?Promise, 996 | timeout?: number 997 | ): void, 998 | 999 | /** 1000 | * Run the test concurrently 1001 | * 1002 | * @param {JestTestName} Name of Test 1003 | * @param {Function} Test 1004 | * @param {number} Timeout for the test, in milliseconds. 1005 | */ 1006 | concurrent( 1007 | name: JestTestName, 1008 | fn?: (done: () => void) => ?Promise, 1009 | timeout?: number 1010 | ): void, 1011 | 1012 | /** 1013 | * each runs this test against array of argument arrays per each run 1014 | * 1015 | * @param {table} table of Test 1016 | */ 1017 | each( 1018 | ...table: Array | mixed> | [Array, string] 1019 | ): ( 1020 | name: JestTestName, 1021 | fn?: (...args: Array) => ?Promise, 1022 | timeout?: number 1023 | ) => void, 1024 | }; 1025 | 1026 | declare function fit( 1027 | name: JestTestName, 1028 | fn: (done: () => void) => ?Promise, 1029 | timeout?: number 1030 | ): void; 1031 | /** An individual test unit */ 1032 | declare var test: typeof it; 1033 | /** A disabled group of tests */ 1034 | declare var xdescribe: typeof describe; 1035 | /** A focused group of tests */ 1036 | declare var fdescribe: typeof describe; 1037 | /** A disabled individual test */ 1038 | declare var xit: typeof it; 1039 | /** A disabled individual test */ 1040 | declare var xtest: typeof it; 1041 | 1042 | type JestPrettyFormatColors = { 1043 | comment: { close: string, open: string }, 1044 | content: { close: string, open: string }, 1045 | prop: { close: string, open: string }, 1046 | tag: { close: string, open: string }, 1047 | value: { close: string, open: string }, 1048 | }; 1049 | 1050 | type JestPrettyFormatIndent = string => string; 1051 | type JestPrettyFormatRefs = Array; 1052 | type JestPrettyFormatPrint = any => string; 1053 | type JestPrettyFormatStringOrNull = string | null; 1054 | 1055 | type JestPrettyFormatOptions = {| 1056 | callToJSON: boolean, 1057 | edgeSpacing: string, 1058 | escapeRegex: boolean, 1059 | highlight: boolean, 1060 | indent: number, 1061 | maxDepth: number, 1062 | min: boolean, 1063 | plugins: JestPrettyFormatPlugins, 1064 | printFunctionName: boolean, 1065 | spacing: string, 1066 | theme: {| 1067 | comment: string, 1068 | content: string, 1069 | prop: string, 1070 | tag: string, 1071 | value: string, 1072 | |}, 1073 | |}; 1074 | 1075 | type JestPrettyFormatPlugin = { 1076 | print: ( 1077 | val: any, 1078 | serialize: JestPrettyFormatPrint, 1079 | indent: JestPrettyFormatIndent, 1080 | opts: JestPrettyFormatOptions, 1081 | colors: JestPrettyFormatColors, 1082 | ) => string, 1083 | test: any => boolean, 1084 | }; 1085 | 1086 | type JestPrettyFormatPlugins = Array; 1087 | 1088 | /** The expect function is used every time you want to test a value */ 1089 | declare var expect: { 1090 | /** The object that you want to make assertions against */ 1091 | (value: any): 1092 | & JestExpectType 1093 | & JestPromiseType 1094 | & EnzymeMatchersType 1095 | & DomTestingLibraryType 1096 | & JestJQueryMatchersType 1097 | & JestStyledComponentsMatchersType 1098 | & JestExtendedMatchersType, 1099 | 1100 | /** Add additional Jasmine matchers to Jest's roster */ 1101 | extend(matchers: { [name: string]: JestMatcher }): void, 1102 | /** Add a module that formats application-specific data structures. */ 1103 | addSnapshotSerializer(pluginModule: JestPrettyFormatPlugin): void, 1104 | assertions(expectedAssertions: number): void, 1105 | hasAssertions(): void, 1106 | any(value: mixed): JestAsymmetricEqualityType, 1107 | anything(): any, 1108 | arrayContaining(value: Array): Array, 1109 | objectContaining(value: Object): Object, 1110 | /** Matches any received string that contains the exact expected string. */ 1111 | stringContaining(value: string): string, 1112 | stringMatching(value: string | RegExp): string, 1113 | not: { 1114 | arrayContaining: (value: $ReadOnlyArray) => Array, 1115 | objectContaining: (value: {}) => Object, 1116 | stringContaining: (value: string) => string, 1117 | stringMatching: (value: string | RegExp) => string, 1118 | }, 1119 | }; 1120 | 1121 | // TODO handle return type 1122 | // http://jasmine.github.io/2.4/introduction.html#section-Spies 1123 | declare function spyOn(value: mixed, method: string): Object; 1124 | 1125 | /** Holds all functions related to manipulating test runner */ 1126 | declare var jest: JestObjectType; 1127 | 1128 | /** 1129 | * The global Jasmine object, this is generally not exposed as the public API, 1130 | * using features inside here could break in later versions of Jest. 1131 | */ 1132 | declare var jasmine: { 1133 | DEFAULT_TIMEOUT_INTERVAL: number, 1134 | any(value: mixed): JestAsymmetricEqualityType, 1135 | anything(): any, 1136 | arrayContaining(value: Array): Array, 1137 | clock(): JestClockType, 1138 | createSpy(name: string): JestSpyType, 1139 | createSpyObj( 1140 | baseName: string, 1141 | methodNames: Array 1142 | ): { [methodName: string]: JestSpyType }, 1143 | objectContaining(value: Object): Object, 1144 | stringMatching(value: string): string 1145 | }; 1146 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "lint": "eslint '**/*.js'", 4 | "test:jest-enzyme": "jest --config tests/jest-enzyme/jest.config.js", 5 | "test:jest-enzyme:watch": "yarn test:jest-enzyme --watch", 6 | "test:jest-rtl": "jest --config tests/jest-rtl/jest.config.js", 7 | "test:jest-rtl:watch": "yarn test:jest-rtl --watch", 8 | "test:jest-interactor": "jest --config tests/jest-interactor/jest.config.js", 9 | "test:jest-interactor:watch": "yarn test:jest-interactor --watch", 10 | "test:ui": "yarn jest --config ui/jest.config.js", 11 | "test:ui:watch": "yarn test:ui --watch", 12 | "test": "yarn test:jest-enzyme && yarn test:jest-rtl && yarn test:jest-interactor && yarn test:ui", 13 | "test:ci": "yarn test:jest-enzyme --maxWorkers=2 && yarn test:jest-rtl --maxWorkers=2 && yarn test:jest-interactor --maxWorkers=2 && yarn test:ui --maxWorkers=2", 14 | "cosmos": "cosmos-classic --config ui/cosmos.config", 15 | "dev": "yarn babel-node ui/server/start-dev.js", 16 | "build": "next build ui && next export ui -o .export", 17 | "upload": "cd .export && now --name rte --public && cd -" 18 | }, 19 | "devDependencies": { 20 | "@babel/cli": "7.1.2", 21 | "@babel/core": "7.1.2", 22 | "@babel/node": "^7.0.0", 23 | "@babel/plugin-proposal-class-properties": "7.1.0", 24 | "@babel/plugin-proposal-decorators": "^7.1.6", 25 | "@babel/plugin-proposal-object-rest-spread": "7.0.0", 26 | "@babel/preset-env": "7.1.0", 27 | "@babel/preset-flow": "7.0.0", 28 | "@babel/preset-react": "7.0.0", 29 | "@bigtest/interactor": "^0.9.1", 30 | "@bigtest/react": "^0.1.2", 31 | "@mdx-js/loader": "^0.15.5", 32 | "@mdx-js/mdx": "^0.15.5", 33 | "@react-mock/fetch": "^0.3.0", 34 | "@react-mock/localstorage": "^0.1.2", 35 | "@react-mock/state": "^0.1.7", 36 | "@react-mock/xhr": "^0.2.0", 37 | "@skidding/async-retry": "^1.0.2", 38 | "async-until": "^1.2.2", 39 | "axios": "^0.18.0", 40 | "babel-core": "^7.0.0-bridge.0", 41 | "babel-eslint": "^10.0.1", 42 | "babel-jest": "^23.6.0", 43 | "babel-loader": "^8.0.4", 44 | "babel-plugin-inline-import-data-uri": "^1.0.1", 45 | "babel-plugin-module-resolver": "^3.1.1", 46 | "babel-plugin-styled-components": "^1.8.0", 47 | "css-loader": "^1.0.0", 48 | "enzyme": "^3.7.0", 49 | "enzyme-adapter-react-16": "^1.6.0", 50 | "eslint": "^5.7.0", 51 | "eslint-import-resolver-babel-module": "^5.0.0-beta.1", 52 | "eslint-plugin-babel": "^5.2.1", 53 | "eslint-plugin-flowtype": "^3.0.0", 54 | "eslint-plugin-import": "^2.14.0", 55 | "eslint-plugin-jest": "^21.25.1", 56 | "eslint-plugin-react": "^7.11.1", 57 | "express": "^4.16.4", 58 | "flow-bin": "^0.93.0", 59 | "flow-typed": "^2.5.1", 60 | "glob": "^7.1.3", 61 | "html-webpack-plugin": "^3.2.0", 62 | "jest": "^24.1.0", 63 | "jest-dom": "^2.1.0", 64 | "prettier": "^1.16.4", 65 | "raw-loader": "^0.5.1", 66 | "react-cosmos-classic": "^4.8.3", 67 | "react-cosmos-fetch-proxy": "^4.8.2", 68 | "react-cosmos-localstorage-proxy": "^4.8.2", 69 | "react-cosmos-redux-proxy": "^4.8.2", 70 | "react-cosmos-router-proxy": "^4.8.2", 71 | "react-cosmos-test": "^4.8.2", 72 | "react-cosmos-xhr-proxy": "^4.8.2", 73 | "react-redux": "^5.0.7", 74 | "react-router": "^4.3.1", 75 | "react-router-dom": "^4.3.1", 76 | "react-test-renderer": "^16.5.2", 77 | "react-testing-library": "^5.2.0", 78 | "redux": "^4.0.1", 79 | "remark-parse": "^5.0.0", 80 | "style-loader": "^0.23.1", 81 | "traverse": "^0.6.6", 82 | "unified": "^7.0.0", 83 | "webpack": "^4.21.0" 84 | }, 85 | "dependencies": { 86 | "clipboard": "^2.0.4", 87 | "delay": "^4.1.0", 88 | "fuzzaldrin-plus": "^0.6.0", 89 | "next": "^7.0.2", 90 | "parse-numeric-range": "^0.0.2", 91 | "prismjs": "^1.15.0", 92 | "query-string": "^6.2.0", 93 | "react": "^16.8.3", 94 | "react-dom": "^16.8.3", 95 | "react-show": "2.0.4", 96 | "styled-components": "^4.1.3" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ovidiuch/react-testing-examples/edc256d9370ccb3ec348ce4543029eda877d3969/screenshot2.png -------------------------------------------------------------------------------- /tests/jest-enzyme/README.md: -------------------------------------------------------------------------------- 1 | ## Setup 2 | 3 | Minimal setup required to use [Enzyme](https://airbnb.io/enzyme/) with [Jest](https://jestjs.io/). 4 | 5 | > All examples featured here run using these exact config files. 6 | -------------------------------------------------------------------------------- /tests/jest-enzyme/click-callback/README.md: -------------------------------------------------------------------------------- 1 | ## Callback fires on button click 2 | 3 | The component receives a callback prop and renders a button. We test that the callback prop is called when the button is clicked. 4 | -------------------------------------------------------------------------------- /tests/jest-enzyme/click-callback/test.js: -------------------------------------------------------------------------------- 1 | // highlight{9,11} 2 | import React from 'react'; 3 | import { mount } from 'enzyme'; 4 | import { Button } from 'shared/components/Button'; 5 | 6 | it('calls "onClick" prop on button click', () => { 7 | // Render new instance in every test to prevent leaking state 8 | const onClick = jest.fn(); 9 | const wrapper = mount(; 5 | } 6 | -------------------------------------------------------------------------------- /tests/shared/components/HelloMessage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function HelloMessage({ name }) { 4 | return Hello {name}; 5 | } 6 | -------------------------------------------------------------------------------- /tests/shared/components/HelloMessageStyled.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | 3 | export const HelloMessageStyled = ({ name }) => ( 4 | Hello {name} 5 | ); 6 | 7 | export const Container = styled.span` 8 | background: ${props => props.theme.background}; 9 | color: ${props => props.theme.text}; 10 | `; 11 | -------------------------------------------------------------------------------- /tests/shared/components/PersistentForm.js: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | 3 | import React, { Component } from 'react'; 4 | 5 | export class PersistentForm extends Component { 6 | state = { 7 | name: 'Guest' 8 | }; 9 | 10 | componentDidMount() { 11 | this.setState({ 12 | name: localStorage.getItem('name') 13 | }); 14 | } 15 | 16 | changeName = e => { 17 | e.preventDefault(); 18 | 19 | const name = this.refs.nameField.value; 20 | this.setState({ name }, () => { 21 | localStorage.setItem('name', name); 22 | }); 23 | }; 24 | 25 | render() { 26 | const { name } = this.state; 27 | 28 | return ( 29 | <> 30 |

Welcome, {name}!

31 |
32 | 33 | 34 | 35 |
36 | 37 | ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tests/shared/components/ReduxCounter.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | 4 | function Counter({ count, increment }) { 5 | return ( 6 |
7 | Clicked {count} times 8 |
9 | ); 10 | } 11 | 12 | function mapStateToProps({ count }) { 13 | return { count }; 14 | } 15 | 16 | const mapDispatchToProps = { 17 | increment: () => ({ type: 'INCREMENT' }) 18 | }; 19 | 20 | export const ReduxCounter = connect(mapStateToProps, mapDispatchToProps)( 21 | Counter 22 | ); 23 | -------------------------------------------------------------------------------- /tests/shared/components/ServerFetchCounter.js: -------------------------------------------------------------------------------- 1 | /* eslint-env browser */ 2 | 3 | import React, { Component } from 'react'; 4 | 5 | export class ServerCounter extends Component { 6 | state = { 7 | isSyncing: true, 8 | count: 0 9 | }; 10 | 11 | componentDidMount() { 12 | fetch('/count') 13 | .then(res => res.json()) 14 | .then(({ count }) => { 15 | this.setState({ isSyncing: false, count }); 16 | }); 17 | } 18 | 19 | increment = () => { 20 | this.setState({ isSyncing: true }); 21 | 22 | fetch('/count', { method: 'POST' }) 23 | .then(res => res.json()) 24 | .then(({ count }) => { 25 | this.setState({ isSyncing: false, count }); 26 | }); 27 | }; 28 | 29 | render() { 30 | const { isSyncing, count } = this.state; 31 | 32 | return isSyncing ? ( 33 |
Syncing...
34 | ) : ( 35 |
36 | Clicked {count} times 37 |
38 | ); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tests/shared/components/ServerXhrCounter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import axios from 'axios'; 3 | 4 | export class ServerCounter extends Component { 5 | state = { 6 | isSyncing: true, 7 | count: 0 8 | }; 9 | 10 | componentDidMount() { 11 | axios('/count').then(({ data: { count } }) => { 12 | this.setState({ isSyncing: false, count }); 13 | }); 14 | } 15 | 16 | increment = () => { 17 | this.setState({ isSyncing: true }); 18 | 19 | axios.post('/count').then(({ data: { count } }) => { 20 | this.setState({ isSyncing: false, count }); 21 | }); 22 | }; 23 | 24 | render() { 25 | const { isSyncing, count } = this.state; 26 | 27 | return isSyncing ? ( 28 |
Syncing...
29 | ) : ( 30 |
31 | Clicked {count} times 32 |
33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tests/shared/components/StatefulCounter.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | export class StatefulCounter extends Component { 4 | state = { 5 | count: 0 6 | }; 7 | 8 | increment = () => { 9 | this.setState({ count: this.state.count + 1 }); 10 | }; 11 | 12 | render() { 13 | return ( 14 |
15 | Clicked {this.state.count} times{' '} 16 | 17 |
18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /tests/shared/components/UserWithRouter.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { withRouter } from 'react-router'; 3 | import { Link } from 'react-router-dom'; 4 | 5 | function UserPage({ match: { params } }) { 6 | return ( 7 |
8 | User #{params.userId} Next user 9 |
10 | ); 11 | } 12 | 13 | export const UserWithRouter = withRouter(UserPage); 14 | -------------------------------------------------------------------------------- /tests/shared/theme.js: -------------------------------------------------------------------------------- 1 | export const themeLight = { 2 | background: 'white', 3 | text: 'black' 4 | }; 5 | 6 | export const themeDark = { 7 | background: 'black', 8 | text: 'white' 9 | }; 10 | -------------------------------------------------------------------------------- /ui/components/AboutModal.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import React, { Component } from 'react'; 4 | import Router from 'next/router'; 5 | import Link from 'next/link'; 6 | import styled from 'styled-components'; 7 | import WhatsThis from '../../WHATSTHIS.md'; 8 | import { CenterText, H2, H3, Button, Paragraph } from './shared/styles'; 9 | import { WindowKeyListener, KEY_ESC } from './shared/WindowKeyListener'; 10 | 11 | type Props = {}; 12 | 13 | export class AboutModal extends Component { 14 | handleContentClick = (e: SyntheticEvent) => { 15 | e.stopPropagation(); 16 | }; 17 | 18 | handleKeyDown = (e: SyntheticKeyboardEvent) => { 19 | if (e.keyCode === KEY_ESC) { 20 | goHome(); 21 | } 22 | }; 23 | 24 | render() { 25 | return ( 26 | 27 | 28 | 29 | , 35 | ol: OpinionsList 36 | }} 37 | /> 38 | 39 | 40 | Show me some tests 41 | 42 | 43 | 44 | 45 | 46 | ); 47 | } 48 | } 49 | 50 | function goHome() { 51 | Router.push('/'); 52 | } 53 | 54 | const Overlay = styled.div` 55 | position: fixed; 56 | top: 0; 57 | bottom: 0; 58 | left: 0; 59 | right: 0; 60 | z-index: 2; 61 | padding: 32px 12px; 62 | background: rgba(221, 224, 232, 0.9); 63 | overflow-x: hidden; 64 | overflow-y: auto; 65 | `; 66 | 67 | const Content = styled(CenterText)` 68 | background: #fff; 69 | border-radius: 10px; 70 | box-shadow: 0 3px 15px 0 rgba(32, 35, 42, 0.2); 71 | overflow: hidden; 72 | padding: 8px 24px 16px 24px; 73 | 74 | @media (min-width: 480px) { 75 | padding: 8px 36px 16px 36px; 76 | } 77 | `; 78 | 79 | const ButtonContainer = styled.div` 80 | text-align: right; 81 | `; 82 | 83 | const OpinionsList = styled.ol` 84 | padding-left: 36px; 85 | `; 86 | 87 | const SubtleLink = styled.a` 88 | color: #20232a; 89 | font-weight: 500; 90 | `; 91 | 92 | const GoButton = styled(Button)` 93 | display: inline-block; 94 | padding: 12px 20px; 95 | border-radius: 5px; 96 | background: #2b51ad; 97 | color: #f5f7f9; 98 | line-height: 24px; 99 | `; 100 | -------------------------------------------------------------------------------- /ui/components/App.fixture.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | import { createFixture } from 'react-cosmos-classic'; 4 | import { App } from './App'; 5 | import { gitRef } from '../import-files'; 6 | import { getTestKind } from '../shared/testKinds'; 7 | 8 | export default [ 9 | createFixture({ 10 | name: 'react-testing-library', 11 | component: App, 12 | props: { 13 | gitRef, 14 | testKind: getTestKind('jest-rtl'), 15 | showAbout: false 16 | }, 17 | state: {} 18 | }), 19 | createFixture({ 20 | name: 'react-testing-library Fetch', 21 | component: App, 22 | props: { 23 | gitRef, 24 | testKind: getTestKind('jest-rtl'), 25 | sectionName: 'fetch', 26 | showAbout: false 27 | }, 28 | state: {} 29 | }), 30 | createFixture({ 31 | name: 'Enzyme', 32 | component: App, 33 | props: { 34 | gitRef, 35 | testKind: getTestKind('jest-enzyme'), 36 | showAbout: false 37 | }, 38 | state: {} 39 | }), 40 | createFixture({ 41 | name: 'Enzyme setup', 42 | component: App, 43 | props: { 44 | gitRef, 45 | testKind: getTestKind('jest-enzyme'), 46 | sectionName: 'setup', 47 | showAbout: false 48 | }, 49 | state: {} 50 | }), 51 | createFixture({ 52 | name: 'About', 53 | component: App, 54 | props: { 55 | gitRef, 56 | testKind: getTestKind('jest-rtl'), 57 | showAbout: true 58 | } 59 | }) 60 | ]; 61 | -------------------------------------------------------------------------------- /ui/components/App.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /* eslint-env browser */ 3 | 4 | import React, { Component } from 'react'; 5 | import styled from 'styled-components'; 6 | import { sortBy } from 'lodash'; 7 | import { FileOptions, GitRef } from '../contexts'; 8 | import { shouldSearch, matchReadmeText, sortSections } from '../search'; 9 | import { hasSectionChanged, getSectionByName } from '../shared/section'; 10 | import { MOBILE_BREAKPOINT } from './shared/styles'; 11 | import { Header } from './Header'; 12 | import { AboutModal } from './AboutModal'; 13 | import { SectionList } from './SectionList'; 14 | import { Section } from './Section'; 15 | import { Footer } from './Footer'; 16 | 17 | import type { TTestKind, TSection } from '../types'; 18 | 19 | type Props = { 20 | gitRef: string, 21 | testKind: TTestKind, 22 | sectionName?: string, 23 | showAbout: boolean 24 | }; 25 | 26 | type State = { 27 | showComments: boolean, 28 | showImports: boolean, 29 | searchText: string 30 | }; 31 | 32 | export class App extends Component { 33 | static defaultProps = { 34 | showAbout: false 35 | }; 36 | 37 | state = { 38 | showAboutModal: false, 39 | showComments: true, 40 | showImports: false, 41 | searchText: '' 42 | }; 43 | 44 | handleToggleComments = () => { 45 | this.setState({ showComments: !this.state.showComments }); 46 | }; 47 | 48 | handleToggleImports = () => { 49 | this.setState({ showImports: !this.state.showImports }); 50 | }; 51 | 52 | handleSearchChange = (searchText: string) => { 53 | this.setState({ searchText }); 54 | }; 55 | 56 | componentDidMount() { 57 | setBodyScroll(this.props.showAbout); 58 | } 59 | 60 | componentDidUpdate(prevProps: Props, prevState: State) { 61 | const { showAbout } = this.props; 62 | const { searchText } = this.state; 63 | 64 | if ( 65 | searchText && 66 | hasSectionChanged(getSectionProps(this.props), getSectionProps(prevProps)) 67 | ) { 68 | this.setState({ 69 | searchText: '' 70 | }); 71 | } 72 | // Jump to top when changing search query, because results will change 73 | // anyway so previous scroll position will be irrelevant 74 | else if (searchText && searchText !== prevState.searchText) { 75 | window.scrollTo(0, 0); 76 | } 77 | 78 | if (showAbout !== prevProps.showAbout) { 79 | setBodyScroll(showAbout); 80 | } 81 | } 82 | 83 | render() { 84 | const { gitRef, testKind, sectionName, showAbout } = this.props; 85 | const { showComments, showImports, searchText } = this.state; 86 | 87 | const isSearching = shouldSearch(searchText); 88 | const sections = [testKind.setup, ...getSortedTests(testKind)]; 89 | 90 | return ( 91 | 92 | 93 | 94 | 95 |
102 | 103 | {isSearching ? ( 104 | this.renderSearchContent(sections) 105 | ) : ( 106 | <> 107 | 114 | {sectionName 115 | ? getSectionEl({ 116 | section: getSectionByName(sections, sectionName), 117 | testKind, 118 | searchText 119 | }) 120 | : sections.map(section => 121 | getSectionEl({ section, testKind, searchText }) 122 | )} 123 | 124 | )} 125 | 126 |