Skip to content
This repository was archived by the owner on Mar 5, 2022. It is now read-only.

Commit 72799e2

Browse files
committed
feat: add style option
1 parent a7916c3 commit 72799e2

File tree

4 files changed

+134
-2
lines changed

4 files changed

+134
-2
lines changed

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,47 @@ describe('HelloState component', () => {
6363

6464
![Unit testing React components](images/demo.png)
6565

66+
### styles
67+
68+
You can add individual style to the mounted component by passing its text as an option
69+
70+
```js
71+
it('can be passed as an option', () => {
72+
const style = `
73+
.component-button {
74+
display: inline-flex;
75+
width: 25%;
76+
flex: 1 0 auto;
77+
}
78+
79+
.component-button.orange button {
80+
background-color: #F5923E;
81+
color: white;
82+
}
83+
`
84+
cy.mount(<Button name='Orange' orange />, null, { style })
85+
cy.get('.orange button')
86+
.should('have.css', 'background-color', 'rgb(245, 146, 62)')
87+
})
88+
```
89+
90+
Often your component rely on global CSS style imported from the root `index.js` or `app.js` file
91+
92+
```js
93+
// index.js
94+
import './styles.css'
95+
// bootstrap application
96+
```
97+
98+
You can read the CSS file and pass it as `style` option yourself
99+
100+
```js
101+
cy.readFile('cypress/integration/Button.css')
102+
.then(style => {
103+
cy.mount(<Button name='Orange' orange />, null, { style })
104+
})
105+
```
106+
66107
## Configuration
67108

68109
If your React and React DOM libraries are installed in non-standard paths (think monorepo scenario), you can tell this plugin where to find them. In `cypress.json` specify paths like this:
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/// <reference types="cypress" />
2+
import React from 'react'
3+
4+
class Button extends React.Component {
5+
handleClick () {
6+
this.props.clickHandler(this.props.name)
7+
}
8+
9+
render () {
10+
const className = [
11+
'component-button',
12+
this.props.orange ? 'orange' : '',
13+
this.props.wide ? 'wide' : ''
14+
]
15+
16+
return (
17+
<div className={className.join(' ').trim()}>
18+
<button onClick={this.handleClick.bind(this)}>{this.props.name}</button>
19+
</div>
20+
)
21+
}
22+
}
23+
24+
describe('Injecting style', () => {
25+
it('can be passed as an option', () => {
26+
const style = `
27+
.component-button {
28+
display: inline-flex;
29+
width: 25%;
30+
flex: 1 0 auto;
31+
}
32+
33+
.component-button.orange button {
34+
background-color: #F5923E;
35+
color: white;
36+
}
37+
`
38+
cy.mount(<Button name='Orange' orange />, null, { style })
39+
cy.get('.orange button')
40+
.should('have.css', 'background-color', 'rgb(245, 146, 62)')
41+
})
42+
43+
it('read CSS file and pass as style', () => {
44+
cy.readFile('cypress/integration/Button.css')
45+
.then(style => {
46+
cy.mount(<Button name='Orange' orange />, null, { style })
47+
})
48+
49+
cy.get('.component-button')
50+
.should('have.class', 'orange')
51+
.find('button')
52+
.should('have.css', 'background-color', 'rgb(245, 146, 62)')
53+
})
54+
55+
context('read CSS file once', () => {
56+
before(() => {
57+
// .as('style') will save the loaded CSS text
58+
// in the text context property "style"
59+
cy.readFile('cypress/integration/Button.css').as('style')
60+
})
61+
62+
it('is orange', function () {
63+
// notice we use "function () {}" callback
64+
// to get the test context "this" to be able to use "this.style"
65+
cy.mount(<Button name='Orange' orange />, null, { style: this.style })
66+
67+
cy.get('.orange button')
68+
.should('have.css', 'background-color', 'rgb(245, 146, 62)')
69+
})
70+
71+
it('is orange again', function () {
72+
cy.mount(<Button name='Orange' orange />, null, { style: this.style })
73+
74+
cy.get('.orange button')
75+
.should('have.css', 'background-color', 'rgb(245, 146, 62)')
76+
})
77+
})
78+
})

lib/index.d.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ interface JSXElement {
2424
props: object
2525
}
2626

27+
interface MountOptions {
28+
style: string
29+
}
30+
2731
declare namespace Cypress {
2832
interface Cypress {
2933
stylesCache: any
@@ -58,7 +62,7 @@ declare namespace Cypress {
5862
cy.get(Hello)
5963
```
6064
**/
61-
mount: (component: JSXElement, alias?: string) => Chainable<void>
65+
mount: (component: JSXElement, alias?: string, options?: Partial<MountOptions>) => Chainable<void>
6266
get<S = any>(alias: string | symbol | Function, options?: Partial<Loggable & Timeoutable>): Chainable<any>
6367
}
6468
}

lib/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ Cypress.Commands.add('copyComponentStyles', component => {
8787
})
8888
})
8989

90+
const injectStyle = (options?: Partial<MountOptions>) => (w: Window) => {
91+
if (options && options.style) {
92+
const style = w.document.createElement('style')
93+
style.appendChild(document.createTextNode(options.style))
94+
w.document.body.appendChild(style)
95+
}
96+
}
97+
9098
/**
9199
* Mount a React component in a blank document; register it as an alias
92100
* To access: use an alias or original component reference
@@ -106,7 +114,7 @@ Cypress.Commands.add('copyComponentStyles', component => {
106114
cy.get(Hello)
107115
```
108116
**/
109-
export const mount = (jsx: JSXElement, alias?: string) => {
117+
export const mount = (jsx: JSXElement, alias?: string, options?: Partial<MountOptions>) => {
110118
// Get the display name property via the component constructor
111119
const jsxType = typeof jsx.type === 'string' ? jsx as unknown as JSX : jsx.type
112120
const displayname = getDisplayName(jsxType, alias)
@@ -127,6 +135,7 @@ export const mount = (jsx: JSXElement, alias?: string) => {
127135
}
128136
})
129137
})
138+
.then(injectStyle(options))
130139
.then(setXMLHttpRequest)
131140
.then(setAlert)
132141
.then(win => {

0 commit comments

Comments
 (0)