Skip to content

Commit

Permalink
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-life…
Browse files Browse the repository at this point in the history
…cycle

* 10.0-release:
  build: remove syncRemoteGraphQL from codegen
  chore: fix incorrect type from merge
  build: allow work with local dashboard (#19376)
  chore: Test example recipes against chrome (#19362)
  test(unify): Settings e2e tests (#19324)
  chore(deps): update dependency ssri to 6.0.2 [security] (#19351)
  fix: spec from story generation, add deps for install (#19352)
  chore: Fix server unit tests running on mac by using actual tmp dir (#19350)
  fix: Add more precise types to Cypress.Commands (#19003)
  fix: Do not screenshot or trigger the failed event when tests are skipped (#19331)
  fix (#19262)
  fix: throw when writing to 'read only' properties of `config` (#18896)
  fix: close chrome when closing electron (#19322)
  fix: disable automatic request retries (#19161)
  chore: refactor cy funcs (#19080)
  chore(deps): update dependency @ffmpeg-installer/ffmpeg to v1.1.0 🌟 (#19300)
  • Loading branch information
tgriesser committed Dec 15, 2021
2 parents 2b7c02c + eda638e commit 92842dd
Show file tree
Hide file tree
Showing 91 changed files with 2,310 additions and 1,516 deletions.
12 changes: 12 additions & 0 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1999,6 +1999,14 @@ jobs:
repo: cypress-example-recipes
command: npm run test:ci:firefox

"test-binary-against-recipes-chrome":
<<: *defaults
steps:
- test-binary-against-repo:
repo: cypress-example-recipes
browser: chrome
command: npm run test:ci:chrome

# This is a special job. It allows you to test the current
# built test runner against a pull request in the repo
# cypress-example-recipes.
Expand Down Expand Up @@ -2427,6 +2435,10 @@ linux-workflow: &linux-workflow
<<: *mainBuildFilters
requires:
- create-build-artifacts
- test-binary-against-recipes-chrome:
<<: *mainBuildFilters
requires:
- create-build-artifacts
- test-binary-against-kitchensink-firefox:
<<: *mainBuildFilters
requires:
Expand Down
52 changes: 45 additions & 7 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,38 @@ declare namespace Cypress {
type HttpMethod = string
type RequestBody = string | object
type ViewportOrientation = 'portrait' | 'landscape'
type PrevSubject = 'optional' | 'element' | 'document' | 'window'
type PrevSubject = keyof PrevSubjectMap
type TestingType = 'e2e' | 'component'
type PluginConfig = (on: PluginEvents, config: PluginConfigOptions) => void | ConfigOptions | Promise<ConfigOptions>

interface PrevSubjectMap<O = unknown> {
optional: O
element: JQuery
document: Document
window: Window
}

interface CommandOptions {
prevSubject: boolean | PrevSubject | PrevSubject[]
}
interface CommandFn<T extends keyof ChainableMethods> {
(this: Mocha.Context, ...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]> | void
}
interface CommandFnWithSubject<T extends keyof ChainableMethods, S> {
(this: Mocha.Context, prevSubject: S, ...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]> | void
}
interface CommandOriginalFn<T extends keyof ChainableMethods> extends CallableFunction {
(...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]>
}
interface CommandOriginalFnWithSubject<T extends keyof ChainableMethods, S> extends CallableFunction {
(prevSubject: S, ...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]>
}
interface CommandFnWithOriginalFn<T extends keyof Chainable> {
(this: Mocha.Context, originalFn: CommandOriginalFn<T>, ...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]> | void
}
interface CommandFnWithOriginalFnAndSubject<T extends keyof Chainable, S> {
(this: Mocha.Context, originalFn: CommandOriginalFnWithSubject<T, S>, prevSubject: S, ...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]> | void
}
interface ObjectLike {
[key: string]: any
}
Expand Down Expand Up @@ -328,7 +353,7 @@ declare namespace Cypress {
// 60000
```
*/
config<K extends keyof ConfigOptions>(key: K): ResolvedConfigOptions[K]
config<K extends keyof Config>(key: K): Config[K]
/**
* Sets one configuration value.
* @see https://on.cypress.io/config
Expand All @@ -337,7 +362,7 @@ declare namespace Cypress {
Cypress.config('viewportWidth', 800)
```
*/
config<K extends keyof ConfigOptions>(key: K, value: ResolvedConfigOptions[K]): void
config<K extends keyof TestConfigOverrides>(key: K, value: TestConfigOverrides[K]): void
/**
* Sets multiple configuration values at once.
* @see https://on.cypress.io/config
Expand Down Expand Up @@ -420,9 +445,16 @@ declare namespace Cypress {
* @see https://on.cypress.io/api/commands
*/
Commands: {
add<T extends keyof Chainable>(name: T, fn: Chainable[T]): void
add<T extends keyof Chainable>(name: T, options: CommandOptions, fn: Chainable[T]): void
overwrite<T extends keyof Chainable>(name: T, fn: Chainable[T]): void
add<T extends keyof Chainable>(name: T, fn: CommandFn<T>): void
add<T extends keyof Chainable>(name: T, options: CommandOptions & {prevSubject: false}, fn: CommandFn<T>): void
add<T extends keyof Chainable, S extends PrevSubject>(
name: T, options: CommandOptions & { prevSubject: true | S | ['optional'] }, fn: CommandFnWithSubject<T, PrevSubjectMap[S]>,
): void
add<T extends keyof Chainable, S extends PrevSubject>(
name: T, options: CommandOptions & { prevSubject: S[] }, fn: CommandFnWithSubject<T, PrevSubjectMap<void>[S]>,
): void
overwrite<T extends keyof Chainable>(name: T, fn: CommandFnWithOriginalFn<T>): void
overwrite<T extends keyof Chainable, S extends PrevSubject>(name: T, fn: CommandFnWithOriginalFnAndSubject<T, PrevSubjectMap[S]>): void
}

/**
Expand Down Expand Up @@ -2248,6 +2280,12 @@ declare namespace Cypress {
$$<TElement extends Element = HTMLElement>(selector: JQuery.Selector, context?: Element | Document | JQuery): JQuery<TElement>
}

type ChainableMethods<Subject = any> = {
[P in keyof Chainable<Subject>]: Chainable<Subject>[P] extends ((...args: any[]) => any)
? Chainable<Subject>[P]
: never
}

interface SinonSpyAgent<A extends sinon.SinonSpy> {
log(shouldOutput?: boolean): Omit<A, 'withArgs'> & Agent<A>

Expand Down Expand Up @@ -2884,7 +2922,7 @@ declare namespace Cypress {
xhrUrl: string
}

interface TestConfigOverrides extends Partial<Pick<ConfigOptions, 'animationDistanceThreshold' | 'baseUrl' | 'defaultCommandTimeout' | 'env' | 'execTimeout' | 'includeShadowDom' | 'requestTimeout' | 'responseTimeout' | 'retries' | 'scrollBehavior' | 'taskTimeout' | 'viewportHeight' | 'viewportWidth' | 'waitForAnimations'>> {
interface TestConfigOverrides extends Partial<Pick<ConfigOptions, 'animationDistanceThreshold' | 'baseUrl' | 'blockHosts' | 'defaultCommandTimeout' | 'env' | 'execTimeout' | 'includeShadowDom' | 'numTestsKeptInMemory' | 'pageLoadTimeout' | 'redirectionLimit' | 'requestTimeout' | 'responseTimeout' | 'retries' | 'screenshotOnRunFailure' | 'slowTestThreshold' | 'scrollBehavior' | 'taskTimeout' | 'viewportHeight' | 'viewportWidth' | 'waitForAnimations'>> {
browser?: IsBrowserMatcher | IsBrowserMatcher[]
keystrokeDelay?: number
}
Expand Down
102 changes: 94 additions & 8 deletions cli/types/tests/cypress-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ namespace CypressIsCyTests {

declare namespace Cypress {
interface Chainable {
newCommand: (arg: string) => void
newCommand: (arg: string) => Chainable<number>
}
}

Expand All @@ -74,20 +74,106 @@ namespace CypressCommandsTests {
arg
return
})
Cypress.Commands.add('newCommand', { prevSubject: true }, (arg) => {
Cypress.Commands.add('newCommand', (arg) => {
// $ExpectType string
arg
})
Cypress.Commands.add('newCommand', function(arg) {
this // $ExpectType Context
arg // $ExpectType string
})
Cypress.Commands.add('newCommand', { prevSubject: true }, (subject, arg) => {
subject // $ExpectType unknown
arg // $ExpectType string
return
})
Cypress.Commands.add('newCommand', (arg) => {
// $ExpectType string
arg
return new Promise((resolve) => {})
Cypress.Commands.add('newCommand', { prevSubject: false }, (arg) => {
arg // $ExpectType string
return
})
Cypress.Commands.add('newCommand', { prevSubject: 'optional' }, (subject, arg) => {
subject // $ExpectType unknown
arg // $ExpectType string
return
})
Cypress.Commands.overwrite('newCommand', (arg) => {
Cypress.Commands.add('newCommand', { prevSubject: 'optional' }, (subject, arg) => {
subject // $ExpectType unknown
arg // $ExpectType string
})
Cypress.Commands.add('newCommand', { prevSubject: ['optional'] }, (subject, arg) => {
subject // $ExpectType unknown
arg // $ExpectType string
})
Cypress.Commands.add('newCommand', { prevSubject: 'document' }, (subject, arg) => {
subject // $ExpectType Document
arg // $ExpectType string
})
Cypress.Commands.add('newCommand', { prevSubject: 'window' }, (subject, arg) => {
subject // $ExpectType Window
arg // $ExpectType string
})
Cypress.Commands.add('newCommand', { prevSubject: 'element' }, (subject, arg) => {
subject // $ExpectType JQuery<HTMLElement>
arg // $ExpectType string
})
Cypress.Commands.add('newCommand', { prevSubject: ['element'] }, (subject, arg) => {
subject // $ExpectType JQuery<HTMLElement>
arg // $ExpectType string
})
Cypress.Commands.add('newCommand', { prevSubject: ['element', 'document', 'window'] }, (subject, arg) => {
if (subject instanceof Window) {
subject // $ExpectType Window
} else if (subject instanceof Document) {
subject // $ExpectType Document
} else {
subject // $ExpectType JQuery<HTMLElement>
}
arg // $ExpectType string
})
Cypress.Commands.add('newCommand', { prevSubject: ['window', 'document', 'optional', 'element'] }, (subject, arg) => {
if (subject instanceof Window) {
subject // $ExpectType Window
} else if (subject instanceof Document) {
subject // $ExpectType Document
} else if (subject) {
subject // $ExpectType JQuery<HTMLElement>
} else {
subject // $ExpectType void
}
arg // $ExpectType string
})
Cypress.Commands.add('newCommand', (arg) => {
// $ExpectType string
arg
return
return cy.wrap(new Promise<number>((resolve) => { resolve(5) }))
})
Cypress.Commands.overwrite('newCommand', (originalFn, arg) => {
arg // $ExpectType string
originalFn // $ExpectedType Chainable['newCommand']
originalFn(arg) // $ExpectType Chainable<number>
})
Cypress.Commands.overwrite('newCommand', function(originalFn, arg) {
this // $ExpectType Context
arg // $ExpectType string
originalFn // $ExpectedType Chainable['newCommand']
originalFn.apply(this, [arg]) // $ExpectType Chainable<number>
})
Cypress.Commands.overwrite<'type', 'element'>('type', (originalFn, element, text, options?: Partial<Cypress.TypeOptions & {sensitive: boolean}>) => {
element // $ExpectType JQuery<HTMLElement>
text // $ExpectType string

if (options && options.sensitive) {
// turn off original log
options.log = false
// create our own log with masked message
Cypress.log({
$el: element,
name: 'type',
message: '*'.repeat(text.length),
})
}

return originalFn(element, text, options)
})
}

Expand Down
2 changes: 1 addition & 1 deletion npm/vite-dev-server/src/startServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const resolveServerConfig = async ({ viteConfig, options, indexHtml }: StartDevS

finalConfig.server = finalConfig.server || {}

finalConfig.server.port = await getPort({ port: finalConfig.server.port || 3000, host: 'localhost' }),
finalConfig.server.port = await getPort({ port: finalConfig.server.port || 3000 }),

// Ask vite to pre-optimize all dependencies of the specs
finalConfig.optimizeDeps = finalConfig.optimizeDeps || {}
Expand Down
71 changes: 71 additions & 0 deletions packages/app/cypress/e2e/integration/code-gen.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import defaultMessages from '@packages/frontend-shared/src/locales/en-US.json'

const extensionInputSelector = `[placeholder="${defaultMessages.components.fileSearch.byExtensionInput}"]`

describe('Code Generation', () => {
beforeEach(() => {
cy.scaffoldProject('react-code-gen')
cy.openProject('react-code-gen')
cy.startAppServer('component')
cy.visitApp()
})

const checkCodeGenCandidates = (specs: string[]) => {
cy.findByTestId('file-match-indicator').contains(`${specs.length} Match${specs.length > 1 ? 'es' : ''}`)
cy.findAllByTestId('file-list-row').should('have.length', specs.length)
.each((row, i) => cy.wrap(row).contains(specs[i]))
}

it('should generate spec from component', () => {
cy.findByTestId('new-spec-button').click()
cy.findByTestId('create-spec-modal').should('be.visible').within(() => {
cy.contains('Create a new spec').should('be.visible')
cy.get('[data-cy="external"]').should('have.attr', 'href', 'https://on.cypress.io')
})

cy.contains('Create from component').click()
const componentGlob = '**/*.{jsx,tsx}'

cy.findByTestId('file-match-button').contains(componentGlob)
checkCodeGenCandidates(['App.cy.jsx', 'App.jsx', 'index.jsx', 'Button.jsx', 'Button.stories.jsx'])

cy.intercept('query-ComponentGeneratorStepOne').as('code-gen-candidates')
cy.findByTestId('file-match-button').click()
cy.get(extensionInputSelector).clear().type('**/App.*')
cy.wait('@code-gen-candidates')

checkCodeGenCandidates(['App.css', 'App.cy.jsx', 'App.jsx'])

cy.get(extensionInputSelector).clear().type(componentGlob, { parseSpecialCharSequences: false })
cy.contains('Button.jsx').click()
cy.findByTestId('file-row').contains('src/stories/Button.cy.js').click()

cy.withCtx(async (ctx) => {
const spec = await (await ctx.project.findSpecs(ctx.currentProject?.projectRoot ?? '', 'component'))
.find((spec) => spec.relative === 'src/stories/Button.cy.jsx')

expect(spec).to.exist
})
})

it('should generate spec from story', () => {
cy.findByTestId('new-spec-button').click()

cy.contains('Create from story').click()
const storyGlob = '**/*.stories.*'

cy.findByTestId('file-match-button').contains(storyGlob)
checkCodeGenCandidates(['Button.stories.jsx'])

cy.contains('Button.stories.jsx').click()
cy.findByTestId('file-row').contains('src/stories/Button.stories.cy.js').click()
cy.contains('composeStories')

cy.withCtx(async (ctx) => {
const spec = await (await ctx.project.findSpecs(ctx.currentProject?.projectRoot ?? '', 'component'))
.find((spec) => spec.relative === 'src/stories/Button.stories.cy.jsx')

expect(spec).to.exist
})
})
})

0 comments on commit 92842dd

Please sign in to comment.