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

Commit

Permalink
feat: update style options and document them well
Browse files Browse the repository at this point in the history
  • Loading branch information
bahmutov committed Apr 9, 2020
1 parent 1d2c411 commit d1aece8
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 35 deletions.
40 changes: 24 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ describe('HelloState component', () => {

### styles

If you component imports its own style, the style should be applied during the Cypress test. But sometimes you need more power.

You can 3 options to load additional styles:

```js
mount(<Component />, {
style: string, // load inline style CSS
cssFiles: string | string[], // load a single or a list of local CSS files
stylesheets: string | string[] // load external stylesheets
})
```

#### Inline styles

You can add individual style to the mounted component by passing its text as an option

```js
Expand All @@ -89,31 +103,25 @@ it('can be passed as an option', () => {
})
```

Often your component rely on global CSS style imported from the root `index.js` or `app.js` file
#### Load local CSS file

```js
// index.js
import './styles.css'
// bootstrap application
const cssFiles = 'cypress/integration/Button.css'
cy.mount(<Button name="Orange" orange />, { cssFiles })
```

You can read the CSS file and pass it as `style` option yourself

```js
cy.readFile('cypress/integration/Button.css').then(style => {
cy.mount(<Button name="Orange" orange />, { style })
})
```
See [cypress/integration/inject-style-spec.js](cypress/integration/inject-style-spec.js) for more examples.

You can even let Cypress read the file and inject the style
#### Load external stylesheets

```js
const cssFile = 'cypress/integration/Button.css'
cy.mount(<Button name="Orange" orange />, { cssFile })
mount(<Todo todo={todo} />, {
stylesheets: [
'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.css',
],
})
```

See [cypress/integration/inject-style-spec.js](cypress/integration/inject-style-spec.js) for more examples.

## Configuration

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:
Expand Down
3 changes: 3 additions & 0 deletions cypress/component/component tests/basic/css-file/base.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
button {
height: 50px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,35 @@ describe('cssFile', () => {
it('is loaded', () => {
const Component = () => <button className="green">Green button</button>
mount(<Component />, {
cssFile: 'cypress/component/component tests/basic/css-file/index.css',
cssFiles: 'cypress/component/component tests/basic/css-file/index.css',
})

cy.get('button')
.should('have.class', 'green')
.and('have.css', 'background-color', 'rgb(0, 255, 0)')
})

it('allows loading several CSS files', () => {
const Component = () => (
<button className="green">Large green button</button>
)
mount(<Component />, {
cssFiles: [
'cypress/component/component tests/basic/css-file/base.css',
'cypress/component/component tests/basic/css-file/index.css',
],
})

// check the style from the first css file
cy.get('button')
.should('have.class', 'green')
.invoke('css', 'height')
.should(value => {
// round the height, since in real browser it is never exactly 50
expect(parseFloat(value), 'height is 50px').to.be.closeTo(50, 1)
})

// and should have style from the second css file
cy.get('button').and('have.css', 'background-color', 'rgb(0, 255, 0)')
})
})
2 changes: 1 addition & 1 deletion lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface ReactModule {
interface StyleOptions {
stylesheets: string | string[]
style: string
cssFile: string
cssFiles: string | string[]
}

interface MountReactComponentOptions {
Expand Down
77 changes: 60 additions & 17 deletions lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,55 @@
/**
* Insert links to external style resources.
*/
function insertStylesheets(
stylesheets: string[],
document: Document,
el: HTMLElement,
) {
stylesheets.forEach(href => {
const link = document.createElement('link')
link.type = 'text/css'
link.rel = 'stylesheet'
link.href = href
document.body.insertBefore(link, el)
})
}

/**
* Inserts a single stylesheet element
*/
function insertStyles(style: string, document: Document, el: HTMLElement) {
const styleElement = document.createElement('style')
styleElement.appendChild(document.createTextNode(style))
document.body.insertBefore(styleElement, el)
}

function insertSingleCssFile(
cssFilename: string,
document: Document,
el: HTMLElement,
) {
return cy.readFile(cssFilename).then(css => {
const style = document.createElement('style')
style.appendChild(document.createTextNode(css))
document.body.insertBefore(style, el)
})
}

/**
* Reads the given CSS file from local file system
* and adds the loaded style text as an element.
*/
function insertLocalCssFiles(
cssFilenames: string[],
document: Document,
el: HTMLElement,
) {
return Cypress.Promise.mapSeries(cssFilenames, cssFilename =>
insertSingleCssFile(cssFilename, document, el),
)
}

/**
* Injects custom style text or CSS file or 3rd party style resources
* into the given document.
Expand All @@ -12,27 +64,18 @@ export const injectStylesBeforeElement = (
options.stylesheets = [options.stylesheets]
}
if (Array.isArray(options.stylesheets)) {
// console.log('adding stylesheets')
options.stylesheets.forEach(href => {
const link = document.createElement('link')
link.type = 'text/css'
link.rel = 'stylesheet'
link.href = href
document.body.insertBefore(link, el)
})
insertStylesheets(options.stylesheets, document, el)
}

if (options.style) {
const style = document.createElement('style')
style.appendChild(document.createTextNode(options.style))
document.body.insertBefore(style, el)
insertStyles(options.style, document, el)
}

if (Array.isArray(options.cssFiles)) {
return insertLocalCssFiles(options.cssFiles, document, el)
}

if (options.cssFile) {
return cy.readFile(options.cssFile).then(css => {
const style = document.createElement('style')
style.appendChild(document.createTextNode(css))
document.body.insertBefore(style, el)
})
if (typeof options.cssFiles === 'string') {
return insertSingleCssFile(options.cssFiles, document, el)
}
}

0 comments on commit d1aece8

Please sign in to comment.