Skip to content

Commit

Permalink
feat: Bundle cy.origin() dependencies at runtime (#25626)
Browse files Browse the repository at this point in the history
Co-authored-by: cypress-bot[bot] <2f0651858c6e38e0+cypress-bot[bot]@users.noreply.github.com>
Co-authored-by: Ryan Manuel <ryanm@cypress.io>
  • Loading branch information
3 people authored Feb 13, 2023
1 parent 2bfeb53 commit 41512c4
Show file tree
Hide file tree
Showing 46 changed files with 3,310 additions and 1,201 deletions.
11 changes: 6 additions & 5 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@

_Released 02/14/2023 (PENDING)_

**Features:**

- Added the "Open in IDE" feature for failed tests reported from the Debug page. Addressed in [#25691](https://github.com/cypress-io/cypress/pull/25691).
- Added a new CLI flag, called [`--auto-cancel-after-failures`](https://docs.cypress.io/guides/guides/command-line#Options), that overrides the project-level CI ["Auto Cancellation"](https://docs.cypress.io/guides/cloud/smart-orchestration#Auto-Cancellation) value when recording to the Cloud. This gives Cloud users on Business and Enterprise plans the flexibility to alter the auto-cancellation value per run. Addressed in [#25237](https://github.com/cypress-io/cypress/pull/25237).
- Added `Cypress.require()` for including dependencies within the `cy.origin()` callback. Removed support for `require()` and `import()` within the callback. Addresses [#24976](https://github.com/cypress-io/cypress/issues/24976).

**Bugfixes:**

- Fixed an issue with the Cloud project selection modal not showing the correct prompts. Fixes [#25520](https://github.com/cypress-io/cypress/issues/25520).
- Fixed an issue in middleware where error-handling code could itself generate an error and fail to report the original issue. Fixes [#22825](https://github.com/cypress-io/cypress/issues/22825).
- Fixed an issue that could cause the Debug page to display a different number of specs for in-progress runs than shown in Cypress Cloud. Fixes [#25647](https://github.com/cypress-io/cypress/issues/25647).

**Features:**

- Added the "Open in IDE" feature for failed tests reported from the Debug page. Addressed in [#25691](https://github.com/cypress-io/cypress/pull/25691).
- Added a new CLI flag, called [`--auto-cancel-after-failures`](https://docs.cypress.io/guides/guides/command-line#Options), that overrides the project-level CI ["Auto Cancellation"](https://docs.cypress.io/guides/cloud/smart-orchestration#Auto-Cancellation) value when recording to the Cloud. This gives Cloud users on Business and Enterprise plans the flexibility to alter the auto-cancellation value per run. Addressed in [#25237](https://github.com/cypress-io/cypress/pull/25237).

**Misc:**

- Improved the layout of the Debug Page on smaller viewports when there is a pending run. Addresses [#25664](https://github.com/cypress-io/cypress/issues/25664).
Expand Down
10 changes: 8 additions & 2 deletions cli/types/cypress.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -786,14 +786,20 @@ declare namespace Cypress {
*/
off: Actions

/**
* Used to include dependencies within the cy.origin() callback
* @see https://on.cypress.io/origin
*/
require: <T = any>(id: string) => T

/**
* Trigger action
* @private
*/
action: (action: string, ...args: any[]) => any[] | void

/**
* Load files
* Load files
* @private
*/
onSpecWindow: (window: Window, specList: string[] | Array<() => Promise<void>>) => void
Expand Down Expand Up @@ -3126,7 +3132,7 @@ declare namespace Cypress {
*/
experimentalRunAllSpecs?: boolean
/**
* Enables support for require/import within cy.origin.
* Enables support for `Cypress.require()` for including dependencies within the `cy.origin()` callback.
* @default false
*/
experimentalOriginDependencies?: boolean
Expand Down
17 changes: 17 additions & 0 deletions cli/types/tests/cypress-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1164,3 +1164,20 @@ namespace CypressTraversalTests {
cy.wrap({}).parentsUntil('#myItem', 'a', { log: false, timeout: 100 }) // $ExpectType Chainable<JQuery<HTMLElement>>
cy.wrap({}).parentsUntil('#myItem', 'a', { log: 'true' }) // $ExpectError
}

namespace CypressRequireTests {
Cypress.require('lodash')

const anydep = Cypress.require('anydep')
anydep // $ExpectType any

const sinon = Cypress.require<sinon.SinonStatic>('sinon') as typeof import('sinon')
sinon // $ExpectType SinonStatic

const lodash = Cypress.require<_.LoDashStatic>('lodash')
lodash // $ExpectType LoDashStatic

Cypress.require() // $ExpectError
Cypress.require({}) // $ExpectError
Cypress.require(123) // $ExpectError
}
10 changes: 10 additions & 0 deletions npm/webpack-batteries-included-preprocessor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,16 @@ preprocessor.defaultOptions = {
watchOptions: {},
}

preprocessor.getFullWebpackOptions = (filePath, typescript) => {
const options = { typescript }

options.webpackOptions = getDefaultWebpackOptions()

addTypeScriptConfig({ filePath }, options)

return options.webpackOptions
}

// for testing purposes, but do not add this to the typescript interface
preprocessor.__reset = webpackPreprocessor.__reset

Expand Down
104 changes: 7 additions & 97 deletions npm/webpack-preprocessor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,11 @@ import * as events from 'events'
import * as path from 'path'
import webpack from 'webpack'
import utils from './lib/utils'
import { crossOriginCallbackStore } from './lib/cross-origin-callback-store'
import { overrideSourceMaps } from './lib/typescript-overrides'
import { compileCrossOriginCallbackFiles } from './lib/cross-origin-callback-compile'

const debug = Debug('cypress:webpack')
const debugStats = Debug('cypress:webpack:stats')

declare global {
// this indicates which commands should be acted upon by the
// cross-origin-callback-loader. its absence means the loader
// should not be utilized at all
// eslint-disable-next-line no-var
var __cypressCallbackReplacementCommands: string[] | undefined
}

type FilePath = string
interface BundleObject {
promise: Bluebird<FilePath>
Expand Down Expand Up @@ -163,8 +153,6 @@ interface WebpackPreprocessor extends WebpackPreprocessorFn {
const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): FilePreprocessor => {
debug('user options: %o', options)

let crossOriginCallbackLoaderAdded = false

// we return function that accepts the arguments provided by
// the event 'file:preprocessor'
//
Expand Down Expand Up @@ -241,25 +229,6 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
})
.value() as any

const callbackReplacementCommands = global.__cypressCallbackReplacementCommands

if (!crossOriginCallbackLoaderAdded && !!callbackReplacementCommands) {
// webpack runs loaders last-to-first and we want ours to run last
// so that it's working with plain javascript
webpackOptions.module.rules.unshift({
test: /\.(js|ts|jsx|tsx)$/,
exclude: /node_modules/,
use: [{
loader: require.resolve('@cypress/webpack-preprocessor/dist/lib/cross-origin-callback-loader.js'),
options: {
commands: callbackReplacementCommands,
},
}],
})

crossOriginCallbackLoaderAdded = true
}

debug('webpackOptions: %o', webpackOptions)
debug('watchOptions: %o', watchOptions)
if (options.typescript) debug('typescript: %s', options.typescript)
Expand Down Expand Up @@ -327,74 +296,26 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
}

debug('finished bundling', outputPath)

if (debugStats.enabled) {
/* eslint-disable-next-line no-console */
console.error(stats.toString({ colors: true }))
}

const resolveAllBundles = () => {
bundles[filePath].deferreds.forEach((deferred) => {
// resolve with the outputPath so Cypress knows where to serve
// the file from
deferred.resolve(outputPath)
})

bundles[filePath].deferreds.length = 0
}

// the cross-origin-callback-loader extracts any cross-origin callback
// functions that require dependencies and stores their sources
// in the CrossOriginCallbackStore. it saves the callbacks per source
// files, since that's the context it has. here we need to unfurl
// what dependencies the input source file has so we can know which
// files stored in the CrossOriginCallbackStore to compile
const handleCrossOriginCallbackFiles = () => {
// get the source file and any of its dependencies
const sourceFiles = jsonStats.modules
.filter((module) => {
// entries have duplicate modules whose ids are numbers
return _.isString(module.id)
})
.map((module) => {
// module id is the path relative to the cwd,
// e.g. ./cypress/support/e2e.js, but we need it absolute
return path.join(process.cwd(), module.id as string)
})

if (!crossOriginCallbackStore.hasFilesFor(sourceFiles)) {
debug('no cross-origin callback files')

return resolveAllBundles()
}

compileCrossOriginCallbackFiles(crossOriginCallbackStore.getFilesFor(sourceFiles), {
originalFilePath: filePath,
webpackOptions,
})
.then(() => {
debug('resolve all after handling cross-origin callback files')
resolveAllBundles()
})
.catch((err) => {
rejectWithErr(err)
})
.finally(() => {
crossOriginCallbackStore.reset(filePath)
})
}

// seems to be a race condition where changing file before next tick
// does not cause build to rerun
Bluebird.delay(0).then(() => {
if (!bundles[filePath]) {
return
}

if (!callbackReplacementCommands) {
return resolveAllBundles()
}
bundles[filePath].deferreds.forEach((deferred) => {
// resolve with the outputPath so Cypress knows where to serve
// the file from
deferred.resolve(outputPath)
})

handleCrossOriginCallbackFiles()
bundles[filePath].deferreds.length = 0
})
}

Expand Down Expand Up @@ -454,17 +375,6 @@ const preprocessor: WebpackPreprocessor = (options: PreprocessorOptions = {}): F
bundler.close(cb)
}
}

// clean up temp dir where cross-origin callback files are output
const tmpdir = utils.tmpdir(utils.hash(filePath))

debug('remove temp directory:', tmpdir)

utils.rmdir(tmpdir).catch((err) => {
// not the end of the world if removing the tmpdir fails, but we
// don't want it to crash the whole process by going uncaught
debug('failed removing temp directory: %s', err.stack)
})
})

// return the promise, which will resolve with the outputPath or reject
Expand Down
104 changes: 0 additions & 104 deletions npm/webpack-preprocessor/lib/cross-origin-callback-compile.ts

This file was deleted.

Loading

5 comments on commit 41512c4

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 41512c4 Feb 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.6.0/linux-x64/develop-41512c416a80e5158752fef9ffbe722402a5ada4/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 41512c4 Feb 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.6.0/linux-arm64/develop-41512c416a80e5158752fef9ffbe722402a5ada4/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 41512c4 Feb 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.6.0/darwin-x64/develop-41512c416a80e5158752fef9ffbe722402a5ada4/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 41512c4 Feb 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.6.0/darwin-arm64/develop-41512c416a80e5158752fef9ffbe722402a5ada4/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 41512c4 Feb 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the win32 x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/12.6.0/win32-x64/develop-41512c416a80e5158752fef9ffbe722402a5ada4/cypress.tgz

Please sign in to comment.