├── .babelrc ├── .editorconfig ├── .eslintrc ├── .flowconfig ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── package.json ├── spec └── support │ └── jasmine.json ├── src ├── chai.js ├── expect.js ├── index.js ├── init.js ├── jasmine.js ├── jest.js ├── matchers │ ├── toBeAGlobalStyle.js │ ├── toHaveComponent.js │ ├── toHaveKeyframeRule.js │ ├── toHaveStyleRule.js │ └── toNotHaveStyleRule.js ├── serializers │ └── styleSheetSerializer.js └── utils │ ├── getCSS.js │ ├── getClassNames.js │ ├── getCodeBlock.js │ ├── isOverV2.js │ ├── isServer.js │ └── styleSheet.js ├── test ├── chai.spec.js ├── expect.spec.js ├── jasmine.spec.js ├── jest.spec.js ├── matchers │ ├── __snapshots__ │ │ └── toMatchSnapshot.spec.js.snap │ ├── toBeAGlobalStyle.spec.js │ ├── toHaveComponent.spec.js │ ├── toHaveKeyframeRule.spec.js │ ├── toHaveStyleRule.spec.js │ ├── toMatchSnapshot.spec.js │ └── toNotHaveStyleRule.js ├── setup.js └── utils │ ├── framework.js │ └── getCodeBlock.spec.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "flow", 4 | "es2015", 5 | "stage-0", 6 | "react" 7 | ], 8 | "plugins": [ 9 | [ 10 | "transform-decorators-legacy" 11 | ], 12 | [ 13 | "transform-es3-member-expression-literals" 14 | ], 15 | [ 16 | "transform-es3-property-literals" 17 | ] 18 | ] 19 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain 2 | # consistent coding styles between different editors and IDEs. 3 | 4 | root = true 5 | 6 | [*] 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaFeatures": { 3 | "jsx": true, 4 | "modules": true 5 | }, 6 | "env": { 7 | "browser": true, 8 | "node": true 9 | }, 10 | "parser": "babel-eslint", 11 | "rules": { 12 | "linebreak-style": 0, 13 | "react/jsx-filename-extension": "off", 14 | "quotes": [ 15 | 2, 16 | "single" 17 | ], 18 | "strict": [ 19 | 2, 20 | "never" 21 | ], 22 | "react/jsx-uses-react": 2, 23 | "react/jsx-uses-vars": 2, 24 | "react/react-in-jsx-scope": 2 25 | }, 26 | "plugins": [ 27 | "flowtype", 28 | "react" 29 | ], 30 | "globals": { 31 | "describe": false, 32 | "test": false, 33 | "expect": false, 34 | "jasmine": false, 35 | "it": false, 36 | "before": false, 37 | "beforeEach": false, 38 | "beforeAll": false, 39 | "after": false, 40 | "afterEach": false 41 | }, 42 | "extends": [ 43 | "plugin:flowtype/recommended", 44 | "prettier", 45 | "prettier/flowtype", 46 | "prettier/react", 47 | "airbnb" 48 | ], 49 | "settings": { 50 | "flowtype": { 51 | "onlyFilesWithFlowAnnotation": true 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | 3 | [include] 4 | ./src 5 | 6 | [libs] 7 | 8 | [options] 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **General Information** 2 | 3 | - [ ] Bug 4 | - [ ] Improvement 5 | - [ ] Feature 6 | - [ ] Other 7 | 8 | **Description** 9 | 10 | (Add images if possible) 11 | 12 | **Steps to reproduce** 13 | 14 | (Add link to a demo on https://jsfiddle.net or similar if possible) 15 | 16 | **Versions** 17 | 18 | - styled-components-test-utils: 19 | - node: 20 | 21 | - jest: 22 | - expect: 23 | - chai: 24 | - jasmine: 25 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - [ ] Pull request has tests / docs demo, and is linted. 2 | - [ ] Description explains the issue / use-case resolved, and auto-closes the related issue(s) (https://help.github.com/articles/closing-issues-via-commit-messages/). 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | *.log 4 | dist 5 | lib 6 | es 7 | coverage 8 | _book 9 | .nyc_output 10 | TODO.md 11 | package-lock.json -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | - "7" 5 | - "8" 6 | script: 7 | - npm run check:src 8 | - npm run build 9 | branches: 10 | only: 11 | - master 12 | cache: 13 | directories: 14 | - $HOME/.npm 15 | after_success: npm run test:cov 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | Every release, along with the migration instructions, is documented on the Github [Releases](https://github.com/mbasso/styled-components-test-utils/releases) page. 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We are pleased to receive any contribution by the community. By contributing to styled-components-test-utils, you agree to abide by the [code of conduct](https://github.com/mbasso/styled-components-test-utils/blob/master/CODE_OF_CONDUCT.md). 4 | 5 | ## Issues 6 | 7 | Before opening an issue, please search the [issue tracker](https://github.com/mbasso/styled-components-test-utils/issues) to make sure your issue hasn’t already been reported. 8 | Please follow our guidelines when opening an issue, in that way we can understand your problem easily and we can help you faster. 9 | 10 | ### Bugs and Improvements 11 | 12 | Bugs and Improvements in general can be discussed on the [issue tracker](https://github.com/mbasso/styled-components-test-utils/issues), make sure that there aren't other issues with the same purpose. 13 | 14 | ## Development 15 | 16 | Visit the [issue tracker](https://github.com/mbasso/styled-components-test-utils/issues) to find a list of open issues that need attention. 17 | 18 | Fork, then clone the repo: 19 | 20 | ``` 21 | git clone https://github.com/mbasso/styled-components-test-utils.git 22 | ``` 23 | 24 | ### Building 25 | 26 | #### Building styled-components-test-utils 27 | 28 | Running the `build` task will create both a CommonJS module-per-module build and a UMD build. 29 | ``` 30 | npm run build 31 | ``` 32 | 33 | To create just a CommonJS module-per-module build: 34 | 35 | ``` 36 | npm run build:commonjs 37 | 38 | ``` 39 | 40 | The result will be in the `lib` folder. 41 | 42 | To create just a UMD build: 43 | ``` 44 | npm run build:umd 45 | npm run build:umd:min 46 | ``` 47 | 48 | The result will be in the `dist` folder. 49 | 50 | ### Testing and Linting 51 | 52 | To run both linting and testing at once, run the following: 53 | 54 | ``` 55 | npm run check:src 56 | ``` 57 | 58 | To only run linting: 59 | 60 | ``` 61 | npm run lint 62 | ``` 63 | 64 | To only run tests: 65 | 66 | ``` 67 | npm run test 68 | ``` 69 | 70 | To continuously watch and run tests, run the following: 71 | 72 | ``` 73 | npm run test:watch 74 | ``` 75 | 76 | ### Docs 77 | 78 | Improvements to the documentation are always welcome. Before submitting your changes, check that they respect all docs style. 79 | For example, use "-" for lists etc. 80 | 81 | ### Pull Request 82 | 83 | Pull requests are welcome, but make sure that your changes respect the 2 points in PR template: 84 | 85 | - Pull request has tests / docs demo, and is linted. 86 | - Description explains the issue / use-case resolved, and auto-closes the related issue(s) 87 | 88 | Thank you! 89 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright for portions of project styled-components-test-utils are held by Michele Bertoli, 2017 as part of project jest-styled-components. All other copyright for project styled-components-test-utils are held by Matteo Basso. 4 | 5 | Copyright (c) 2017 Matteo Basso 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # styled-components-test-utils 2 | 3 | [![Build Status](https://travis-ci.org/mbasso/styled-components-test-utils.svg?branch=master)](https://travis-ci.org/mbasso/styled-components-test-utils) 4 | [![npm version](https://img.shields.io/npm/v/styled-components-test-utils.svg)](https://www.npmjs.com/package/styled-components-test-utils) 5 | [![npm downloads](https://img.shields.io/npm/dm/styled-components-test-utils.svg?maxAge=2592000)](https://www.npmjs.com/package/styled-components-test-utils) 6 | [![Coverage Status](https://coveralls.io/repos/github/mbasso/styled-components-test-utils/badge.svg?branch=master)](https://coveralls.io/github/mbasso/styled-components-test-utils?branch=master) 7 | 8 | > Test utils for styled-components compatible with jest, expect, chai and jasmine 9 | 10 | ## Table of Contents 11 | 12 | - [Motivation](#motivation) 13 | - [Installation](#installation) 14 | - [Jest](#jest) 15 | - [Expect](#expect) 16 | - [Chai](#chai) 17 | - [Jasmine](#jasmine) 18 | - [Api](#api) 19 | - [toHaveStyleRule](#tohavestylerule) 20 | - [toNotHaveStyleRule](#tonothavestylerule) 21 | - [toHaveKeyframeRule](#tohavekeyframerule) 22 | - [toHaveComponent](#tohavecomponent) 23 | - [toBeAGlobalStyle](#tobeaglobalstyle) 24 | - [toMatchSnapshot](#tomatchsnapshot) 25 | - [Change Log](#change-log) 26 | - [Authors](#authors) 27 | - [Copyright and License](#copyright-and-license) 28 | 29 | ## Motivation 30 | This project is based on one simple idea: write a powerful set of test-utils for styled-components compatible with a lot assertion libraries. 31 | This is born from the willing to use [jest-styled-components](https://github.com/styled-components/jest-styled-components) (a useful project on which this one is based) with [expect](https://github.com/mjackson/expect). 32 | 33 | ## Installation 34 | 35 | You can install styled-components-test-utils using [npm](https://www.npmjs.com/package/styled-components-test-utils): 36 | 37 | ```bash 38 | npm install --save-dev styled-components-test-utils 39 | ``` 40 | 41 | and if you haven't `react-test-renderer`: 42 | 43 | ```bash 44 | npm install --save-dev react-test-renderer 45 | ``` 46 | 47 | and following one of these: [Jest](#jest), [Expect](#expect), [Chai](#chai), [Jasmine](#jasmine) 48 | 49 | ### Jest 50 | To use styled-components-test-utils with jest, you simply have to import the following: 51 | 52 | ```js 53 | import 'styled-components-test-utils/lib/jest'; 54 | 55 | // ... 56 | 57 | expect(component).toHaveStyleRule(property, value); 58 | ``` 59 | 60 | ### Expect 61 | To use styled-components-test-utils with expect, you have to do the following: 62 | 63 | ```js 64 | import expect from 'expect'; 65 | import injectStyledUtils from 'styled-components-test-utils/lib/expect'; 66 | 67 | injectStyledUtils(expect); 68 | 69 | // ... 70 | 71 | expect(component).toHaveStyleRule(property, value); 72 | ``` 73 | 74 | ### Chai 75 | To use styled-components-test-utils with chai, you simply have to import the following: 76 | 77 | ```js 78 | import 'styled-components-test-utils/lib/chai'; 79 | 80 | // ... 81 | 82 | expect(component).toHaveStyleRule(property, value); 83 | ``` 84 | 85 | ### Jasmine 86 | To use styled-components-test-utils with jasmine, you have to do the following: 87 | 88 | ```js 89 | import injectStyledUtils from 'styled-components-test-utils/lib/jasmine'; 90 | 91 | describe('test', () => { 92 | beforeAll(() => { 93 | injectStyledUtils(jasmine); 94 | }); 95 | 96 | // ... 97 | 98 | expect(component).toHaveStyleRule(property, value); 99 | 100 | // ... 101 | }); 102 | ``` 103 | 104 | ## Api 105 | Here is the list of the available APIs. Please, note that in the examples we are using `react-test-renderer` but this library works also with `react-test-renderer/shallow` and `enzyme's shallow`, `enzyme's mount` is not supported yet. 106 | 107 | ### toHaveStyleRule 108 | > expect(tree).toHaveStyleRule(selector, value) 109 | > 110 | > expect({ component, modifier, media }).toHaveStyleRule(selector, value) 111 | > 112 | > expect({ css, props, modifier, media }).toHaveStyleRule(selector, value) 113 | 114 | Asserts that `tree`, `component` or `css` has a rule `selector: value;`. You can also pass some additional parameters to test selectors and media queries, here is an example: 115 | 116 | ```js 117 | const Button = styled.button` 118 | color: blue; 119 | 120 | &:hover { 121 | color: green; 122 | } 123 | 124 | @media screen and (max-width: 600px) { 125 | &:hover { 126 | color: yellow; 127 | } 128 | } 129 | `; 130 | const component = renderer.create( 210 | 211 | 212 | 217 | 218 | 219 | `; 220 | 221 | exports[`extending styles - react-test-renderer 1`] = ` 222 | .c0 { 223 | color: palevioletred; 224 | font-size: 1em; 225 | margin: 1em; 226 | padding: 0.25em 1em; 227 | border: 2px solid palevioletred; 228 | border-radius: 3px; 229 | } 230 | 231 | .c1 { 232 | color: palevioletred; 233 | font-size: 1em; 234 | margin: 1em; 235 | padding: 0.25em 1em; 236 | border: 2px solid palevioletred; 237 | border-radius: 3px; 238 | color: tomato; 239 | border-color: tomato; 240 | } 241 | 242 |
243 | 248 | 253 |
254 | `; 255 | 256 | exports[`extending styles - shallow 1`] = ` 257 |
258 | 259 | Normal Button 260 | 261 | 262 | Tomato Button 263 | 264 |
265 | `; 266 | 267 | exports[`non-styled - mount 1`] = `
`; 268 | 269 | exports[`non-styled - react-test-renderer 1`] = `
`; 270 | 271 | exports[`non-styled - shallow 1`] = `
`; 272 | 273 | exports[`null 1`] = `null`; 274 | 275 | exports[`referring to other components - mount 1`] = ` 276 | .c1 { 277 | display: -webkit-box; 278 | display: -webkit-flex; 279 | display: -ms-flexbox; 280 | display: flex; 281 | -webkit-align-items: center; 282 | -webkit-box-align: center; 283 | -ms-flex-align: center; 284 | align-items: center; 285 | padding: 5px 10px; 286 | background: papayawhip; 287 | color: palevioletred; 288 | } 289 | 290 | .c2 { 291 | -webkit-transition: fill 0.25s; 292 | transition: fill 0.25s; 293 | width: 48px; 294 | height: 48px; 295 | } 296 | 297 | .c0:hover .c2 { 298 | fill: rebeccapurple; 299 | } 300 | 301 | .c3 { 302 | display: -webkit-box; 303 | display: -webkit-flex; 304 | display: -ms-flexbox; 305 | display: flex; 306 | -webkit-align-items: center; 307 | -webkit-box-align: center; 308 | -ms-flex-align: center; 309 | align-items: center; 310 | line-height: 1.2; 311 | } 312 | 313 | .c3::before { 314 | content: '◀'; 315 | margin: 0 10px; 316 | } 317 | 318 | 321 | 325 | 326 | 329 | 330 | 331 | 334 | Hovering my parent changes my style! 335 | 336 | 337 | 338 | 339 | `; 340 | 341 | exports[`referring to other components - react-test-renderer 1`] = ` 342 | .c1 { 343 | display: -webkit-box; 344 | display: -webkit-flex; 345 | display: -ms-flexbox; 346 | display: flex; 347 | -webkit-align-items: center; 348 | -webkit-box-align: center; 349 | -ms-flex-align: center; 350 | align-items: center; 351 | padding: 5px 10px; 352 | background: papayawhip; 353 | color: palevioletred; 354 | } 355 | 356 | .c2 { 357 | -webkit-transition: fill 0.25s; 358 | transition: fill 0.25s; 359 | width: 48px; 360 | height: 48px; 361 | } 362 | 363 | .c0:hover .c2 { 364 | fill: rebeccapurple; 365 | } 366 | 367 | .c3 { 368 | display: -webkit-box; 369 | display: -webkit-flex; 370 | display: -ms-flexbox; 371 | display: flex; 372 | -webkit-align-items: center; 373 | -webkit-box-align: center; 374 | -ms-flex-align: center; 375 | align-items: center; 376 | line-height: 1.2; 377 | } 378 | 379 | .c3::before { 380 | content: '◀'; 381 | margin: 0 10px; 382 | } 383 | 384 | 388 | 391 | 394 | Hovering my parent changes my style! 395 | 396 | 397 | `; 398 | 399 | exports[`supported css - mount 1`] = ` 400 | .c0 { 401 | padding: 2em 1em; 402 | background: papayawhip; 403 | } 404 | 405 | .c0:hover { 406 | background: palevioletred; 407 | } 408 | 409 | .c0 > p { 410 | -webkit-text-decoration: underline; 411 | text-decoration: underline; 412 | } 413 | 414 | html.test .c0 { 415 | display: none; 416 | } 417 | 418 | @media (max-width:600px) { 419 | .c0 { 420 | background: tomato; 421 | } 422 | 423 | .c0:hover { 424 | background: yellow; 425 | } 426 | } 427 | 428 | 429 |
432 |

