Skip to content

Commit 92842dd

Browse files
committed
Merge branch '10.0-release' into tgriesser/10.0-release/refactor-lifecycle
* 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)
2 parents 2b7c02c + eda638e commit 92842dd

File tree

91 files changed

+2310
-1516
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+2310
-1516
lines changed

circle.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,14 @@ jobs:
19991999
repo: cypress-example-recipes
20002000
command: npm run test:ci:firefox
20012001

2002+
"test-binary-against-recipes-chrome":
2003+
<<: *defaults
2004+
steps:
2005+
- test-binary-against-repo:
2006+
repo: cypress-example-recipes
2007+
browser: chrome
2008+
command: npm run test:ci:chrome
2009+
20022010
# This is a special job. It allows you to test the current
20032011
# built test runner against a pull request in the repo
20042012
# cypress-example-recipes.
@@ -2427,6 +2435,10 @@ linux-workflow: &linux-workflow
24272435
<<: *mainBuildFilters
24282436
requires:
24292437
- create-build-artifacts
2438+
- test-binary-against-recipes-chrome:
2439+
<<: *mainBuildFilters
2440+
requires:
2441+
- create-build-artifacts
24302442
- test-binary-against-kitchensink-firefox:
24312443
<<: *mainBuildFilters
24322444
requires:

