From bcf8e825a4f522293f8da6de2fc63d1e6fdf54c5 Mon Sep 17 00:00:00 2001 From: Dan Adajian Date: Wed, 10 Aug 2022 17:30:57 -0500 Subject: [PATCH] chore: fix prettier and use strict mode (#52) fix prettier and use strict mode --- .prettierrc.json | 1 + CONTRIBUTING.md | 4 +- README.md | 48 +++++++------- cypress/commands/custom-mount.tsx | 20 +++--- cypress/component/component-example.cy.tsx | 64 +++++++++---------- cypress/support/component-index.html | 18 +++--- package-lock.json | 59 +++++++++++++++++ package.json | 1 + src/common.ts | 2 +- ...enerate-types-from-abstract-syntax-tree.ts | 13 ++-- src/index.ts | 48 ++++++++------ src/plugin.ts | 2 +- tsconfig.json | 1 + 13 files changed, 177 insertions(+), 104 deletions(-) diff --git a/.prettierrc.json b/.prettierrc.json index 41987a37..bdef9447 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,5 +1,6 @@ { "printWidth": 100, + "tabWidth": 2, "useTabs": false, "singleQuote": true, "trailingComma": "none", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 607bd23b..72fc8492 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ Push your changes to your branch and open a pull request against the parent repo Upon Pull Request submission, your code will be reviewed by the maintainers. They will confirm at least the following: -- Tests run successfully (unit, coverage, integration, style). -- Contribution policy has been followed. +- Tests run successfully (unit, coverage, integration, style). +- Contribution policy has been followed. One (human) reviewer will need to sign off on your Pull Request before it can be merged. diff --git a/README.md b/README.md index 1624aa6b..5933ed36 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,11 @@ A [Cypress](https://www.cypress.io/) plugin which automatically adds and enables ## Table of Contents -- [Why Do I Need This Plugin?](#why-do-i-need-this-plugin) -- [Installation](#installation) -- [Usage](#usage) -- [Example](#example) -- [Configuration](#configuration) +- [Why Do I Need This Plugin?](#why-do-i-need-this-plugin) +- [Installation](#installation) +- [Usage](#usage) +- [Example](#example) +- [Configuration](#configuration) ## Why Do I Need This Plugin? @@ -37,23 +37,23 @@ import { cypressCodegen } from 'cypress-codegen/dist/plugin'; import { defineConfig } from 'cypress'; export default defineConfig({ - e2e: { - setupNodeEvents(on, config) { - cypressCodegen(on, config); - return config; - } - }, + e2e: { + setupNodeEvents(on, config) { + cypressCodegen(on, config); + return config; + } + }, - component: { - setupNodeEvents(on, config) { - cypressCodegen(on, config); - return config; - }, - devServer: { - framework: 'create-react-app', - bundler: 'webpack' - } + component: { + setupNodeEvents(on, config) { + cypressCodegen(on, config); + return config; + }, + devServer: { + framework: 'create-react-app', + bundler: 'webpack' } + } }); ``` @@ -66,8 +66,8 @@ import 'cypress-codegen'; 3. Put all of your custom commands in `cypress/commands` as regular functions. It is recommended to separate each command into its own file of the same name. 4. Run any Cypress test, and `cypress-codegen` will: - - load these functions as valid custom commands - - generate a special Cypress type definition for each function which will enable IntelliSense and "go to definition" shortcuts in your Cypress test code + - load these functions as valid custom commands + - generate a special Cypress type definition for each function which will enable IntelliSense and "go to definition" shortcuts in your Cypress test code ## Example @@ -102,7 +102,7 @@ In cypress.config.ts: ```ts env: { - PROJECT: 'my-project'; + PROJECT: 'my-project'; } ``` @@ -120,6 +120,6 @@ or in `cypress.config.js`: ```ts env: { - CODEGEN: false; + CODEGEN: false; } ``` diff --git a/cypress/commands/custom-mount.tsx b/cypress/commands/custom-mount.tsx index 36caf447..a9c38708 100644 --- a/cypress/commands/custom-mount.tsx +++ b/cypress/commands/custom-mount.tsx @@ -1,17 +1,17 @@ import * as React from 'react'; -export const customMount = (Component: React.ReactElement) => { - cy.mount( -
- -
- ); +export const customMount = (Component: React.FC) => { + cy.mount( +
+ +
+ ); }; declare global { - namespace Cypress { - interface Chainable { - customMount(Component: React.ReactElement): Chainable; - } + namespace Cypress { + interface Chainable { + customMount(Component: React.FC): Chainable; } + } } diff --git a/cypress/component/component-example.cy.tsx b/cypress/component/component-example.cy.tsx index 65805f2d..f51e77f6 100644 --- a/cypress/component/component-example.cy.tsx +++ b/cypress/component/component-example.cy.tsx @@ -16,36 +16,36 @@ import * as React from 'react'; const componentText = 'Here is a component'; describe('Example Test', () => { - beforeEach(() => { - cy.mount(

{componentText}

); - }); - - it('should import custom commands in component tests', () => { - cy.functionExample(componentText); - }); - - it('should dynamically import custom commands from arrow functions', () => { - cy.arrowFunctionExample(componentText); - }); - - it('should support scoped methods', () => { - cy.contains(componentText).functionExampleScoped(componentText); - }); - - it('should dynamically import nested custom commands', () => { - cy.nestedExample(componentText); - }); - - it('should chain custom commands', () => { - cy.log(componentText) - .functionExample(componentText) - .arrowFunctionExample(componentText) - .nestedExample(componentText); - }); - - it('should support custom mount commands', () => { - const myComponent = () => <>{'Different text'}; - cy.customMount(myComponent); - cy.contains('Different text'); - }); + beforeEach(() => { + cy.mount(

{componentText}

); + }); + + it('should import custom commands in component tests', () => { + cy.functionExample(componentText); + }); + + it('should dynamically import custom commands from arrow functions', () => { + cy.arrowFunctionExample(componentText); + }); + + it('should support scoped methods', () => { + cy.contains(componentText).functionExampleScoped(componentText); + }); + + it('should dynamically import nested custom commands', () => { + cy.nestedExample(componentText); + }); + + it('should chain custom commands', () => { + cy.log(componentText) + .functionExample(componentText) + .arrowFunctionExample(componentText) + .nestedExample(componentText); + }); + + it('should support custom mount commands', () => { + const myComponent = () => <>{'Different text'}; + cy.customMount(myComponent); + cy.contains('Different text'); + }); }); diff --git a/cypress/support/component-index.html b/cypress/support/component-index.html index 3d489995..e39ba429 100644 --- a/cypress/support/component-index.html +++ b/cypress/support/component-index.html @@ -1,12 +1,12 @@ - - - - - Components App - - -
- + + + + + Components App + + +
+ diff --git a/package-lock.json b/package-lock.json index a97414df..dee4e981 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "devDependencies": { "@types/glob": "7.2.0", "@types/jest": "28.1.6", + "@types/react": "18.0.17", "cypress": "10.4.0", "eslint": "8.21.0", "eslint-plugin-cypress": "2.12.1", @@ -4051,6 +4052,12 @@ "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", "dev": true }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true + }, "node_modules/@types/q": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", @@ -4069,6 +4076,17 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "node_modules/@types/react": { + "version": "18.0.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.17.tgz", + "integrity": "sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -4084,6 +4102,12 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true + }, "node_modules/@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -6930,6 +6954,12 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", "dev": true }, + "node_modules/csstype": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", + "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==", + "dev": true + }, "node_modules/cypress": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.4.0.tgz", @@ -26234,6 +26264,12 @@ "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", "dev": true }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true + }, "@types/q": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.5.tgz", @@ -26252,6 +26288,17 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "@types/react": { + "version": "18.0.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.17.tgz", + "integrity": "sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -26267,6 +26314,12 @@ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true + }, "@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -28304,6 +28357,12 @@ } } }, + "csstype": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", + "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==", + "dev": true + }, "cypress": { "version": "10.4.0", "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.4.0.tgz", diff --git a/package.json b/package.json index 887b0784..ebecc212 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "devDependencies": { "@types/glob": "7.2.0", "@types/jest": "28.1.6", + "@types/react": "18.0.17", "cypress": "10.4.0", "eslint": "8.21.0", "eslint-plugin-cypress": "2.12.1", diff --git a/src/common.ts b/src/common.ts index e938459e..a87d0b68 100644 --- a/src/common.ts +++ b/src/common.ts @@ -13,4 +13,4 @@ limitations under the License. export const COMMANDS_DIRECTORY = 'cypress/commands'; -export const isScopedMethod = (methodName: string) => methodName.endsWith('Scoped'); +export const isScopedMethod = (methodName?: string) => methodName?.endsWith('Scoped'); diff --git a/src/generate-types-from-abstract-syntax-tree.ts b/src/generate-types-from-abstract-syntax-tree.ts index 34397fb7..7bf8327b 100644 --- a/src/generate-types-from-abstract-syntax-tree.ts +++ b/src/generate-types-from-abstract-syntax-tree.ts @@ -28,7 +28,7 @@ import { resolve } from 'path'; import { format, Options } from 'prettier'; import { isScopedMethod } from './common'; -export const generateTypesFromAbstractSyntaxTree = (filePath: string, prettierConfig?: Options) => { +export const generateTypesFromAbstractSyntaxTree = (filePath: string, prettierConfig: Options) => { const contents = readFileSync(resolve(filePath)).toString(); const ast = parse(contents, { sourceType: 'module', plugins: ['typescript', 'jsx'] }); const currentNodes = ast.program.body; @@ -38,8 +38,11 @@ export const generateTypesFromAbstractSyntaxTree = (filePath: string, prettierCo t.isExportNamedDeclaration(node) && (t.isFunctionDeclaration(node.declaration) || t.isVariableDeclaration(node.declaration)) ) - .map((node: ExportNamedDeclaration) => { - const declaration = node.declaration as FunctionDeclaration | VariableDeclaration; + .map(node => { + const exportNamedDeclaration = node as ExportNamedDeclaration; + const declaration = exportNamedDeclaration.declaration as + | FunctionDeclaration + | VariableDeclaration; const isVariableDeclaration = t.isVariableDeclaration(declaration); const functionIdentifier = isVariableDeclaration ? (declaration.declarations[0].id as Identifier) @@ -56,10 +59,10 @@ export const generateTypesFromAbstractSyntaxTree = (filePath: string, prettierCo const firstParamOmitted = parameters.slice(1); return { functionIdentifier, - parameters: isScopedMethod(functionIdentifier.name) ? firstParamOmitted : parameters + parameters: isScopedMethod(functionIdentifier?.name) ? firstParamOmitted : parameters }; }); - const newInterface = generateInterface(customCommands); + const newInterface = generateInterface(customCommands as CustomCommand[]); const lastNode = currentNodes[currentNodes.length - 1]; const interfaceExists = t.isTSModuleDeclaration(lastNode) && lastNode.global && lastNode.declare; const newNodes = interfaceExists ? currentNodes.slice(0, currentNodes.length - 1) : currentNodes; diff --git a/src/index.ts b/src/index.ts index 0eec3830..4e36747b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,26 +13,34 @@ limitations under the License. import { isScopedMethod } from './common'; +interface TaskResult { + filePaths: string[]; + commandsDirectory: string; +} + before('Import Custom Commands', () => { - cy.task('importCustomCommands').then( - ({ filePaths, commandsDirectory }: { filePaths: string[]; commandsDirectory: string }) => { - filePaths.forEach(filePath => { - const projectName = Cypress.env('PROJECT') ? `${Cypress.env('PROJECT')}/` : ''; - // This relative file path is extremely particular and for some unknown reason must be exactly this. - const customCommandObject = require(`../../../${projectName}cypress/commands/${filePath.replace( - commandsDirectory, - '' - )}`); - const methodNames = Object.keys(customCommandObject); - methodNames.forEach((methodName: keyof Cypress.Chainable) => { - const method = customCommandObject[methodName]; - if (isScopedMethod(methodName)) { - Cypress.Commands.add(methodName, { prevSubject: 'element' }, method); - } else { - Cypress.Commands.add(methodName, method); - } - }); + cy.task('importCustomCommands').then((result: unknown) => { + const { filePaths, commandsDirectory } = result as TaskResult; + filePaths.forEach(filePath => { + const projectName = Cypress.env('PROJECT') ? `${Cypress.env('PROJECT')}/` : ''; + // This relative file path is extremely particular and for some unknown reason must be exactly this. + const customCommandObject = require(`../../../${projectName}cypress/commands/${filePath.replace( + commandsDirectory, + '' + )}`); + const methodNames = Object.keys(customCommandObject); + methodNames.forEach(methodName => { + const method = customCommandObject[methodName]; + if (isScopedMethod(methodName)) { + Cypress.Commands.add( + methodName as keyof Cypress.Chainable, + { prevSubject: 'element' }, + method + ); + } else { + Cypress.Commands.add(methodName as keyof Cypress.Chainable, method); + } }); - } - ); + }); + }); }); diff --git a/src/plugin.ts b/src/plugin.ts index 9b0978dc..e5347037 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -32,7 +32,7 @@ export const cypressCodegen: CypressCodegen = ( if (config.env.CODEGEN !== false) { on('before:browser:launch', (browser, launchOptions) => { const filePaths = sync(`${COMMANDS_DIRECTORY}/**/*`, { nodir: true }); - const prettierConfig = prettierConfigOverride ?? resolveConfig.sync(process.cwd()); + const prettierConfig = prettierConfigOverride ?? resolveConfig.sync(process.cwd()) ?? {}; filePaths.forEach(filePath => { const fileContentsWithTypes = generateTypesFromAbstractSyntaxTree(filePath, prettierConfig); diff --git a/tsconfig.json b/tsconfig.json index 84a9ffac..4e05d8f8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,7 @@ "declaration": true, "module": "CommonJS", "sourceMap": true, + "strict": true, "target": "ES6", "lib": ["ES2019", "DOM"], "jsx": "react"