433 | Hello World! 434 |

435 |
436 |
437 | `; 438 | 439 | exports[`supported css - react-test-renderer 1`] = ` 440 | .c0 { 441 | padding: 2em 1em; 442 | background: papayawhip; 443 | } 444 | 445 | .c0:hover { 446 | background: palevioletred; 447 | } 448 | 449 | .c0 > p { 450 | -webkit-text-decoration: underline; 451 | text-decoration: underline; 452 | } 453 | 454 | html.test .c0 { 455 | display: none; 456 | } 457 | 458 | @media (max-width:600px) { 459 | .c0 { 460 | background: tomato; 461 | } 462 | 463 | .c0:hover { 464 | background: yellow; 465 | } 466 | } 467 | 468 |
471 |

472 | Hello World! 473 |

474 |
475 | `; 476 | 477 | exports[`supported css - shallow 1`] = ` 478 | .c0 { 479 | padding: 2em 1em; 480 | background: papayawhip; 481 | } 482 | 483 | .c0:hover { 484 | background: palevioletred; 485 | } 486 | 487 | .c0 > p { 488 | -webkit-text-decoration: underline; 489 | text-decoration: underline; 490 | } 491 | 492 | html.test .c0 { 493 | display: none; 494 | } 495 | 496 | @media (max-width:600px) { 497 | .c0 { 498 | background: tomato; 499 | } 500 | 501 | .c0:hover { 502 | background: yellow; 503 | } 504 | } 505 | 506 |
509 |