cli/types/cypress.d.ts

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,38 @@ declare namespace Cypress {
77
type HttpMethod = string
88
type RequestBody = string | object
99
type ViewportOrientation = 'portrait' | 'landscape'
10-
type PrevSubject = 'optional' | 'element' | 'document' | 'window'
10+
type PrevSubject = keyof PrevSubjectMap
1111
type TestingType = 'e2e' | 'component'
1212
type PluginConfig = (on: PluginEvents, config: PluginConfigOptions) => void | ConfigOptions | Promise<ConfigOptions>
1313

14+
interface PrevSubjectMap<O = unknown> {
15+
optional: O
16+
element: JQuery
17+
document: Document
18+
window: Window
19+
}
20+
1421
interface CommandOptions {
1522
prevSubject: boolean | PrevSubject | PrevSubject[]
1623
}
24+
interface CommandFn<T extends keyof ChainableMethods> {
25+
(this: Mocha.Context, ...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]> | void
26+
}
27+
interface CommandFnWithSubject<T extends keyof ChainableMethods, S> {
28+
(this: Mocha.Context, prevSubject: S, ...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]> | void
29+
}
30+
interface CommandOriginalFn<T extends keyof ChainableMethods> extends CallableFunction {
31+
(...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]>
32+
}
33+
interface CommandOriginalFnWithSubject<T extends keyof ChainableMethods, S> extends CallableFunction {
34+
(prevSubject: S, ...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]>
35+
}
36+
interface CommandFnWithOriginalFn<T extends keyof Chainable> {
37+
(this: Mocha.Context, originalFn: CommandOriginalFn<T>, ...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]> | void
38+
}
39+
interface CommandFnWithOriginalFnAndSubject<T extends keyof Chainable, S> {
40+
(this: Mocha.Context, originalFn: CommandOriginalFnWithSubject<T, S>, prevSubject: S, ...args: Parameters<ChainableMethods[T]>): ReturnType<ChainableMethods[T]> | void
41+
}
1742
interface ObjectLike {
1843
[key: string]: any
1944
}
@@ -328,7 +353,7 @@ declare namespace Cypress {
328353
// 60000
329354
```
330355
*/
331-
config<K extends keyof ConfigOptions>(key: K): ResolvedConfigOptions[K]
356+
config<K extends keyof Config>(key: K): Config[K]
332357
/**
333358
* Sets one configuration value.
334359
* @see https://on.cypress.io/config
@@ -337,7 +362,7 @@ declare namespace Cypress {
337362
Cypress.config('viewportWidth', 800)
338363
```
339364
*/
340-
config<K extends keyof ConfigOptions>(key: K, value: ResolvedConfigOptions[K]): void
365+
config<K extends keyof TestConfigOverrides>(key: K, value: TestConfigOverrides[K]): void
341366
/**
342367
* Sets multiple configuration values at once.
343368
* @see https://on.cypress.io/config
@@ -420,9 +445,16 @@ declare namespace Cypress {
420445
* @see https://on.cypress.io/api/commands
421446
*/
422447
Commands: {
423-
add<T extends keyof Chainable>(name: T, fn: Chainable[T]): void
424-
add<T extends keyof Chainable>(name: T, options: CommandOptions, fn: Chainable[T]): void
425-
overwrite<T extends keyof Chainable>(name: T, fn: Chainable[T]): void
448+
add<T extends keyof Chainable>(name: T, fn: CommandFn<T>): void
449+
add<T extends keyof Chainable>(name: T, options: CommandOptions & {prevSubject: false}, fn: CommandFn<T>): void
450+
add<T extends keyof Chainable, S extends PrevSubject>(
451+
name: T, options: CommandOptions & { prevSubject: true | S | ['optional'] }, fn: CommandFnWithSubject<T, PrevSubjectMap[S]>,
452+
): void
453+
add<T extends keyof Chainable, S extends PrevSubject>(
454+
name: T, options: CommandOptions & { prevSubject: S[] }, fn: CommandFnWithSubject<T, PrevSubjectMap<void>[S]>,
455+
): void
456+
overwrite<T extends keyof Chainable>(name: T, fn: CommandFnWithOriginalFn<T>): void
457+
overwrite<T extends keyof Chainable, S extends PrevSubject>(name: T, fn: CommandFnWithOriginalFnAndSubject<T, PrevSubjectMap[S]>): void
426458
}
427459

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

2283+
type ChainableMethods<Subject = any> = {
2284+
[P in keyof Chainable<Subject>]: Chainable<Subject>[P] extends ((...args: any[]) => any)
2285+
? Chainable<Subject>[P]
2286+
: never
2287+
}
2288+
22512289
interface SinonSpyAgent<A extends sinon.SinonSpy> {
22522290
log(shouldOutput?: boolean): Omit<A, 'withArgs'> & Agent<A>
22532291

@@ -2884,7 +2922,7 @@ declare namespace Cypress {
28842922
xhrUrl: string
28852923
}
28862924

2887-
interface TestConfigOverrides extends Partial<Pick<ConfigOptions, 'animationDistanceThreshold' | 'baseUrl' | 'defaultCommandTimeout' | 'env' | 'execTimeout' | 'includeShadowDom' | 'requestTimeout' | 'responseTimeout' | 'retries' | 'scrollBehavior' | 'taskTimeout' | 'viewportHeight' | 'viewportWidth' | 'waitForAnimations'>> {
2925+
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'>> {
28882926
browser?: IsBrowserMatcher | IsBrowserMatcher[]
28892927
keystrokeDelay?: number
28902928
}

cli/types/tests/cypress-tests.ts

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ namespace CypressIsCyTests {
6464

6565
declare namespace Cypress {
6666
interface Chainable {
67-
newCommand: (arg: string) => void
67+
newCommand: (arg: string) => Chainable<number>
6868
}
6969
}
7070

@@ -74,20 +74,106 @@ namespace CypressCommandsTests {
7474
arg
7575
return
7676
})
77-
Cypress.Commands.add('newCommand', { prevSubject: true }, (arg) => {
77+
Cypress.Commands.add('newCommand', (arg) => {
7878
// $ExpectType string
7979
arg
80+
})
81+
Cypress.Commands.add('newCommand', function(arg) {
82+
this // $ExpectType Context
83+
arg // $ExpectType string
84+
})
85+
Cypress.Commands.add('newCommand', { prevSubject: true }, (subject, arg) => {
86+
subject // $ExpectType unknown
87+
arg // $ExpectType string
8088
return
8189
})
82-
Cypress.Commands.add('newCommand', (arg) => {
83-
// $ExpectType string
84-
arg
85-
return new Promise((resolve) => {})
90+
Cypress.Commands.add('newCommand', { prevSubject: false }, (arg) => {
91+
arg // $ExpectType string
92+
return
93+
})
94+
Cypress.Commands.add('newCommand', { prevSubject: 'optional' }, (subject, arg) => {
95+
subject // $ExpectType unknown
96+
arg // $ExpectType string
97+
return
8698
})
87-
Cypress.Commands.overwrite('newCommand', (arg) => {
99+
Cypress.Commands.add('newCommand', { prevSubject: 'optional' }, (subject, arg) => {
100+
subject // $ExpectType unknown
101+
arg // $ExpectType string
102+
})
103+
Cypress.Commands.add('newCommand', { prevSubject: ['optional'] }, (subject, arg) => {
104+
subject // $ExpectType unknown
105+
arg // $ExpectType string
106+
})
107+
Cypress.Commands.add('newCommand', { prevSubject: 'document' }, (subject, arg) => {
108+
subject // $ExpectType Document
109+
arg // $ExpectType string
110+
})
111+
Cypress.Commands.add('newCommand', { prevSubject: 'window' }, (subject, arg) => {
112+
subject // $ExpectType Window
113+
arg // $ExpectType string
114+
})
115+
Cypress.Commands.add('newCommand', { prevSubject: 'element' }, (subject, arg) => {
116+
subject // $ExpectType JQuery<HTMLElement>
117+
arg // $ExpectType string
118+
})
119+
Cypress.Commands.add('newCommand', { prevSubject: ['element'] }, (subject, arg) => {
120+
subject // $ExpectType JQuery<HTMLElement>
121+
arg // $ExpectType string
122+
})
123+
Cypress.Commands.add('newCommand', { prevSubject: ['element', 'document', 'window'] }, (subject, arg) => {
124+
if (subject instanceof Window) {
125+
subject // $ExpectType Window
126+
} else if (subject instanceof Document) {
127+
subject // $ExpectType Document
128+
} else {
129+
subject // $ExpectType JQuery<HTMLElement>
130+
}
131+
arg // $ExpectType string
132+
})
133+
Cypress.Commands.add('newCommand', { prevSubject: ['window', 'document', 'optional', 'element'] }, (subject, arg) => {
134+
if (subject instanceof Window) {
135+
subject // $ExpectType Window
136+
} else if (subject instanceof Document) {
137+
subject // $ExpectType Document
138+
} else if (subject) {
139+
subject // $ExpectType JQuery<HTMLElement>
140+
} else {
141+
subject // $ExpectType void
142+
}
143+
arg // $ExpectType string
144+
})
145+
Cypress.Commands.add('newCommand', (arg) => {
88146
// $ExpectType string
89147
arg
90-
return
148+
return cy.wrap(new Promise<number>((resolve) => { resolve(5) }))
149+
})
150+
Cypress.Commands.overwrite('newCommand', (originalFn, arg) => {
151+
arg // $ExpectType string
152+
originalFn // $ExpectedType Chainable['newCommand']
153+
originalFn(arg) // $ExpectType Chainable<number>
154+
})
155+
Cypress.Commands.overwrite('newCommand', function(originalFn, arg) {
156+
this // $ExpectType Context
157+
arg // $ExpectType string
158+
originalFn // $ExpectedType Chainable['newCommand']
159+
originalFn.apply(this, [arg]) // $ExpectType Chainable<number>
160+
})
161+
Cypress.Commands.overwrite<'type', 'element'>('type', (originalFn, element, text, options?: Partial<Cypress.TypeOptions & {sensitive: boolean}>) => {
162+
element // $ExpectType JQuery<HTMLElement>
163+
text // $ExpectType string
164+
165+
if (options && options.sensitive) {
166+
// turn off original log
167+
options.log = false
168+
// create our own log with masked message
169+
Cypress.log({
170+
$el: element,
171+
name: 'type',
172+
message: '*'.repeat(text.length),
173+
})
174+
}
175+
176+
return originalFn(element, text, options)
91177
})
92178
}
93179

npm/vite-dev-server/src/startServer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const resolveServerConfig = async ({ viteConfig, options, indexHtml }: StartDevS
5252

5353
finalConfig.server = finalConfig.server || {}
5454

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

5757
// Ask vite to pre-optimize all dependencies of the specs
5858
finalConfig.optimizeDeps = finalConfig.optimizeDeps || {}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import defaultMessages from '@packages/frontend-shared/src/locales/en-US.json'
2+
3+
const extensionInputSelector = `[placeholder="${defaultMessages.components.fileSearch.byExtensionInput}"]`
4+
5+
describe('Code Generation', () => {
6+
beforeEach(() => {
7+
cy.scaffoldProject('react-code-gen')
8+
cy.openProject('react-code-gen')
9+
cy.startAppServer('component')
10+
cy.visitApp()
11+
})
12+
13+
const checkCodeGenCandidates = (specs: string[]) => {
14+
cy.findByTestId('file-match-indicator').contains(`${specs.length} Match${specs.length > 1 ? 'es' : ''}`)
15+
cy.findAllByTestId('file-list-row').should('have.length', specs.length)
16+
.each((row, i) => cy.wrap(row).contains(specs[i]))
17+
}
18+
19+
it('should generate spec from component', () => {
20+
cy.findByTestId('new-spec-button').click()
21+
cy.findByTestId('create-spec-modal').should('be.visible').within(() => {
22+
cy.contains('Create a new spec').should('be.visible')
23+
cy.get('[data-cy="external"]').should('have.attr', 'href', 'https://on.cypress.io')
24+
})
25+
26+
cy.contains('Create from component').click()
27+
const componentGlob = '**/*.{jsx,tsx}'
28+
29+
cy.findByTestId('file-match-button').contains(componentGlob)
30+
checkCodeGenCandidates(['App.cy.jsx', 'App.jsx', 'index.jsx', 'Button.jsx', 'Button.stories.jsx'])
31+
32+
cy.intercept('query-ComponentGeneratorStepOne').as('code-gen-candidates')
33+
cy.findByTestId('file-match-button').click()
34+
cy.get(extensionInputSelector).clear().type('**/App.*')
35+
cy.wait('@code-gen-candidates')
36+
37+
checkCodeGenCandidates(['App.css', 'App.cy.jsx', 'App.jsx'])
38+
39+
cy.get(extensionInputSelector).clear().type(componentGlob, { parseSpecialCharSequences: false })
40+
cy.contains('Button.jsx').click()
41+
cy.findByTestId('file-row').contains('src/stories/Button.cy.js').click()
42+
43+
cy.withCtx(async (ctx) => {
44+
const spec = await (await ctx.project.findSpecs(ctx.currentProject?.projectRoot ?? '', 'component'))
45+
.find((spec) => spec.relative === 'src/stories/Button.cy.jsx')
46+
47+
expect(spec).to.exist
48+
})
49+
})
50+
51+
it('should generate spec from story', () => {
52+
cy.findByTestId('new-spec-button').click()
53+
54+
cy.contains('Create from story').click()
55+
const storyGlob = '**/*.stories.*'
56+
57+
cy.findByTestId('file-match-button').contains(storyGlob)
58+
checkCodeGenCandidates(['Button.stories.jsx'])
59+
60+
cy.contains('Button.stories.jsx').click()
61+
cy.findByTestId('file-row').contains('src/stories/Button.stories.cy.js').click()
62+
cy.contains('composeStories')
63+
64+
cy.withCtx(async (ctx) => {
65+
const spec = await (await ctx.project.findSpecs(ctx.currentProject?.projectRoot ?? '', 'component'))
66+
.find((spec) => spec.relative === 'src/stories/Button.stories.cy.jsx')
67+
68+
expect(spec).to.exist
69+
})
70+
})
71+
})

0 commit comments

Comments
 (0)