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

Commit 4e2f899

Browse files
nealeubahmutov
andauthored
feat: allow consuming projects to use noImplicitAny and fix JSX
* tsc: Enable noImplicitAny and fix type issues that showed up * Replace Symbol with JSXElement to address JSX.Element -> Symbol errors (#55) * tsc: Enable strictNullChecks and fix type issues that showed for some users * remove stray JSX Co-authored-by: Gleb Bahmutov <[email protected]>
1 parent 93e0fef commit 4e2f899

File tree

4 files changed

+77
-72
lines changed

4 files changed

+77
-72
lines changed

lib/getDisplayName.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export default function getDisplayName(type: JSX, fallbackName: string = 'Unknow
1515
return nameFromCache
1616
}
1717

18-
let displayName: string
18+
let displayName: string | null = null;
1919

2020
// The displayName property is not guaranteed to be a string.
2121
// It's only safe to use for our purposes if it's a string.

lib/index.d.ts

+64-59
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,64 @@
1-
// I hope to get types and docs from functions imported from ./index one day
2-
// but for now have to document methods in both places
3-
// like this: import {mount} from './index'
4-
5-
interface ReactModule {
6-
name: string
7-
type: string
8-
location: string
9-
source: string
10-
}
11-
12-
/**
13-
* The `type` property from the transpiled JSX object.
14-
* @example
15-
* const { type } = React.createElement('div', null, 'Hello')
16-
* const { type } = <div>Hello</div>
17-
*/
18-
interface JSX extends Function {
19-
displayName: string
20-
}
21-
22-
declare namespace Cypress {
23-
interface Cypress {
24-
stylesCache: any
25-
React: string
26-
ReactDOM: string
27-
Styles: string
28-
modules: ReactModule[]
29-
}
30-
31-
// NOTE: By default, avoiding React.Component/Element typings
32-
// for many cases, we don't want to import @types/react
33-
interface Chainable<Subject> {
34-
state: (key) => any,
35-
injectReactDOM: () => Chainable<void>
36-
copyComponentStyles: (component: Symbol) => Chainable<void>
37-
/**
38-
* Mount a React component in a blank document; register it as an alias
39-
* To access: use an alias or original component reference
40-
* @function cy.mount
41-
* @param {Object} jsx - component to mount
42-
* @param {string} [Component] - alias to use later
43-
* @example
44-
```
45-
import Hello from './hello.jsx'
46-
// mount and access by alias
47-
cy.mount(<Hello />, 'Hello')
48-
// using default alias
49-
cy.get('@Component')
50-
// using specified alias
51-
cy.get('@Hello').its('state').should(...)
52-
// using original component
53-
cy.get(Hello)
54-
```
55-
**/
56-
mount: (component: Symbol, alias?: string) => Chainable<void>
57-
get<S = any>(alias: string | symbol | Function, options?: Partial<Loggable & Timeoutable>): Chainable<any>
58-
}
59-
}
1+
// I hope to get types and docs from functions imported from ./index one day
2+
// but for now have to document methods in both places
3+
// like this: import {mount} from './index'
4+
5+
interface ReactModule {
6+
name: string
7+
type: string
8+
location: string
9+
source: string
10+
}
11+
12+
/**
13+
* The `type` property from the transpiled JSX object.
14+
* @example
15+
* const { type } = React.createElement('div', null, 'Hello')
16+
* const { type } = <div>Hello</div>
17+
*/
18+
interface JSX extends Function {
19+
displayName: string
20+
}
21+
22+
interface JSXElement {
23+
type: JSX
24+
props: object
25+
}
26+
27+
declare namespace Cypress {
28+
interface Cypress {
29+
stylesCache: any
30+
React: string
31+
ReactDOM: string
32+
Styles: string
33+
modules: ReactModule[]
34+
}
35+
36+
// NOTE: By default, avoiding React.Component/Element typings
37+
// for many cases, we don't want to import @types/react
38+
interface Chainable<Subject> {
39+
state: (key: any) => any,
40+
injectReactDOM: () => Chainable<void>
41+
copyComponentStyles: (component: JSXElement) => Chainable<void>
42+
/**
43+
* Mount a React component in a blank document; register it as an alias
44+
* To access: use an alias or original component reference
45+
* @function cy.mount
46+
* @param {Object} jsx - component to mount
47+
* @param {string} [Component] - alias to use later
48+
* @example
49+
```
50+
import Hello from './hello.jsx'
51+
// mount and access by alias
52+
cy.mount(<Hello />, 'Hello')
53+
// using default alias
54+
cy.get('@Component')
55+
// using specified alias
56+
cy.get('@Hello').its('state').should(...)
57+
// using original component
58+
cy.get(Hello)
59+
```
60+
**/
61+
mount: (component: JSXElement, alias?: string) => Chainable<void>
62+
get<S = any>(alias: string | symbol | Function, options?: Partial<Loggable & Timeoutable>): Chainable<any>
63+
}
64+
}

lib/index.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import getDisplayName from './getDisplayName';
66
// and "losing" styles when the next test starts
77
const stylesCache = new Map()
88

9-
const setXMLHttpRequest = w => {
9+
const setXMLHttpRequest = (w: Window) => {
1010
// by grabbing the XMLHttpRequest from app's iframe
1111
// and putting it here - in the test iframe
1212
// we suddenly get spying and stubbing 😁
@@ -15,7 +15,7 @@ const setXMLHttpRequest = w => {
1515
return w
1616
}
1717

18-
const setAlert = w => {
18+
const setAlert = (w: Window) => {
1919
window.alert = w.alert
2020
return w
2121
}
@@ -61,12 +61,12 @@ Cypress.Commands.add('copyComponentStyles', component => {
6161
// like component name
6262
const parentDocument = window.parent.document
6363
// @ts-ignore
64-
const specDocument = parentDocument.querySelector('iframe.spec-iframe').contentDocument
64+
const specDocument: Element = parentDocument.querySelector('iframe.spec-iframe').contentDocument
6565
// @ts-ignore
66-
const appDocument = parentDocument.querySelector('iframe.aut-iframe').contentDocument
66+
const appDocument: Element = parentDocument.querySelector('iframe.aut-iframe').contentDocument
6767

6868
const hash = component.type.name
69-
let styles = specDocument.querySelectorAll('head style')
69+
let styles: NodeListOf<Element> | null = specDocument.querySelectorAll('head style')
7070
if (styles.length) {
7171
cy.log(`injected ${styles.length} style(s)`)
7272
Cypress.stylesCache.set(hash, styles)
@@ -81,7 +81,7 @@ Cypress.Commands.add('copyComponentStyles', component => {
8181
if (!styles) {
8282
return
8383
}
84-
const head = appDocument.querySelector('head')
84+
const head = appDocument.querySelector('head')!
8585
styles.forEach(function (style) {
8686
head.appendChild(style)
8787
})
@@ -92,7 +92,7 @@ Cypress.Commands.add('copyComponentStyles', component => {
9292
* To access: use an alias or original component reference
9393
* @function cy.mount
9494
* @param {Object} jsx - component to mount
95-
* @param {string} [Component] - alias to use later
95+
* @param {string} alias [Component] - alias to use later
9696
* @example
9797
```
9898
import Hello from './hello.jsx'
@@ -106,11 +106,11 @@ Cypress.Commands.add('copyComponentStyles', component => {
106106
cy.get(Hello)
107107
```
108108
**/
109-
export const mount = (jsx, alias) => {
109+
export const mount = (jsx: JSXElement, alias?: string) => {
110110
// Get the display name property via the component constructor
111111
const displayname = getDisplayName(jsx.type, alias)
112112

113-
let cmd
113+
let cmd: Cypress.Log;
114114

115115
cy.injectReactDOM()
116116
.window({ log: false })
@@ -129,7 +129,7 @@ export const mount = (jsx, alias) => {
129129
.then(setXMLHttpRequest)
130130
.then(setAlert)
131131
.then(win => {
132-
const { ReactDOM } = win
132+
const { ReactDOM } = win as Window & {ReactDOM: any}
133133
const document = cy.state('document')
134134
const component = ReactDOM.render(
135135
jsx,

tsconfig.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020

2121
/* Strict Type-Checking Options */
2222
"strict": false, /* Enable all strict type-checking options. */
23-
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
24-
// "strictNullChecks": true, /* Enable strict null checks. */
23+
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
24+
"strictNullChecks": true, /* Enable strict null checks. */
2525
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
2626
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
2727
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */

0 commit comments

Comments
 (0)