510 | Hello World! 511 |

512 |
513 | `; 514 | 515 | exports[`theming - mount 1`] = ` 516 | .c0 { 517 | font-size: 1em; 518 | margin: 1em; 519 | padding: 0.25em 1em; 520 | border-radius: 3px; 521 | color: palevioletred; 522 | border: 2px solid palevioletred; 523 | } 524 | 525 | .c1 { 526 | font-size: 1em; 527 | margin: 1em; 528 | padding: 0.25em 1em; 529 | border-radius: 3px; 530 | color: mediumseagreen; 531 | border: 2px solid mediumseagreen; 532 | } 533 | 534 |
535 | 542 | 547 | 548 | 555 | 562 | 567 | 568 | 569 |
570 | `; 571 | 572 | exports[`theming - react-test-renderer 1`] = ` 573 | .c0 { 574 | font-size: 1em; 575 | margin: 1em; 576 | padding: 0.25em 1em; 577 | border-radius: 3px; 578 | color: palevioletred; 579 | border: 2px solid palevioletred; 580 | } 581 | 582 | .c1 { 583 | font-size: 1em; 584 | margin: 1em; 585 | padding: 0.25em 1em; 586 | border-radius: 3px; 587 | color: mediumseagreen; 588 | border: 2px solid mediumseagreen; 589 | } 590 | 591 |
592 | 597 | 602 |
603 | `; 604 | 605 | exports[`theming - shallow 1`] = ` 606 |
607 | 614 | Normal 615 | 616 | 623 | 630 | Themed 631 | 632 | 633 |
634 | `; 635 | -------------------------------------------------------------------------------- /test/matchers/toBeAGlobalStyle.spec.js: -------------------------------------------------------------------------------- 1 | import { injectGlobal } from 'styled-components'; 2 | import chalk from 'chalk'; 3 | import '../../src/jest'; 4 | import toBeAGlobalStyle from '../../src/matchers/toBeAGlobalStyle'; 5 | 6 | // eslint-disable-next-line 7 | injectGlobal` 8 | body { 9 | font-family: 'Roboto'; 10 | } 11 | `; 12 | 13 | describe('toBeAGlobalStyle', () => { 14 | const style = ` 15 | body { 16 | font-family: 'Roboto'; 17 | } 18 | `; 19 | 20 | const getMessage = value => `Expected global styles to contain:\n\t${chalk.red(value)}`; 21 | 22 | test('should pass', () => { 23 | const result = toBeAGlobalStyle(style); 24 | expect(result.message).toEqual(getMessage(style)); 25 | expect(result.pass).toBeTruthy(); 26 | }); 27 | 28 | test('should skip whitespaces', () => { 29 | const received = ` 30 | body { 31 | font-family: 'Roboto'; 32 | } 33 | `; 34 | const result = toBeAGlobalStyle(received); 35 | expect(result.message).toEqual(getMessage(received)); 36 | expect(result.pass).toBeTruthy(); 37 | }); 38 | 39 | test('should fail', () => { 40 | const received = ` 41 | body { 42 | font-family: ; 43 | } 44 | `; 45 | 46 | const result = toBeAGlobalStyle(received); 47 | expect(result.message).toEqual(getMessage(received)); 48 | expect(result.pass).toBeFalsy(); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /test/matchers/toHaveComponent.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import chalk from 'chalk'; 3 | import styled from 'styled-components'; 4 | import '../../src/jest'; 5 | import toHaveComponent from '../../src/matchers/toHaveComponent'; 6 | 7 | const Foo = () =>
foo
; 8 | const Bar = () =>
bar
; 9 | 10 | const Button = styled.button``; 11 | const Link = styled.a``; 12 | const StyledFoo = styled(Foo)``; 13 | 14 | describe('toHaveComponent', () => { 15 | const getMessage = ({ received, expected }) => 16 | `Expected styled-component to have component\n\t${chalk.green(expected)}\nreceived:\n\t${chalk.red(received)}`; 17 | 18 | test('should pass if tagnames are equal', () => { 19 | const result = toHaveComponent(Button, 'button'); 20 | expect(result.message).toEqual(getMessage({ 21 | received: 'button', 22 | expected: 'button', 23 | })); 24 | expect(result.pass).toBeTruthy(); 25 | }); 26 | 27 | test('should fail if tagnames are different', () => { 28 | const result = toHaveComponent(Link, 'button'); 29 | expect(result.message).toEqual(getMessage({ 30 | received: 'a', 31 | expected: 'button', 32 | })); 33 | expect(result.pass).toBeFalsy(); 34 | }); 35 | 36 | test('should pass if components are equal', () => { 37 | const result = toHaveComponent(StyledFoo, Foo); 38 | expect(result.message).toEqual(getMessage({ 39 | received: 'Foo', 40 | expected: 'Foo', 41 | })); 42 | expect(result.pass).toBeTruthy(); 43 | }); 44 | 45 | test('should fail if components are different', () => { 46 | const result = toHaveComponent(StyledFoo, Bar); 47 | expect(result.message).toEqual(getMessage({ 48 | received: 'Foo', 49 | expected: 'Bar', 50 | })); 51 | expect(result.pass).toBeFalsy(); 52 | }); 53 | 54 | test('should fail if component and tagname are different', () => { 55 | const result = toHaveComponent(StyledFoo, 'button'); 56 | expect(result.message).toEqual(getMessage({ 57 | received: 'Foo', 58 | expected: 'button', 59 | })); 60 | expect(result.pass).toBeFalsy(); 61 | }); 62 | 63 | test('should work with withComponent api', () => { 64 | const StyledButtonFoo = Button.withComponent(Foo); 65 | const result = toHaveComponent(StyledButtonFoo, Foo); 66 | expect(result.message).toEqual(getMessage({ 67 | received: 'Foo', 68 | expected: 'Foo', 69 | })); 70 | expect(result.pass).toBeTruthy(); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /test/matchers/toHaveKeyframeRule.spec.js: -------------------------------------------------------------------------------- 1 | import { keyframes } from 'styled-components'; 2 | import chalk from 'chalk'; 3 | import '../../src/jest'; 4 | import toHaveKeyframeRule from '../../src/matchers/toHaveKeyframeRule'; 5 | 6 | describe('toHaveKeyframeRule', () => { 7 | const fadeIn = keyframes` 8 | 100% { 9 | opacity: 1; 10 | } 11 | 0% { 12 | opacity: 0; 13 | } 14 | `; 15 | 16 | const getMessage = ({ 17 | keyframeSelector, 18 | selector, 19 | expected, 20 | received, 21 | }) => 22 | `Expected keyframe to have ${keyframeSelector} ${selector} matching\n\t${chalk.green(expected)}\nreceived:\n\t${chalk.red(received)}`; 23 | 24 | test('should pass if properties are equal', () => { 25 | const result = toHaveKeyframeRule(fadeIn, '0%', 'opacity', '0'); 26 | expect(result.message).toEqual(getMessage({ 27 | keyframeSelector: '0%', 28 | selector: 'opacity', 29 | expected: '0', 30 | received: '0', 31 | })); 32 | expect(result.pass).toBeTruthy(); 33 | }); 34 | 35 | test('should pass if properties are not equal', () => { 36 | const result = toHaveKeyframeRule(fadeIn, '0%', 'opacity', '1'); 37 | expect(result.message).toEqual(getMessage({ 38 | keyframeSelector: '0%', 39 | selector: 'opacity', 40 | expected: '1', 41 | received: '0', 42 | })); 43 | expect(result.pass).toBeFalsy(); 44 | }); 45 | 46 | test('should fail if property is not present', () => { 47 | const result = toHaveKeyframeRule(fadeIn, '0%', 'foo', '0'); 48 | expect(result.message).toEqual(`Property not found: ${chalk.red('0%')} ${chalk.red('foo')}`); 49 | expect(result.pass).toBeFalsy(); 50 | }); 51 | 52 | test('should fail if keyframeSelector is not present', () => { 53 | const result = toHaveKeyframeRule(fadeIn, '75%', 'top', '0'); 54 | expect(result.message).toEqual(`Property not found: ${chalk.red('75%')} ${chalk.red('top')}`); 55 | expect(result.pass).toBeFalsy(); 56 | }); 57 | 58 | test('should fail if keyframed doesn\'t exist', () => { 59 | const result = toHaveKeyframeRule('foo', '75%', 'top', '0'); 60 | expect(result.message).toEqual(`Property not found: ${chalk.red('75%')} ${chalk.red('top')}`); 61 | expect(result.pass).toBeFalsy(); 62 | }); 63 | 64 | test('should support regexp', () => { 65 | const result = toHaveKeyframeRule(fadeIn, '0%', 'opacity', /0/); 66 | expect(result.message).toEqual(getMessage({ 67 | keyframeSelector: '0%', 68 | selector: 'opacity', 69 | expected: '/0/', 70 | received: '0', 71 | })); 72 | expect(result.pass).toBeTruthy(); 73 | }); 74 | }); 75 | -------------------------------------------------------------------------------- /test/matchers/toHaveStyleRule.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import chalk from 'chalk'; 3 | import ReactTestRenderer from 'react-test-renderer'; 4 | import ShallowRenderer from 'react-test-renderer/shallow'; 5 | import styled, { css } from 'styled-components'; 6 | import { shallow /* , mount */ } from 'enzyme'; 7 | import '../../src/jest'; 8 | import toHaveStyleRule from '../../src/matchers/toHaveStyleRule'; 9 | 10 | const Button = styled.button` 11 | color: blue; 12 | background-color: red; 13 | 14 | &:hover { 15 | color: white; 16 | } 17 | 18 | *:not([fill='none']) { 19 | color: black; 20 | } 21 | 22 | > span { 23 | color: green; 24 | } 25 | 26 | > span > span { 27 | color: red; 28 | } 29 | 30 | html.test & { 31 | color: black; 32 | } 33 | 34 | @media screen and (max-width: 3800px) and (min-width: 601px) { 35 | &:hover { 36 | color: pink; 37 | } 38 | } 39 | 40 | @media screen and (max-width: 600px) { 41 | &:hover { 42 | color: purple; 43 | } 44 | 45 | > *:not(:first-child) { 46 | margin-left: 12px; 47 | } 48 | } 49 | 50 | @media screen and (max-width: 600px) { 51 | &:active { 52 | color: red; 53 | } 54 | } 55 | `; 56 | 57 | const ButtonWithSpaces = styled.button` 58 | color : blue ; 59 | `; 60 | 61 | describe('toHaveStyleRule', () => { 62 | const getMessage = ({ 63 | expected, 64 | selector, 65 | received, 66 | } = {}) => 67 | `Expected ${selector} matching\n\t${chalk.green(expected)}\nreceived:\n\t${chalk.red(received)}`; 68 | 69 | test('should pass if properties are equal', () => { 70 | const component = ReactTestRenderer.create( 95 | Tomato Button 96 |
, 97 | ); 98 | }); 99 | 100 | test('attaching additional props', () => { 101 | const Div = styled.div.attrs({ 102 | className: 'div', 103 | })` 104 | color: red; 105 | `; 106 | 107 | toMatchSnapshot('attaching additional props',
); 108 | }); 109 | 110 | test('theming', () => { 111 | const Button = styled.button` 112 | font-size: 1em; 113 | margin: 1em; 114 | padding: 0.25em 1em; 115 | border-radius: 3px; 116 | color: ${props => props.theme.main}; 117 | border: 2px solid ${props => props.theme.main}; 118 | `; 119 | 120 | Button.defaultProps = { 121 | theme: { 122 | main: 'palevioletred', 123 | }, 124 | }; 125 | 126 | const theme = { 127 | main: 'mediumseagreen', 128 | }; 129 | 130 | toMatchSnapshot( 131 | 'theming', 132 |
133 | 134 | 135 | 136 | 137 |
, 138 | ); 139 | }); 140 | 141 | test('supported css', () => { 142 | const Example = styled.div` 143 | padding: 2em 1em; 144 | background: papayawhip; 145 | &:hover { 146 | background: palevioletred; 147 | } 148 | @media (max-width: 600px) { 149 | background: tomato; 150 | &:hover { 151 | background: yellow; 152 | } 153 | } 154 | > p { 155 | text-decoration: underline; 156 | } 157 | html.test & { 158 | display: none; 159 | } 160 | `; 161 | 162 | toMatchSnapshot( 163 | 'supported css', 164 | 165 |

Hello World!

166 |
, 167 | ); 168 | }); 169 | 170 | test('referring to other components', () => { 171 | const Link = styled.a` 172 | display: flex; 173 | align-items: center; 174 | padding: 5px 10px; 175 | background: papayawhip; 176 | color: palevioletred; 177 | `; 178 | 179 | const Icon = styled.svg` 180 | transition: fill 0.25s; 181 | width: 48px; 182 | height: 48px; 183 | ${Link}:hover & { 184 | fill: rebeccapurple; 185 | } 186 | `; 187 | 188 | const Label = styled.span` 189 | display: flex; 190 | align-items: center; 191 | line-height: 1.2; 192 | &::before { 193 | content: '◀'; 194 | margin: 0 10px; 195 | } 196 | `; 197 | 198 | const component = ( 199 | 200 | 201 | 202 | 203 | ); 204 | 205 | expect(renderer.create(component).toJSON()).toMatchSnapshot( 206 | 'referring to other components - react-test-renderer', 207 | ); 208 | expect(mount(component)).toMatchSnapshot('referring to other components - mount'); 209 | }); 210 | -------------------------------------------------------------------------------- /test/matchers/toNotHaveStyleRule.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import chalk from 'chalk'; 3 | import ReactTestRenderer from 'react-test-renderer'; 4 | import styled from 'styled-components'; 5 | import '../../src/jest'; 6 | import toHaveStyleRule from '../../src/matchers/toHaveStyleRule'; 7 | 8 | const Button = styled.button` 9 | color: blue; 10 | background-color: red; 11 | 12 | &:hover { 13 | color: white; 14 | } 15 | 16 | > span { 17 | color: green; 18 | } 19 | 20 | > span > span { 21 | color: red; 22 | } 23 | 24 | html.test & { 25 | color: black; 26 | } 27 | 28 | @media screen and (max-width: 600px) { 29 | &:hover { 30 | color: purple; 31 | } 32 | } 33 | `; 34 | 35 | describe('toNotHaveStyleRule', () => { 36 | const getMessage = ({ 37 | selector, 38 | value, 39 | } = {}) => 40 | `Expected ${selector} to not exists but received:\n\t${chalk.red(value)}`; 41 | 42 | test('should pass if property is not present', () => { 43 | const component = ReactTestRenderer.create(