Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Bundle cy.origin() dependencies at runtime #25626

Merged
merged 39 commits into from
Feb 13, 2023
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
90018b0
wip - bundle cy.origin dependencies at runtime
chrisbreiding Dec 20, 2022
e9822fa
Merge remote-tracking branch 'origin/develop' into crb/origin-depende…
chrisbreiding Dec 20, 2022
5a77262
wip - forgotten
chrisbreiding Dec 20, 2022
e82e1e7
Merge remote-tracking branch 'origin/develop' into crb/origin-depende…
chrisbreiding Jan 25, 2023
87ccef2
feat: add support for Cypress.require() within the cy.origin() callba…
chrisbreiding Jan 26, 2023
4e55939
cleanup [run ci]
chrisbreiding Jan 26, 2023
172083f
cleanup / fixes [run ci]
chrisbreiding Jan 26, 2023
9dfbb13
remove obsolete method
chrisbreiding Jan 26, 2023
af1be2c
fix tests
chrisbreiding Jan 26, 2023
6fa42b7
fix typescript
chrisbreiding Jan 26, 2023
b5ae5dc
fix test
chrisbreiding Jan 26, 2023
e33f0b2
use experimental flag [run ci]
chrisbreiding Jan 26, 2023
13233e1
ok
chrisbreiding Jan 26, 2023
c069eb2
fixes [run ci]
chrisbreiding Jan 27, 2023
b522452
fix system test [run ci]
chrisbreiding Jan 27, 2023
f27ccc9
Merge branch 'develop' into issue-24976-cypress-require
chrisbreiding Jan 30, 2023
d043060
revert graphql files
chrisbreiding Jan 30, 2023
e2396ef
add changelog
chrisbreiding Jan 30, 2023
f84fe8b
?
chrisbreiding Jan 30, 2023
b6025f4
Merge branch 'develop' into issue-24976-cypress-require
chrisbreiding Jan 30, 2023
e2ddf03
fix changelog
chrisbreiding Jan 30, 2023
671285e
Merge remote-tracking branch 'origin/develop' into issue-24976-cypres…
chrisbreiding Jan 31, 2023
b610708
move changelog item
chrisbreiding Jan 31, 2023
94e2176
chore: updating v8 snapshot cache
Feb 1, 2023
b79075f
allow generic for return type
chrisbreiding Feb 1, 2023
b5270d5
updates from pr feedback
chrisbreiding Feb 1, 2023
e79fdca
Merge branch 'issue-24976-cypress-require' of github.com:cypress-io/c…
chrisbreiding Feb 1, 2023
20e7bd3
Merge branch 'develop' into issue-24976-cypress-require
chrisbreiding Feb 1, 2023
65fa57b
update type tests
chrisbreiding Feb 1, 2023
d1f69f1
expect the error
chrisbreiding Feb 1, 2023
25a6827
chore: updating v8 snapshot cache
Feb 1, 2023
0ed626a
chore: updating v8 snapshot cache
Feb 1, 2023
b8f095a
fix binary tests
ryanthemanuel Feb 2, 2023
c6d73b9
Merge remote-tracking branch 'origin/develop' into issue-24976-cypres…
chrisbreiding Feb 10, 2023
75aa15d
Merge remote-tracking branch 'origin/develop' into issue-24976-cypres…
chrisbreiding Feb 10, 2023
986d487
Merge remote-tracking branch 'origin/develop' into issue-24976-cypres…
chrisbreiding Feb 13, 2023
ee47a3b
fix
chrisbreiding Feb 13, 2023
e23e7f7
run ci
chrisbreiding Feb 13, 2023
5a2a7d8
Merge remote-tracking branch 'origin/develop' into issue-24976-cypres…
chrisbreiding Feb 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions cli/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
<!-- See the ../guides/writing-the-cypress-changelog.md for details on writing the changelog. -->
## 12.6.0

_Released 02/14/2023 (PENDING)_

**Features:**

- 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).

## 12.5.1

_Released 02/10/2023 (PENDING)_
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