mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-05 14:09:46 -06:00
refactor: Data context cleanup & IPC bindings for data push (#18357)
This commit is contained in:
22
.gitignore
vendored
22
.gitignore
vendored
@@ -13,18 +13,35 @@ cypress.zip
|
||||
Cached Theme.pak
|
||||
Cached Theme Material Design.pak
|
||||
|
||||
# from data-context, compiled .js files
|
||||
packages/data-context/src/**/*.js
|
||||
|
||||
# from desktop-gui
|
||||
packages/desktop-gui/cypress/videos
|
||||
packages/desktop-gui/src/jsconfig.json
|
||||
|
||||
|
||||
# from driver
|
||||
packages/driver/cypress/videos
|
||||
packages/driver/cypress/screenshots
|
||||
|
||||
# from launcher, compiled .js files
|
||||
packages/launcher/index.js
|
||||
packages/launcher/lib/**/*.js
|
||||
|
||||
# from network, compiled .js files
|
||||
packages/network/lib/**/*.js
|
||||
|
||||
# from net-stubbing, compiled .js files
|
||||
packages/net-stubbing/lib/**/*.js
|
||||
|
||||
# from runner
|
||||
packages/runner/cypress/videos
|
||||
packages/runner/cypress/screenshots
|
||||
|
||||
# from proxy, compiled .js files
|
||||
packages/proxy/lib/**/*.js
|
||||
|
||||
# npm packages
|
||||
npm/**/cypress/screenshots
|
||||
|
||||
@@ -40,6 +57,9 @@ packages/server/support
|
||||
packages/server/test/support/fixtures/server/imgs
|
||||
packages/server/test/support/fixtures/server/libs
|
||||
|
||||
# from socket, dist built files
|
||||
packages/socket/lib/*.js
|
||||
|
||||
# from npm/react
|
||||
/npm/react/bin/*
|
||||
/npm/react/cypress/videos
|
||||
@@ -347,4 +367,4 @@ globbed_node_modules
|
||||
|
||||
# Autogenerated files, typically from graphql-code-generator
|
||||
*.gen.ts
|
||||
*.gen.json
|
||||
*.gen.json
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
"semantic-release": "17.4.2",
|
||||
"to-string-loader": "1.1.6",
|
||||
"ts-loader": "8.1.0",
|
||||
"ts-node": "9.1.1",
|
||||
"ts-node": "^10.2.1",
|
||||
"tslib": "^2.2.0",
|
||||
"tslint": "5.20.1",
|
||||
"typescript": "4.2.4",
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
"sass-loader": "10.1.1",
|
||||
"style-loader": "^2.0.0",
|
||||
"svg-url-loader": "3.0.3",
|
||||
"ts-node": "^9.1.1",
|
||||
"ts-node": "^10.2.1",
|
||||
"tsc-alias": "^1.2.9",
|
||||
"tsconfig-paths-webpack-plugin": "^3.5.1",
|
||||
"typed-scss-modules": "^4.1.1",
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
"sinon": "^9.0.0",
|
||||
"sinon-chai": "^3.5.0",
|
||||
"snap-shot-it": "7.9.2",
|
||||
"ts-node": "8.10.1",
|
||||
"ts-node": "^10.2.1",
|
||||
"webpack": "^4.41.12"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
"cypress:run:debug": "node ./scripts/debug.js cypress:run",
|
||||
"cypress:verify": "cypress verify --dev",
|
||||
"dev": "gulp dev",
|
||||
"dev:no-watch": "gulp dev:no-watch",
|
||||
"dev:clean": "gulp dev:clean",
|
||||
"gulp:debug": "node --inspect-brk ./node_modules/.bin/gulp",
|
||||
"dev-debug": "node ./scripts/debug.js dev",
|
||||
"docker": "./scripts/run-docker-local.sh",
|
||||
@@ -116,6 +118,7 @@
|
||||
"@types/react": "16.9.50",
|
||||
"@types/react-dom": "16.9.8",
|
||||
"@types/request-promise": "4.1.45",
|
||||
"@types/send": "^0.17.1",
|
||||
"@types/sinon-chai": "3.2.3",
|
||||
"@types/through2": "^2.0.36",
|
||||
"@typescript-eslint/eslint-plugin": "4.18.0",
|
||||
@@ -129,6 +132,7 @@
|
||||
"babel-eslint": "10.1.0",
|
||||
"bluebird": "3.5.3",
|
||||
"bluebird-retry": "0.11.0",
|
||||
"c8": "^7.10.0",
|
||||
"chai": "4.2.0",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"chalk": "2.4.2",
|
||||
@@ -217,7 +221,7 @@
|
||||
"through": "2.3.8",
|
||||
"through2": "^4.0.2",
|
||||
"tree-kill": "1.2.2",
|
||||
"ts-node": "8.3.0",
|
||||
"ts-node": "^10.2.1",
|
||||
"typescript": "^4.2.3",
|
||||
"yarn-deduplicate": "3.1.0"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"projectId": "sehy69",
|
||||
"baseUrl": "http://localhost:5556",
|
||||
"viewportWidth": 800,
|
||||
"viewportHeight": 850,
|
||||
"fixturesFolder": false,
|
||||
@@ -14,11 +13,16 @@
|
||||
"reporterOptions": {
|
||||
"configFile": "../../mocha-reporter-config.json"
|
||||
},
|
||||
"integrationFolder": "cypress/e2e/integration",
|
||||
"componentFolder": "src",
|
||||
"supportFile": false,
|
||||
"component": {
|
||||
"testFiles": "**/*.spec.{js,ts,tsx,jsx}",
|
||||
"supportFile": "cypress/component/support/index.ts",
|
||||
"pluginsFile": "cypress/component/plugins/index.js"
|
||||
},
|
||||
"e2e": {
|
||||
"pluginsFile": "cypress/e2e/plugins/index.ts",
|
||||
"supportFile": "cypress/e2e/support/e2eSupport.ts"
|
||||
}
|
||||
}
|
||||
|
||||
39
packages/app/cypress/e2e/integration/basic.spec.ts
Normal file
39
packages/app/cypress/e2e/integration/basic.spec.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
let GQL_PORT
|
||||
let SERVER_PORT
|
||||
|
||||
describe('App', () => {
|
||||
beforeEach(() => {
|
||||
cy.withCtx(async (ctx) => {
|
||||
await ctx.dispose()
|
||||
await ctx.actions.project.setActiveProject(ctx.launchArgs.projectRoot)
|
||||
ctx.actions.wizard.setTestingType('e2e')
|
||||
await ctx.actions.project.initializeActiveProject({
|
||||
skipPluginIntializeForTesting: true,
|
||||
})
|
||||
|
||||
await ctx.actions.project.launchProject({
|
||||
skipBrowserOpenForTest: true,
|
||||
})
|
||||
|
||||
return [
|
||||
ctx.gqlServerPort,
|
||||
ctx.appServerPort,
|
||||
]
|
||||
}).then(([gqlPort, serverPort]) => {
|
||||
GQL_PORT = gqlPort
|
||||
SERVER_PORT = serverPort
|
||||
})
|
||||
})
|
||||
|
||||
it('resolves the home page', () => {
|
||||
cy.visit(`dist/index.html?serverPort=${SERVER_PORT}&gqlPort=${GQL_PORT}`)
|
||||
cy.get('[href="#/runner"]').click()
|
||||
cy.get('[href="#/settings"]').click()
|
||||
})
|
||||
|
||||
it('resolves the home page, with a different server port?', () => {
|
||||
cy.visit(`dist/index.html?serverPort=${SERVER_PORT}&gqlPort=${GQL_PORT}`)
|
||||
cy.get('[href="#/runner"]').click()
|
||||
cy.get('[href="#/settings"]').click()
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,7 @@
|
||||
/// <reference types="cypress" />
|
||||
const { monorepoPaths } = require('../../../../../scripts/gulp/monorepoPaths')
|
||||
import { e2ePluginSetup } from '@packages/frontend-shared/cypress/e2e/e2ePluginSetup'
|
||||
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
@@ -15,8 +18,6 @@
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
module.exports = (on, config) => {
|
||||
// `on` is used to hook into various events Cypress emits
|
||||
// `config` is the resolved Cypress config
|
||||
module.exports = async (on, config) => {
|
||||
return await e2ePluginSetup(monorepoPaths.pkgApp, on, config)
|
||||
}
|
||||
2
packages/app/cypress/e2e/support/e2eSupport.ts
Normal file
2
packages/app/cypress/e2e/support/e2eSupport.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
/// <reference path="../../../../frontend-shared/cypress/e2e/support/e2eSupport.ts" />
|
||||
require('../../../../frontend-shared/cypress/e2e/support/e2eSupport')
|
||||
@@ -1,7 +0,0 @@
|
||||
describe('App', () => {
|
||||
it('resolves the home page', () => {
|
||||
cy.visit('http://localhost:5556')
|
||||
cy.get('[data-e2e-href="/runner"]').click()
|
||||
cy.get('[data-e2e-href="/settings"]').click()
|
||||
})
|
||||
})
|
||||
@@ -14,10 +14,7 @@
|
||||
"debug": "gulp debug --project ${PWD}",
|
||||
"dev": "gulp dev --project ${PWD}",
|
||||
"start": "echo \"run 'yarn dev' from the root\" && exit 1",
|
||||
"watch": "echo \"run 'yarn dev' from the root\" && exit 1",
|
||||
"vite:dev": "vite",
|
||||
"vite:build": "vite build",
|
||||
"vite:preview": "yarn vite:build && vite preview"
|
||||
"watch": "echo \"run 'yarn dev' from the root\" && exit 1"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
@@ -76,13 +73,25 @@
|
||||
"vite": {
|
||||
"optimizeDeps": {
|
||||
"include": [
|
||||
"@iconify/iconify",
|
||||
"@testing-library/cypress/add-commands",
|
||||
"@urql/exchange-execute",
|
||||
"@urql/vue",
|
||||
"@vueuse/core",
|
||||
"cypress-file-upload",
|
||||
"dedent",
|
||||
"fake-uuid",
|
||||
"graphql",
|
||||
"graphql-relay",
|
||||
"graphql/jsutils/Path",
|
||||
"lodash",
|
||||
"mobx",
|
||||
"nanoid",
|
||||
"path",
|
||||
"socket.io-client",
|
||||
"vue",
|
||||
"vue-toast-notification"
|
||||
"vue-toast-notification",
|
||||
"wonka"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
describe('hello', () => {
|
||||
it('works', () => {
|
||||
expect(1).to.eq(1)
|
||||
})
|
||||
})
|
||||
@@ -9,7 +9,7 @@ import { createRouter } from './router/router'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(urql, makeUrqlClient())
|
||||
app.use(urql, makeUrqlClient('app'))
|
||||
app.use(createRouter())
|
||||
app.use(createI18n())
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
</route>
|
||||
<script lang="ts" setup>
|
||||
import { gql, useMutation, useQuery } from '@urql/vue'
|
||||
import { MainQueryDocument, GenerateSpecFromStoryDocument } from '../generated/graphql'
|
||||
import { NewSpecQueryDocument, NewSpec_GenerateSpecFromStoryDocument } from '../generated/graphql'
|
||||
|
||||
gql`
|
||||
query MainQuery {
|
||||
query NewSpecQuery {
|
||||
wizard {
|
||||
storybook {
|
||||
configured
|
||||
@@ -39,7 +39,7 @@ query MainQuery {
|
||||
`
|
||||
|
||||
gql`
|
||||
mutation GenerateSpecFromStory($storyPath: String!) {
|
||||
mutation NewSpec_GenerateSpecFromStory($storyPath: String!) {
|
||||
generateSpecFromStory (storyPath: $storyPath) {
|
||||
storybook {
|
||||
configured,
|
||||
@@ -49,8 +49,8 @@ mutation GenerateSpecFromStory($storyPath: String!) {
|
||||
}
|
||||
`
|
||||
|
||||
const query = useQuery({ query: MainQueryDocument })
|
||||
const mutation = useMutation(GenerateSpecFromStoryDocument)
|
||||
const query = useQuery({ query: NewSpecQueryDocument })
|
||||
const mutation = useMutation(NewSpec_GenerateSpecFromStoryDocument)
|
||||
|
||||
async function storyClick (story) {
|
||||
await mutation.executeMutation({ storyPath: story })
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { createRouter as _createRouter, createWebHistory } from 'vue-router'
|
||||
import { createRouter as _createRouter, createWebHashHistory } from 'vue-router'
|
||||
import generatedRoutes from 'virtual:generated-pages'
|
||||
import { setupLayouts } from 'virtual:generated-layouts'
|
||||
|
||||
export const createRouter = () => {
|
||||
const routes = setupLayouts(generatedRoutes)
|
||||
|
||||
// TODO: clean this up
|
||||
const historyBase = window.location.href.includes('__vite__') ? '__vite__' : ''
|
||||
|
||||
return _createRouter({
|
||||
history: createWebHistory(historyBase),
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"build-prod": "tsc || echo 'built, with errors'",
|
||||
"check-ts": "tsc --noEmit",
|
||||
"clean-deps": "rimraf node_modules",
|
||||
"clean": "rimraf ./src/*.js ./src/**/*.js ./src/**/**/*.js ./test/**/*.js || echo 'cleaned'",
|
||||
"clean": "rimraf './{src,test}/**/*.js'",
|
||||
"test-unit": "mocha -r @packages/ts/register test/unit/**/*.spec.ts --config ./test/.mocharc.js --exit",
|
||||
"test-integration": "mocha -r @packages/ts/register test/integration/**/*.spec.ts --config ./test/.mocharc.js --exit"
|
||||
},
|
||||
@@ -22,5 +22,8 @@
|
||||
"mocha": "7.0.1",
|
||||
"rimraf": "3.0.2"
|
||||
},
|
||||
"files": [
|
||||
"src"
|
||||
],
|
||||
"types": "src/index.ts"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { LaunchArgs, OpenProjectLaunchOptions } from '@packages/types'
|
||||
import type { LaunchArgs, OpenProjectLaunchOptions, PlatformName } from '@packages/types'
|
||||
import type { AppApiShape, ProjectApiShape } from './actions'
|
||||
import type { NexusGenAbstractTypeMembers } from '@packages/graphql/src/gen/nxs.gen'
|
||||
import type { AuthApiShape } from './actions/AuthActions'
|
||||
@@ -17,8 +17,10 @@ import {
|
||||
StorybookDataSource,
|
||||
} from './sources/'
|
||||
import { cached } from './util/cached'
|
||||
import { DataContextShell, DataContextShellConfig } from './DataContextShell'
|
||||
|
||||
export interface DataContextConfig {
|
||||
export interface DataContextConfig extends DataContextShellConfig {
|
||||
os: PlatformName
|
||||
launchArgs: LaunchArgs
|
||||
launchOptions: OpenProjectLaunchOptions
|
||||
/**
|
||||
@@ -33,15 +35,39 @@ export interface DataContextConfig {
|
||||
projectApi: ProjectApiShape
|
||||
}
|
||||
|
||||
export class DataContext {
|
||||
export class DataContext extends DataContextShell {
|
||||
private _coreData: CoreDataShape
|
||||
|
||||
fs = fsExtra
|
||||
@cached
|
||||
get fs () {
|
||||
return fsExtra
|
||||
}
|
||||
|
||||
constructor (private config: DataContextConfig) {
|
||||
super(config)
|
||||
this._coreData = config.coreData ?? makeCoreData()
|
||||
}
|
||||
|
||||
async initializeData () {
|
||||
const toAwait: Promise<any>[] = [
|
||||
// Fetch the browsers when the app starts, so we have some by
|
||||
// the time we're continuing.
|
||||
this.actions.app.refreshBrowsers(),
|
||||
// load projects from cache on start
|
||||
this.actions.project.loadProjects(),
|
||||
]
|
||||
|
||||
if (this.config.launchArgs.projectRoot) {
|
||||
toAwait.push(this.actions.project.setActiveProject(this.config.launchArgs.projectRoot))
|
||||
}
|
||||
|
||||
return Promise.all(toAwait)
|
||||
}
|
||||
|
||||
get os () {
|
||||
return this.config.os
|
||||
}
|
||||
|
||||
get launchArgs () {
|
||||
return this.config.launchArgs
|
||||
}
|
||||
@@ -132,6 +158,7 @@ export class DataContext {
|
||||
appApi: this.config.appApi,
|
||||
authApi: this.config.authApi,
|
||||
projectApi: this.config.projectApi,
|
||||
busApi: this.config.rootBus,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,8 +187,11 @@ export class DataContext {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
dispose () {
|
||||
this.util.disposeLoaders()
|
||||
async dispose () {
|
||||
return Promise.all([
|
||||
this.util.disposeLoaders(),
|
||||
this.actions.project.clearActiveProject(),
|
||||
])
|
||||
}
|
||||
|
||||
get loader () {
|
||||
|
||||
43
packages/data-context/src/DataContextShell.ts
Normal file
43
packages/data-context/src/DataContextShell.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { EventEmitter } from 'events'
|
||||
import { DataEmitterActions } from './actions/DataEmitterActions'
|
||||
import { cached } from './util/cached'
|
||||
|
||||
export interface DataContextShellConfig {
|
||||
rootBus: EventEmitter
|
||||
}
|
||||
|
||||
// Used in places where we have to create a "shell" data context,
|
||||
// for non-unified parts of the codebase
|
||||
export class DataContextShell {
|
||||
private _appServerPort: number | undefined
|
||||
private _gqlServerPort: number | undefined
|
||||
|
||||
constructor (private shellConfig: DataContextShellConfig = { rootBus: new EventEmitter }) {}
|
||||
|
||||
setAppServerPort (port: number | undefined) {
|
||||
this._appServerPort = port
|
||||
}
|
||||
|
||||
setGqlServerPort (port: number | undefined) {
|
||||
this._gqlServerPort = port
|
||||
}
|
||||
|
||||
get appServerPort () {
|
||||
return this._appServerPort
|
||||
}
|
||||
|
||||
get gqlServerPort () {
|
||||
return this._gqlServerPort
|
||||
}
|
||||
|
||||
@cached
|
||||
get emitter () {
|
||||
return new DataEmitterActions(this)
|
||||
}
|
||||
|
||||
get _apis () {
|
||||
return {
|
||||
busApi: this.shellConfig.rootBus,
|
||||
}
|
||||
}
|
||||
}
|
||||
29
packages/data-context/src/actions/DataEmitterActions.ts
Normal file
29
packages/data-context/src/actions/DataEmitterActions.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { SocketIOServer } from '@packages/socket'
|
||||
import type { DataContextShell } from '../DataContextShell'
|
||||
|
||||
export class DataEmitterActions {
|
||||
private _launchpadSocketServer: SocketIOServer | undefined
|
||||
private _appSocketServer: SocketIOServer | undefined
|
||||
constructor (private ctx: DataContextShell) {}
|
||||
|
||||
setLaunchpadSocketServer (socketServer: SocketIOServer | undefined) {
|
||||
this._launchpadSocketServer = socketServer
|
||||
}
|
||||
|
||||
setAppSocketServer (socketServer: SocketIOServer | undefined) {
|
||||
this._appSocketServer = socketServer
|
||||
}
|
||||
|
||||
init () {
|
||||
this.ctx._apis.busApi.on('menu:item:clicked', (logout) => {
|
||||
})
|
||||
}
|
||||
|
||||
toApp (...args: any[]) {
|
||||
this._appSocketServer?.emit('data-context-push', ...args)
|
||||
}
|
||||
|
||||
toLaunchpad (ev: string, ...args: any[]) {
|
||||
this._launchpadSocketServer?.emit('data-context-push', ...args)
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ export interface ProjectApiShape {
|
||||
removeProjectFromCache(projectRoot: string): void
|
||||
getProjectRootsFromCache(): Promise<string[]>
|
||||
clearLatestProjectsCache(): Promise<unknown>
|
||||
closeActiveProject(): Promise<unknown>
|
||||
}
|
||||
|
||||
export class ProjectActions {
|
||||
@@ -28,8 +29,9 @@ export class ProjectActions {
|
||||
return this.ctx._apis.projectApi
|
||||
}
|
||||
|
||||
clearActiveProject () {
|
||||
async clearActiveProject () {
|
||||
this.ctx.appData.activeProject = null
|
||||
await this.api.closeActiveProject()
|
||||
|
||||
return
|
||||
}
|
||||
@@ -98,8 +100,8 @@ export class ProjectActions {
|
||||
return this.projects
|
||||
}
|
||||
|
||||
async initializeActiveProject () {
|
||||
if (!this.ctx.activeProject?.projectRoot || !this.ctx.wizardData.chosenTestingType) {
|
||||
async initializeActiveProject (options: OpenProjectLaunchOptions = {}) {
|
||||
if (!this.ctx.activeProject?.projectRoot) {
|
||||
throw Error('Cannot initialize project without an active project')
|
||||
}
|
||||
|
||||
@@ -115,7 +117,18 @@ export class ProjectActions {
|
||||
testingType: this.ctx.wizardData.chosenTestingType,
|
||||
}
|
||||
|
||||
await this.api.initializeProject(launchArgs, this.ctx.launchOptions, browsers)
|
||||
try {
|
||||
await this.api.initializeProject(launchArgs, {
|
||||
...this.ctx.launchOptions,
|
||||
...options,
|
||||
ctx: this.ctx,
|
||||
}, browsers)
|
||||
} catch (e) {
|
||||
// TODO(tim): remove / replace with ctx.log.error
|
||||
// eslint-disable-next-line
|
||||
console.error(e)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
createProject () {
|
||||
@@ -153,7 +166,7 @@ export class ProjectActions {
|
||||
}
|
||||
}
|
||||
|
||||
async launchProject () {
|
||||
async launchProject (options: LaunchOpts = {}) {
|
||||
const browser = this.ctx.wizardData.chosenBrowser ?? this.ctx.appData.browsers?.[0]
|
||||
|
||||
if (!browser) {
|
||||
@@ -167,7 +180,7 @@ export class ProjectActions {
|
||||
specType: this.ctx.wizardData.chosenTestingType === 'e2e' ? 'integration' : 'component',
|
||||
}
|
||||
|
||||
return this.api.launchProject(browser, spec, {})
|
||||
return this.api.launchProject(browser, spec, options)
|
||||
}
|
||||
|
||||
removeProject (projectRoot: string) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
export * from './AppActions'
|
||||
export * from './AuthActions'
|
||||
export * from './DataEmitterActions'
|
||||
export * from './FileActions'
|
||||
export * from './ProjectActions'
|
||||
export * from './StorybookActions'
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export class DataEmitter {
|
||||
|
||||
//
|
||||
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
/* eslint-disable padding-line-between-statements */
|
||||
// created by autobarrel, do not modify directly
|
||||
|
||||
export * from './DataEmitter'
|
||||
export * from './coreDataShape'
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export type {
|
||||
export {
|
||||
DataContext,
|
||||
DataContextConfig,
|
||||
} from './DataContext'
|
||||
|
||||
export * from './makeDataContext'
|
||||
export type {
|
||||
DataContextConfig,
|
||||
} from './DataContext'
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { DataContext, DataContextConfig } from './DataContext'
|
||||
|
||||
/**
|
||||
* Creates & initializes a "Data Context" instance,
|
||||
*/
|
||||
export async function makeDataContext (config: DataContextConfig) {
|
||||
const ctx = new DataContext(config)
|
||||
|
||||
if (config.launchArgs.projectRoot) {
|
||||
await ctx.actions.project.setActiveProject(config.launchArgs.projectRoot)
|
||||
}
|
||||
|
||||
return ctx
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
],
|
||||
"compilerOptions": {
|
||||
"lib": ["es2020"],
|
||||
"importHelpers": true,
|
||||
"strict": true,
|
||||
"allowJs": false,
|
||||
"noImplicitAny": true,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"extends": "./../ts/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "ES2016",
|
||||
"lib": ["ES2018", "DOM", "DOM.Iterable"],
|
||||
"module": "commonjs",
|
||||
"allowJs": true,
|
||||
"noImplicitAny": false,
|
||||
|
||||
@@ -119,8 +119,9 @@ module.exports = {
|
||||
// we have an active debugger session
|
||||
if (inspector.url()) {
|
||||
const dp = process.debugPort + 1
|
||||
const inspectFlag = process.execArgv.includes('--inspect') ? '--inspect' : '--inspect-brk'
|
||||
|
||||
argv.unshift(`--inspect-brk=${dp}`)
|
||||
argv.unshift(`${inspectFlag}=${dp}`)
|
||||
} else {
|
||||
const opts = minimist(argv)
|
||||
|
||||
|
||||
@@ -17,6 +17,6 @@
|
||||
"componentFolder": "src/components"
|
||||
},
|
||||
"e2e": {
|
||||
"supportFile": false
|
||||
"supportFile": "cypress/e2e/support/e2eSupport.ts"
|
||||
}
|
||||
}
|
||||
|
||||
31
packages/frontend-shared/cypress/e2e/e2ePluginSetup.ts
Normal file
31
packages/frontend-shared/cypress/e2e/e2ePluginSetup.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import type { DataContext } from '@packages/data-context'
|
||||
|
||||
export async function e2ePluginSetup (projectRoot: string, on: Cypress.PluginEvents, config: Cypress.PluginConfigOptions) {
|
||||
// require'd so we don't import the types from @packages/server which would
|
||||
// pollute strict type checking
|
||||
const { runInternalServer } = require('@packages/server/lib/modes/internal-server')
|
||||
|
||||
process.env.CYPRESS_INTERNAL_E2E_TESTING_SELF = 'true'
|
||||
const { serverPortPromise, ctx } = runInternalServer({
|
||||
projectRoot,
|
||||
}) as {ctx: DataContext, serverPortPromise: Promise<number>}
|
||||
|
||||
on('task', {
|
||||
async withCtx (fnString: string) {
|
||||
await serverPortPromise
|
||||
|
||||
return new Function('ctx', `return (${fnString})(ctx)`).call(undefined, ctx)
|
||||
},
|
||||
async resetCtxState () {
|
||||
return ctx.dispose()
|
||||
},
|
||||
getGraphQLPort () {
|
||||
return serverPortPromise
|
||||
},
|
||||
getAppServerPort () {
|
||||
return ctx.appServerPort ?? null
|
||||
},
|
||||
})
|
||||
|
||||
return config
|
||||
}
|
||||
27
packages/frontend-shared/cypress/e2e/support/e2eSupport.ts
Normal file
27
packages/frontend-shared/cypress/e2e/support/e2eSupport.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { DataContext } from '@packages/data-context'
|
||||
|
||||
const SIXTY_SECONDS = 60 * 1000
|
||||
|
||||
declare global {
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
withCtx(fn: (ctx: DataContext) => any): Chainable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cypress.Commands.add('withCtx', (fn) => {
|
||||
const _log = Cypress.log({
|
||||
name: 'withCtx',
|
||||
message: '(view in console)',
|
||||
consoleProps () {
|
||||
return {
|
||||
'Executed': fn.toString(),
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
cy.task('withCtx', fn.toString(), { timeout: SIXTY_SECONDS, log: false }).then(() => {
|
||||
_log.end()
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import _ from 'lodash'
|
||||
import { randomComponents } from '../../../src/graphql/specs/testStubSpecs'
|
||||
import { randomComponents } from './testStubSpecs'
|
||||
import config from '../../fixtures/config.json'
|
||||
|
||||
import type {
|
||||
|
||||
4
packages/frontend-shared/env.d.ts
vendored
4
packages/frontend-shared/env.d.ts
vendored
@@ -1,4 +0,0 @@
|
||||
// Unsure why the ImportMeta type isn't picking this up.
|
||||
interface ImportMetaEnv {
|
||||
VITE_CYPRESS_INTERNAL_GQL_PORT: string
|
||||
}
|
||||
@@ -3,18 +3,22 @@ import {
|
||||
createClient,
|
||||
dedupExchange,
|
||||
errorExchange,
|
||||
Exchange,
|
||||
fetchExchange,
|
||||
Exchange,
|
||||
} from '@urql/core'
|
||||
import { devtoolsExchange } from '@urql/devtools'
|
||||
import VueToast, { ToastPluginApi } from 'vue-toast-notification'
|
||||
import { client } from '@packages/socket/lib/browser'
|
||||
|
||||
import 'vue-toast-notification/dist/theme-sugar.css'
|
||||
|
||||
export { VueToast }
|
||||
|
||||
import { cacheExchange as graphcacheExchange } from '@urql/exchange-graphcache'
|
||||
import { pubSubExchange } from './urqlExchangePubsub'
|
||||
|
||||
import { GRAPHQL_URL } from '../utils/env'
|
||||
const GQL_PORT_MATCH = /gqlPort=(\d+)/.exec(window.location.search)
|
||||
const SERVER_PORT_MATCH = /serverPort=(\d+)/.exec(window.location.search)
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@@ -32,9 +36,30 @@ export function makeCacheExchange () {
|
||||
})
|
||||
}
|
||||
|
||||
export function makeUrqlClient (): Client {
|
||||
export function makeUrqlClient (target: 'launchpad' | 'app'): Client {
|
||||
let gqlPort: string
|
||||
|
||||
if (GQL_PORT_MATCH) {
|
||||
gqlPort = GQL_PORT_MATCH[1]
|
||||
} else {
|
||||
// @ts-ignore
|
||||
gqlPort = window.__CYPRESS_GRAPHQL_PORT__
|
||||
}
|
||||
|
||||
if (!gqlPort) {
|
||||
throw new Error(`${window.location.href} cannot be visited without a gqlPort`)
|
||||
}
|
||||
|
||||
const GRAPHQL_URL = `http://localhost:${gqlPort}/graphql`
|
||||
|
||||
// If we're in the launchpad, we connect to the known GraphQL Socket port,
|
||||
// otherwise we connect to the /__socket.io of the current domain, unless we've explicitly
|
||||
//
|
||||
const io = getPubSubSource({ target, gqlPort, serverPort: SERVER_PORT_MATCH?.[1] })
|
||||
|
||||
const exchanges: Exchange[] = [
|
||||
dedupExchange,
|
||||
pubSubExchange(io),
|
||||
errorExchange({
|
||||
onError (error) {
|
||||
const message = `
|
||||
@@ -53,6 +78,9 @@ export function makeUrqlClient (): Client {
|
||||
}),
|
||||
// https://formidable.com/open-source/urql/docs/graphcache/errors/
|
||||
makeCacheExchange(),
|
||||
// TODO(tim): add this when we want to use the socket as the GraphQL
|
||||
// transport layer for all operations
|
||||
// target === 'launchpad' ? fetchExchange : socketExchange(io),
|
||||
fetchExchange,
|
||||
]
|
||||
|
||||
@@ -66,3 +94,40 @@ export function makeUrqlClient (): Client {
|
||||
exchanges,
|
||||
})
|
||||
}
|
||||
|
||||
interface PubSubConfig {
|
||||
target: 'launchpad' | 'app'
|
||||
gqlPort: string
|
||||
serverPort?: string
|
||||
}
|
||||
|
||||
function getPubSubSource (config: PubSubConfig) {
|
||||
if (config.target === 'launchpad') {
|
||||
return client(`http://localhost:${config.gqlPort}`, {
|
||||
path: '/__gqlSocket',
|
||||
transports: ['websocket'],
|
||||
})
|
||||
}
|
||||
|
||||
// Only happens during testing
|
||||
if (config.serverPort) {
|
||||
return client(`http://localhost:${config.serverPort}`, {
|
||||
path: '/__socket.io',
|
||||
transports: ['websocket'],
|
||||
})
|
||||
}
|
||||
|
||||
return client({
|
||||
path: '/__socket.io',
|
||||
transports: ['websocket'],
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(tim): add this when we want to use the socket as the GraphQL
|
||||
// transport layer for all operations
|
||||
// const socketExchange = (io: Socket): Exchange => {
|
||||
// return (input) => {
|
||||
// return (ops$) => {
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
40
packages/frontend-shared/src/graphql/urqlExchangePubsub.ts
Normal file
40
packages/frontend-shared/src/graphql/urqlExchangePubsub.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { pipe, tap } from 'wonka'
|
||||
import type { Exchange, Operation } from '@urql/core'
|
||||
import type { Socket } from '@packages/socket/lib/browser'
|
||||
|
||||
export const pubSubExchange = (io: Socket): Exchange => {
|
||||
return ({ client, forward }) => {
|
||||
return (ops$) => {
|
||||
if (typeof window === 'undefined') {
|
||||
return forward(ops$)
|
||||
}
|
||||
|
||||
const watchedOperations = new Map<number, Operation>()
|
||||
const observedOperations = new Map<number, number>()
|
||||
|
||||
io.on('data-context-push', (...args) => {
|
||||
watchedOperations.forEach((op) => {
|
||||
client.reexecuteOperation(
|
||||
client.createRequestOperation('query', op, {
|
||||
requestPolicy: 'cache-and-network',
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
const processIncomingOperation = (op: Operation) => {
|
||||
if (op.kind === 'query' && !observedOperations.has(op.key)) {
|
||||
observedOperations.set(op.key, 1)
|
||||
watchedOperations.set(op.key, op)
|
||||
}
|
||||
|
||||
if (op.kind === 'teardown' && observedOperations.has(op.key)) {
|
||||
observedOperations.delete(op.key)
|
||||
watchedOperations.delete(op.key)
|
||||
}
|
||||
}
|
||||
|
||||
return forward(pipe(ops$, tap(processIncomingOperation)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
// This code is meant to be executed within Vite
|
||||
// which supports environment variables being injected into the client at build time
|
||||
|
||||
export const GRAPHQL_PORT = import.meta.env.VITE_CYPRESS_INTERNAL_GQL_PORT || `${52200}`
|
||||
|
||||
export const GRAPHQL_URL = `http://localhost:${GRAPHQL_PORT}/graphql`
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Basic Options */
|
||||
"target": "esnext",
|
||||
"target": "ES2018",
|
||||
"module": "esnext",
|
||||
"lib": ["dom", "ESNext"],
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"build-prod": "tsc || echo 'built, with errors'",
|
||||
"check-ts": "tsc --noEmit",
|
||||
"clean-deps": "rimraf node_modules",
|
||||
"clean": "rimraf ./src/*.js ./src/**/*.js ./src/**/**/*.js ./test/**/*.js || echo 'cleaned'",
|
||||
"clean": "rimraf './{src,test}/**/*.js'",
|
||||
"postinstall": "echo '@packages/graphql needs: yarn build'",
|
||||
"test-unit": "mocha -r @packages/ts/register test/unit/**/*.spec.ts --config ./test/.mocharc.js --exit",
|
||||
"test-integration": "mocha -r @packages/ts/register test/integration/**/*.spec.ts --config ./test/.mocharc.js --exit"
|
||||
@@ -18,7 +18,6 @@
|
||||
"@graphql-tools/delegate": "8.2.1",
|
||||
"@graphql-tools/utils": "8.2.3",
|
||||
"@graphql-tools/wrap": "8.1.1",
|
||||
"cors": "2.8.5",
|
||||
"cross-fetch": "^3.1.4",
|
||||
"dedent": "^0.7.0",
|
||||
"express": "4.17.1",
|
||||
|
||||
@@ -284,6 +284,8 @@ type Mutation {
|
||||
"""
|
||||
initializeOpenProject: Wizard
|
||||
internal_clearLatestProjectCache: Boolean
|
||||
internal_triggerIpcToApp: Boolean
|
||||
internal_triggerIpcToLaunchpad(msg: String!): Boolean
|
||||
|
||||
"""Launches project from open_project global singleton"""
|
||||
launchOpenProject: App
|
||||
|
||||
@@ -4,6 +4,27 @@ import { Wizard } from './gql-Wizard'
|
||||
|
||||
export const mutation = mutationType({
|
||||
definition (t) {
|
||||
t.field('internal_triggerIpcToLaunchpad', {
|
||||
type: 'Boolean',
|
||||
args: {
|
||||
msg: nonNull(stringArg()),
|
||||
},
|
||||
resolve: (root, args, ctx) => {
|
||||
ctx.emitter.toLaunchpad(args.msg)
|
||||
|
||||
return true
|
||||
},
|
||||
})
|
||||
|
||||
t.field('internal_triggerIpcToApp', {
|
||||
type: 'Boolean',
|
||||
resolve: (root, args, ctx) => {
|
||||
ctx.emitter.toApp('someData')
|
||||
|
||||
return true
|
||||
},
|
||||
})
|
||||
|
||||
t.field('internal_clearLatestProjectCache', {
|
||||
type: 'Boolean',
|
||||
resolve: (source, args, ctx) => {
|
||||
|
||||
@@ -1,82 +1,16 @@
|
||||
import { graphqlHTTP } from 'express-graphql'
|
||||
import express from 'express'
|
||||
import Debug from 'debug'
|
||||
import type { Server } from 'http'
|
||||
import type { AddressInfo } from 'net'
|
||||
import cors from 'cors'
|
||||
import getenv from 'getenv'
|
||||
import { graphqlSchema } from './schema'
|
||||
import type { DataContext } from '@packages/data-context'
|
||||
import type express from 'express'
|
||||
|
||||
const debug = Debug('cypress:server:graphql')
|
||||
const GRAPHQL_PORT = getenv.int('CYPRESS_INTERNAL_GQL_PORT', 52200)
|
||||
|
||||
let app: ReturnType<typeof express>
|
||||
let server: Server
|
||||
|
||||
export function closeGraphQLServer (): Promise<void | null> {
|
||||
if (!server || !server.listening) {
|
||||
return Promise.resolve(null)
|
||||
}
|
||||
|
||||
return new Promise<void | null>((res, rej) => {
|
||||
server.close((err) => {
|
||||
if (err) {
|
||||
rej(err)
|
||||
}
|
||||
|
||||
res(null)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// singleton during the lifetime of the application
|
||||
let dataContext: DataContext | undefined
|
||||
|
||||
// Injected this way, since we want to set this up where the IPC layer
|
||||
// is established in the server package, which should be an independent
|
||||
// layer from GraphQL
|
||||
export function setDataContext (ctx: DataContext) {
|
||||
dataContext = ctx
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
export function startGraphQLServer ({ port }: { port: number } = { port: GRAPHQL_PORT }): Promise<{
|
||||
server: Server
|
||||
app: Express.Application
|
||||
endpoint: string
|
||||
}> {
|
||||
app = express()
|
||||
app.use(cors())
|
||||
export function addGraphQLHTTP (app: ReturnType<typeof express>, context: DataContext) {
|
||||
app.use('/graphql', graphqlHTTP((req) => {
|
||||
if (!dataContext) {
|
||||
throw new Error(`setDataContext has not been called`)
|
||||
}
|
||||
|
||||
return {
|
||||
schema: graphqlSchema,
|
||||
graphiql: true,
|
||||
context: dataContext,
|
||||
context,
|
||||
}
|
||||
}))
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
server = app.listen(port, () => {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
/* eslint-disable-next-line no-console */
|
||||
console.log(`GraphQL server is running at http://localhost:${port}/graphql`)
|
||||
}
|
||||
|
||||
const endpoint = `http://localhost:${(server.address() as AddressInfo).port}/graphql`
|
||||
|
||||
debug(`GraphQL Server at ${endpoint}`)
|
||||
|
||||
return resolve({
|
||||
server,
|
||||
endpoint,
|
||||
app,
|
||||
})
|
||||
})
|
||||
})
|
||||
return app
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
"script"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2020"],
|
||||
"importHelpers": true,
|
||||
"strict": true,
|
||||
"allowJs": false,
|
||||
"noImplicitAny": true,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"projectId": "sehy69",
|
||||
"baseUrl": "http://localhost:5555",
|
||||
"viewportWidth": 800,
|
||||
"viewportHeight": 850,
|
||||
"retries": {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { longBrowsersList } from '@packages/frontend-shared/cypress/support/mock-graphql/stubgql-App'
|
||||
@@ -1,6 +1,14 @@
|
||||
let GQL_PORT
|
||||
|
||||
describe('Launchpad', () => {
|
||||
before(() => {
|
||||
cy.task('getGraphQLPort').then((port) => {
|
||||
GQL_PORT = port
|
||||
})
|
||||
})
|
||||
|
||||
it('resolves the home page', () => {
|
||||
cy.visit('http://localhost:5555')
|
||||
cy.visit(`dist/index.html?gqlPort=${GQL_PORT}`)
|
||||
cy.get('h1').should('contain', 'Welcome')
|
||||
})
|
||||
})
|
||||
|
||||
23
packages/launchpad/cypress/plugins/index.ts
Normal file
23
packages/launchpad/cypress/plugins/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/// <reference types="cypress" />
|
||||
const { monorepoPaths } = require('../../../../scripts/gulp/monorepoPaths')
|
||||
import { e2ePluginSetup } from '@packages/frontend-shared/cypress/e2e/e2ePluginSetup'
|
||||
|
||||
// ***********************************************************
|
||||
// This example plugins/index.js can be used to load plugins
|
||||
//
|
||||
// You can change the location of this file or turn off loading
|
||||
// the plugins file with the 'pluginsFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/plugins-guide
|
||||
// ***********************************************************
|
||||
|
||||
// This function is called when a project is opened or re-opened (e.g. due to
|
||||
// the project's config changing)
|
||||
|
||||
/**
|
||||
* @type {Cypress.PluginConfig}
|
||||
*/
|
||||
export default async (on, config) => {
|
||||
return await e2ePluginSetup(monorepoPaths.pkgLaunchpad, on, config)
|
||||
}
|
||||
@@ -98,6 +98,7 @@
|
||||
"prismjs",
|
||||
"prismjs/components/prism-typescript",
|
||||
"prismjs/components/prism-yaml",
|
||||
"socket.io-client",
|
||||
"vue",
|
||||
"vue-demi",
|
||||
"vue-i18n",
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { gql, useQuery } from '@urql/vue'
|
||||
import { MainQueryDocument } from './generated/graphql'
|
||||
import { MainLaunchpadQueryDocument } from './generated/graphql'
|
||||
import TestingTypeCards from './setup/TestingTypeCards.vue'
|
||||
import Wizard from './setup/Wizard.vue'
|
||||
import WizardHeader from './setup/WizardHeader.vue'
|
||||
@@ -37,7 +37,7 @@ import GlobalPage from './global/GlobalPage.vue'
|
||||
import BaseError from './error/BaseError.vue'
|
||||
|
||||
gql`
|
||||
query MainQuery {
|
||||
query MainLaunchpadQuery {
|
||||
...TestingTypeCards
|
||||
...Wizard
|
||||
|
||||
@@ -54,5 +54,5 @@ query MainQuery {
|
||||
}
|
||||
`
|
||||
|
||||
const query = useQuery({ query: MainQueryDocument })
|
||||
const query = useQuery({ query: MainLaunchpadQueryDocument })
|
||||
</script>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { createI18n } from '@cy/i18n'
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(VueToast)
|
||||
app.use(urql, makeUrqlClient())
|
||||
app.use(urql, makeUrqlClient('launchpad'))
|
||||
app.use(createI18n())
|
||||
|
||||
window.$app = app.mount('#app')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { OpenBrowserListFragmentDoc } from '../generated/graphql-test'
|
||||
import OpenBrowserList from './OpenBrowserList.vue'
|
||||
import { longBrowsersList } from '../../cypress/fixtures/browsers/long-browsers-list'
|
||||
import { longBrowsersList } from '@packages/frontend-shared/cypress/support/mock-graphql/stubgql-App'
|
||||
|
||||
const launchButtonSelector = 'button[data-testid=launch-button]'
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Url } from 'url'
|
||||
import { URL, Url } from 'url'
|
||||
import debugModule from 'debug'
|
||||
import minimatch from 'minimatch'
|
||||
import Forge from 'node-forge'
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build-prod": "tsc --project .",
|
||||
"clean": "rimraf lib/*.js || echo 'cleaned'",
|
||||
"clean": "rimraf 'lib/**/*.js'",
|
||||
"clean-deps": "rimraf node_modules",
|
||||
"test": "yarn test-unit",
|
||||
"test-debug": "yarn test-unit --inspect-brk=5566",
|
||||
|
||||
@@ -9,7 +9,7 @@ import tls from 'tls'
|
||||
import url from 'url'
|
||||
import DebuggingProxy from '@cypress/debugging-proxy'
|
||||
import request from '@cypress/request-promise'
|
||||
import * as socketIo from '@packages/socket'
|
||||
import * as socketIo from '@packages/socket/lib/browser'
|
||||
import {
|
||||
buildConnectReqHead,
|
||||
createProxySock,
|
||||
|
||||
@@ -11,6 +11,7 @@ import { InterceptResponse } from '@packages/net-stubbing'
|
||||
import { PassThrough, Readable } from 'stream'
|
||||
import * as rewriter from './util/rewriter'
|
||||
import zlib from 'zlib'
|
||||
import { URL } from 'url'
|
||||
|
||||
export type ResponseMiddleware = HttpMiddleware<{
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build-prod": "tsc --project .",
|
||||
"clean": "rimraf 'lib/**/*.js'",
|
||||
"clean-deps": "rimraf node_modules",
|
||||
"run-mocha": "mocha -r @packages/ts/register -r test/pretest.ts --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json",
|
||||
"test": "yarn run-mocha \"test/integration/*.spec.ts\" \"test/unit/**/*.spec.ts\"",
|
||||
|
||||
@@ -7,13 +7,7 @@ export type RunnerPkg = 'app' | 'runner' | 'runner-ct'
|
||||
type FoldersWithDist = 'static' | 'driver' | RunnerPkg
|
||||
|
||||
export const getPathToDist = (folder: FoldersWithDist, ...args: string[]) => {
|
||||
let distDir = 'dist'
|
||||
|
||||
if (process.env.CYPRESS_INTERNAL_E2E_TESTING_SELF) {
|
||||
distDir = 'dist-e2e'
|
||||
}
|
||||
|
||||
return path.join(...[__dirname, '..', '..', folder, distDir, ...args])
|
||||
return path.join(...[__dirname, '..', '..', folder, 'dist', ...args])
|
||||
}
|
||||
|
||||
export const getRunnerInjectionContents = () => {
|
||||
@@ -26,18 +20,12 @@ export const getPathToIndex = (pkg: RunnerPkg) => {
|
||||
return getPathToDist(pkg, 'index.html')
|
||||
}
|
||||
|
||||
export const getPathToDesktopIndex = (pkg: 'desktop-gui' | 'launchpad') => {
|
||||
let distDir = 'dist'
|
||||
|
||||
export const getPathToDesktopIndex = (pkg: 'desktop-gui' | 'launchpad', graphqlPort?: number) => {
|
||||
// For now, if we see that there's a CYPRESS_INTERNAL_VITE_LAUNCHPAD_PORT
|
||||
// we assume we're running Cypress targeting that (dev server)
|
||||
if (pkg === 'launchpad' && process.env.CYPRESS_INTERNAL_VITE_LAUNCHPAD_PORT) {
|
||||
return `http://localhost:${process.env.CYPRESS_INTERNAL_VITE_LAUNCHPAD_PORT}`
|
||||
return `http://localhost:${process.env.CYPRESS_INTERNAL_VITE_LAUNCHPAD_PORT}?gqlPort=${graphqlPort}`
|
||||
}
|
||||
|
||||
if (process.env.CYPRESS_INTERNAL_E2E_TESTING_SELF) {
|
||||
distDir = 'dist-e2e'
|
||||
}
|
||||
|
||||
return `file://${path.join(__dirname, '..', '..', pkg, distDir, 'index.html')}`
|
||||
return `file://${path.join(__dirname, '..', '..', pkg, 'dist', 'index.html')}?gqlPort=${graphqlPort}`
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build-prod": "tsc --project .",
|
||||
"clean": "rimraf lib/*.js || echo 'cleaned'",
|
||||
"clean": "rimraf 'lib/**/*.js'",
|
||||
"clean-deps": "rimraf node_modules",
|
||||
"test": "yarn test-unit",
|
||||
"test-debug": "yarn test-unit --inspect-brk=5566",
|
||||
|
||||
@@ -21,7 +21,7 @@ const _debugOpts = !debug.enabled ? _.noop : (opts: RewriteOpts) => {
|
||||
// because it does not require importing @packages/ts like development does.
|
||||
// this has a huge performance impact, bringing the `responsiveMs` for threads
|
||||
// from ~1s to about ~300ms on my system
|
||||
const WORKER_FILENAME = process.env.CYPRESS_INTERNAL_ENV === 'production' ? 'worker.js' : 'worker-shim.js'
|
||||
const WORKER_FILENAME = process.env.CYPRESS_INTERNAL_ENV === 'production' ? 'worker.js' : '../../script/worker-shim.js'
|
||||
|
||||
const WORKER_PATH = path.join(__dirname, WORKER_FILENAME)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"scripts": {
|
||||
"build-prod": "tsc --project .",
|
||||
"build-test": "yarn build-prod --noEmit",
|
||||
"clean": "rimraf 'lib/**/*.js'",
|
||||
"clean-deps": "rimraf node_modules",
|
||||
"test": "mocha --reporter mocha-multi-reporters --reporter-options configFile=../../mocha-reporter-config.json"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Moved outside of /lib so we can rm -rf "lib/**/*.js" without deleting this
|
||||
if (process.env.CYPRESS_INTERNAL_ENV === 'production') {
|
||||
throw new Error(`${__filename} should only run outside of prod`)
|
||||
}
|
||||
|
||||
require('@packages/ts/register')
|
||||
require('./worker.ts')
|
||||
require('../lib/threads/worker.ts')
|
||||
@@ -57,7 +57,7 @@
|
||||
"sockjs-client": "^1.5.0",
|
||||
"strip-ansi": "6.0.0",
|
||||
"ts-loader": "^8.0.5",
|
||||
"ts-node": "8.3.0",
|
||||
"ts-node": "^10.2.1",
|
||||
"watch": "^1.0.2",
|
||||
"webpack": "4.44.2"
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ import { EventEmitter } from 'events'
|
||||
import Promise from 'bluebird'
|
||||
import { action } from 'mobx'
|
||||
|
||||
import { client } from '@packages/socket'
|
||||
import { client } from '@packages/socket/lib/browser'
|
||||
import type { BaseStore } from './store'
|
||||
|
||||
import { studioRecorder } from './studio'
|
||||
@@ -14,11 +14,15 @@ import { selectorPlaygroundModel } from './selector-playground'
|
||||
import $Cypress from '@packages/driver'
|
||||
import type { automationElementId } from './automation-element'
|
||||
|
||||
const $ = $Cypress.$
|
||||
const ws = client.connect({
|
||||
const PORT_MATCH = /serverPort=(\d+)/.exec(window.location.search)
|
||||
|
||||
const socketConfig = {
|
||||
path: '/__socket.io',
|
||||
transports: ['websocket'],
|
||||
})
|
||||
}
|
||||
|
||||
const $ = $Cypress.$
|
||||
const ws = PORT_MATCH ? client(`http://localhost:${PORT_MATCH[1]}`, socketConfig) : client(socketConfig)
|
||||
|
||||
ws.on('connect', () => {
|
||||
ws.emit('runner:connected')
|
||||
|
||||
@@ -19,9 +19,11 @@ register({
|
||||
},
|
||||
})
|
||||
|
||||
const io = returnMockRequire('@packages/socket/lib/browser', { client: {} })
|
||||
|
||||
io.client.connect = sinon.stub().returns({ emit: () => {}, on: () => {} })
|
||||
returnMockRequire('@packages/socket/lib/browser', {
|
||||
client () {
|
||||
return { emit: () => {}, on: () => {} }
|
||||
},
|
||||
})
|
||||
|
||||
const _useFakeTimers = sinon.useFakeTimers
|
||||
let timers = []
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"extends": "../ts/tsconfig.json",
|
||||
"extends": "../ts/tsconfig.dom.json",
|
||||
"compilerOptions": {
|
||||
"jsx": "react",
|
||||
"experimentalDecorators": true
|
||||
|
||||
@@ -19,9 +19,11 @@ register({
|
||||
},
|
||||
})
|
||||
|
||||
const io = returnMockRequire('@packages/socket/lib/browser', { client: {} })
|
||||
|
||||
io.client.connect = sinon.stub().returns({ emit: () => {}, on: () => {} })
|
||||
returnMockRequire('@packages/socket/lib/browser', {
|
||||
client () {
|
||||
return { emit: () => {}, on: () => {} }
|
||||
},
|
||||
})
|
||||
|
||||
const _useFakeTimers = sinon.useFakeTimers
|
||||
let timers = []
|
||||
|
||||
@@ -11,7 +11,6 @@ const errors = require('../errors')
|
||||
const machineId = require('../util/machine_id')
|
||||
const random = require('../util/random')
|
||||
const user = require('../user')
|
||||
const windows = require('./windows')
|
||||
|
||||
let app
|
||||
let authCallback
|
||||
@@ -101,7 +100,7 @@ const start = (onMessage, utmCode) => {
|
||||
})
|
||||
.finally(() => {
|
||||
_stopServer()
|
||||
windows.focusMainWindow()
|
||||
require('./windows').focusMainWindow()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ const { clipboard } = require('electron')
|
||||
const debug = require('debug')('cypress:server:events')
|
||||
const pluralize = require('pluralize')
|
||||
const stripAnsi = require('strip-ansi')
|
||||
|
||||
const dialog = require('./dialog')
|
||||
const pkg = require('./package')
|
||||
const logs = require('./logs')
|
||||
@@ -26,21 +27,11 @@ const fileOpener = require('../util/file-opener')
|
||||
const api = require('../api')
|
||||
const savedState = require('../saved_state')
|
||||
|
||||
import * as config from '../config'
|
||||
import auth from './auth'
|
||||
import user from '../user'
|
||||
import { openProject } from '../open_project'
|
||||
import specsUtil from '../util/specs'
|
||||
|
||||
import { setDataContext, startGraphQLServer } from '@packages/graphql/src/server'
|
||||
import { getProjectRoots, insertProject, removeLatestProjects, removeProject } from '@packages/server/lib/cache'
|
||||
import { checkAuthQuery } from '@packages/graphql/src/stitching/remoteGraphQLCalls'
|
||||
import type { FindSpecs, FoundBrowser, LaunchArgs, LaunchOpts, OpenProjectLaunchOptions } from '@packages/types'
|
||||
import type { LaunchArgs } from '@packages/types'
|
||||
import type { EventEmitter } from 'events'
|
||||
import { makeDataContext } from '@packages/data-context'
|
||||
import browserUtils from '../browsers/utils'
|
||||
|
||||
const { getBrowsers } = browserUtils
|
||||
|
||||
const nullifyUnserializableValues = (obj) => {
|
||||
// nullify values that cannot be cloned
|
||||
@@ -167,7 +158,7 @@ const handleEvent = function (options, bus, event, id, type, arg) {
|
||||
})
|
||||
|
||||
return openProject.launch(arg.browser, fullSpec, {
|
||||
// TODO: Tim see why this
|
||||
// TODO: Tim see why this "projectRoot" is passed along
|
||||
projectRoot: options.projectRoot,
|
||||
onBrowserOpen () {
|
||||
return send({ browserOpened: true })
|
||||
@@ -495,7 +486,11 @@ const handleEvent = function (options, bus, event, id, type, arg) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
interface EventsStartArgs extends LaunchArgs {
|
||||
onFocusTests: () => void
|
||||
}
|
||||
|
||||
export = {
|
||||
nullifyUnserializableValues,
|
||||
|
||||
handleEvent,
|
||||
@@ -504,72 +499,8 @@ module.exports = {
|
||||
return ipc.removeAllListeners()
|
||||
},
|
||||
|
||||
async start (options: LaunchArgs, bus: EventEmitter, { startGraphQL } = { startGraphQL: true }) {
|
||||
async start (options: EventsStartArgs, bus: EventEmitter) {
|
||||
// curry left options
|
||||
ipc.on('request', _.partial(this.handleEvent, options, bus))
|
||||
|
||||
// support not starting server for testing purposes.
|
||||
if (!startGraphQL) {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Figure out how we want to cleanup & juggle the config, so it's not jammed
|
||||
// into the projects
|
||||
startGraphQLServer()
|
||||
|
||||
const ctx = await makeDataContext({
|
||||
launchArgs: options,
|
||||
launchOptions: {},
|
||||
appApi: {
|
||||
getBrowsers () {
|
||||
return getBrowsers()
|
||||
},
|
||||
},
|
||||
authApi: {
|
||||
logIn () {
|
||||
return auth.start(() => {}, 'launchpad')
|
||||
},
|
||||
logOut () {
|
||||
return user.logOut()
|
||||
},
|
||||
checkAuth (context) {
|
||||
return checkAuthQuery(context)
|
||||
},
|
||||
},
|
||||
projectApi: {
|
||||
getConfig (projectRoot: string) {
|
||||
return config.get(projectRoot)
|
||||
},
|
||||
launchProject (browser: FoundBrowser, spec: Cypress.Spec, options?: LaunchOpts) {
|
||||
return openProject.launch({ ...browser }, spec, options)
|
||||
},
|
||||
initializeProject (args: LaunchArgs, options: OpenProjectLaunchOptions, browsers: FoundBrowser[]) {
|
||||
return openProject.create(args.projectRoot, args, options, browsers)
|
||||
},
|
||||
insertProjectToCache (projectRoot: string) {
|
||||
insertProject(projectRoot)
|
||||
},
|
||||
removeProjectFromCache (projectRoot: string) {
|
||||
removeProject(projectRoot)
|
||||
},
|
||||
getProjectRootsFromCache () {
|
||||
return getProjectRoots()
|
||||
},
|
||||
findSpecs (payload: FindSpecs) {
|
||||
return specsUtil.findSpecs(payload)
|
||||
},
|
||||
clearLatestProjectsCache () {
|
||||
return removeLatestProjects()
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Fetch the browsers when the app starts, so we have some by
|
||||
// the time we're continuing.
|
||||
ctx.actions.app.refreshBrowsers()
|
||||
// load projects from cache on start
|
||||
ctx.actions.project.loadProjects()
|
||||
|
||||
setDataContext(ctx)
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import _ from 'lodash'
|
||||
import { shell } from 'electron'
|
||||
import { URL, URLSearchParams } from 'url'
|
||||
|
||||
// NOTE: in order for query params to be passed through on links
|
||||
// forwardQueryParams: true must be set for that slug in the on package
|
||||
|
||||
64
packages/server/lib/gui/makeGraphQLServer.ts
Normal file
64
packages/server/lib/gui/makeGraphQLServer.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import express from 'express'
|
||||
import { addGraphQLHTTP } from '@packages/graphql/src/server'
|
||||
import type { AddressInfo } from 'net'
|
||||
import type { DataContext } from '@packages/data-context'
|
||||
import pDefer from 'p-defer'
|
||||
import cors from 'cors'
|
||||
import type { Server } from 'http'
|
||||
import { SocketIOServer } from '@packages/socket'
|
||||
|
||||
let graphqlServer: Server | undefined
|
||||
|
||||
export async function closeGraphQLServer () {
|
||||
if (!graphqlServer) {
|
||||
return
|
||||
}
|
||||
|
||||
const dfd = pDefer()
|
||||
|
||||
graphqlServer.close((err) => {
|
||||
if (err) {
|
||||
dfd.reject()
|
||||
}
|
||||
|
||||
dfd.resolve()
|
||||
})
|
||||
|
||||
graphqlServer = undefined
|
||||
|
||||
dfd.promise
|
||||
}
|
||||
|
||||
export async function makeGraphQLServer (ctx: DataContext) {
|
||||
const dfd = pDefer<number>()
|
||||
const app = express()
|
||||
|
||||
app.use(cors())
|
||||
|
||||
// TODO: Figure out how we want to cleanup & juggle the config, so
|
||||
// it's not jammed into the projects
|
||||
addGraphQLHTTP(app, ctx)
|
||||
|
||||
const srv = graphqlServer = app.listen(() => {
|
||||
const port = (srv.address() as AddressInfo).port
|
||||
const endpoint = `http://localhost:${port}/graphql`
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
/* eslint-disable-next-line no-console */
|
||||
console.log(`GraphQL server is running at ${endpoint}`)
|
||||
}
|
||||
|
||||
ctx.debug(`GraphQL Server at ${endpoint}`)
|
||||
|
||||
dfd.resolve(port)
|
||||
})
|
||||
|
||||
const socketServer = new SocketIOServer(srv, {
|
||||
path: '/__gqlSocket',
|
||||
transports: ['websocket'],
|
||||
})
|
||||
|
||||
ctx.emitter.setLaunchpadSocketServer(socketServer)
|
||||
|
||||
return dfd.promise
|
||||
}
|
||||
@@ -13,19 +13,20 @@ export type WindowOptions = Electron.BrowserWindowConstructorOptions & {
|
||||
type?: 'INDEX'
|
||||
url?: string
|
||||
devTools?: boolean
|
||||
graphqlPort?: number
|
||||
}
|
||||
|
||||
let windows = {}
|
||||
let recentlyCreatedWindow = false
|
||||
|
||||
const getUrl = function (type) {
|
||||
const getUrl = function (type, port?: number) {
|
||||
switch (type) {
|
||||
case 'INDEX':
|
||||
if (process.env.LAUNCHPAD) {
|
||||
return getPathToDesktopIndex('launchpad')
|
||||
return getPathToDesktopIndex('launchpad', port)
|
||||
}
|
||||
|
||||
return getPathToDesktopIndex('desktop-gui')
|
||||
return getPathToDesktopIndex('desktop-gui', port)
|
||||
|
||||
default:
|
||||
throw new Error(`No acceptable window type found for: '${type}'`)
|
||||
@@ -158,14 +159,6 @@ export function create (projectRoot, _options: WindowOptions = {}, newBrowserWin
|
||||
options.webPreferences.partition = options.partition
|
||||
}
|
||||
|
||||
// When we're E2E testing the launchpad or app, we want to stand up a real Cy server.
|
||||
// It's best to do this without rendering the launchpad, so we won't visually render the electron window.
|
||||
// TODO(jess): Is it better to stub the electron window? The server is pretty coupled to it.
|
||||
if (process.env.CYPRESS_INTERNAL_E2E_TESTING_SELF) {
|
||||
options.frame = false
|
||||
options.show = false
|
||||
}
|
||||
|
||||
const win = newBrowserWindow(options)
|
||||
|
||||
win.on('blur', function (...args) {
|
||||
@@ -223,7 +216,7 @@ export function create (projectRoot, _options: WindowOptions = {}, newBrowserWin
|
||||
}
|
||||
|
||||
// open desktop-gui BrowserWindow
|
||||
export function open (projectRoot, options: WindowOptions = {}, newBrowserWindow = _newBrowserWindow) {
|
||||
export function open (projectRoot, graphqlPort: number | undefined, options: WindowOptions = {}, newBrowserWindow = _newBrowserWindow): Bluebird<BrowserWindow> {
|
||||
// if we already have a window open based
|
||||
// on that type then just show + focus it!
|
||||
let win
|
||||
@@ -249,7 +242,7 @@ export function open (projectRoot, options: WindowOptions = {}, newBrowserWindow
|
||||
})
|
||||
|
||||
if (!options.url) {
|
||||
options.url = getUrl(options.type)
|
||||
options.url = getUrl(options.type, graphqlPort)
|
||||
}
|
||||
|
||||
win = create(projectRoot, options, newBrowserWindow)
|
||||
|
||||
71
packages/server/lib/makeDataContext.ts
Normal file
71
packages/server/lib/makeDataContext.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { DataContext } from '@packages/data-context'
|
||||
import specsUtil from './util/specs'
|
||||
import type { FindSpecs, FoundBrowser, LaunchArgs, LaunchOpts, OpenProjectLaunchOptions, PlatformName } from '@packages/types'
|
||||
import { checkAuthQuery } from '@packages/graphql/src/stitching/remoteGraphQLCalls'
|
||||
import browserUtils from './browsers/utils'
|
||||
import auth from './gui/auth'
|
||||
import user from './user'
|
||||
import * as config from './config'
|
||||
import type { EventEmitter } from 'events'
|
||||
import { openProject } from './open_project'
|
||||
import cache from './cache'
|
||||
|
||||
const { getBrowsers } = browserUtils
|
||||
|
||||
interface MakeDataContextOptions {
|
||||
os: PlatformName
|
||||
rootBus: EventEmitter
|
||||
launchArgs: LaunchArgs
|
||||
}
|
||||
|
||||
export function makeDataContext (options: MakeDataContextOptions) {
|
||||
return new DataContext({
|
||||
...options,
|
||||
launchOptions: {},
|
||||
appApi: {
|
||||
getBrowsers () {
|
||||
return getBrowsers()
|
||||
},
|
||||
},
|
||||
authApi: {
|
||||
logIn () {
|
||||
return auth.start(() => {}, 'launchpad')
|
||||
},
|
||||
logOut () {
|
||||
return user.logOut()
|
||||
},
|
||||
checkAuth (context) {
|
||||
return checkAuthQuery(context)
|
||||
},
|
||||
},
|
||||
projectApi: {
|
||||
getConfig (projectRoot: string) {
|
||||
return config.get(projectRoot)
|
||||
},
|
||||
launchProject (browser: FoundBrowser, spec: Cypress.Spec, options?: LaunchOpts) {
|
||||
return openProject.launch({ ...browser }, spec, options)
|
||||
},
|
||||
initializeProject (args: LaunchArgs, options: OpenProjectLaunchOptions, browsers: FoundBrowser[]) {
|
||||
return openProject.create(args.projectRoot, args, options, browsers)
|
||||
},
|
||||
insertProjectToCache (projectRoot: string) {
|
||||
cache.insertProject(projectRoot)
|
||||
},
|
||||
getProjectRootsFromCache () {
|
||||
return cache.getProjectRoots()
|
||||
},
|
||||
findSpecs (payload: FindSpecs) {
|
||||
return specsUtil.findSpecs(payload)
|
||||
},
|
||||
clearLatestProjectsCache () {
|
||||
return cache.removeLatestProjects()
|
||||
},
|
||||
removeProjectFromCache (path: string) {
|
||||
return cache.removeProject(path)
|
||||
},
|
||||
closeActiveProject () {
|
||||
return openProject.closeOpenProjectAndBrowsers()
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
module.exports = (mode, options) => {
|
||||
export = (mode, options) => {
|
||||
if (mode === 'record') {
|
||||
return require('./record').run(options)
|
||||
}
|
||||
@@ -1,19 +1,22 @@
|
||||
const _ = require('lodash')
|
||||
const os = require('os')
|
||||
const EE = require('events')
|
||||
const { app } = require('electron')
|
||||
const image = require('electron').nativeImage
|
||||
const cyIcons = require('@cypress/icons')
|
||||
const savedState = require('../saved_state')
|
||||
const menu = require('../gui/menu')
|
||||
const Events = require('../gui/events')
|
||||
const Windows = require('../gui/windows')
|
||||
import _ from 'lodash'
|
||||
import os from 'os'
|
||||
import { app, nativeImage as image } from 'electron'
|
||||
// eslint-disable-next-line no-duplicate-imports
|
||||
import type { WebContents } from 'electron'
|
||||
import cyIcons from '@cypress/icons'
|
||||
import savedState from '../saved_state'
|
||||
import menu from '../gui/menu'
|
||||
import Events from '../gui/events'
|
||||
import * as Windows from '../gui/windows'
|
||||
import { runInternalServer } from './internal-server'
|
||||
import type { LaunchArgs, PlatformName } from '@packages/types'
|
||||
import EventEmitter from 'events'
|
||||
|
||||
const isDev = () => {
|
||||
return process.env['CYPRESS_INTERNAL_ENV'] === 'development'
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export = {
|
||||
isMac () {
|
||||
return os.platform() === 'darwin'
|
||||
},
|
||||
@@ -80,7 +83,7 @@ module.exports = {
|
||||
y: 'appY',
|
||||
devTools: 'isAppDevToolsOpen',
|
||||
},
|
||||
onBlur () {
|
||||
onBlur (this: {webContents: WebContents}) {
|
||||
if (this.webContents.isDevToolsOpened()) {
|
||||
return
|
||||
}
|
||||
@@ -121,10 +124,15 @@ module.exports = {
|
||||
return args[os.platform()]
|
||||
},
|
||||
|
||||
ready (options = {}) {
|
||||
const bus = new EE
|
||||
|
||||
/**
|
||||
* @param {import('@packages/types').LaunchArgs} options
|
||||
* @returns
|
||||
*/
|
||||
ready (options: {projectRoot?: string} = {}) {
|
||||
const { projectRoot } = options
|
||||
const { serverPortPromise, bus } = process.env.LAUNCHPAD
|
||||
? runInternalServer(options)
|
||||
: { bus: new EventEmitter, serverPortPromise: Promise.resolve(undefined) }
|
||||
|
||||
// TODO: potentially just pass an event emitter
|
||||
// instance here instead of callback functions
|
||||
@@ -135,19 +143,21 @@ module.exports = {
|
||||
},
|
||||
})
|
||||
|
||||
return savedState.create(projectRoot, false)
|
||||
.then((state) => {
|
||||
return state.get()
|
||||
})
|
||||
.then((state) => {
|
||||
return Windows.open(projectRoot, this.getWindowArgs(state, options))
|
||||
return Promise.all([
|
||||
serverPortPromise,
|
||||
savedState.create(projectRoot, false).then((state) => state.get()),
|
||||
])
|
||||
.then(([port, state]) => {
|
||||
return Windows.open(projectRoot, port, this.getWindowArgs(state))
|
||||
.then((win) => {
|
||||
Events.start(_.extend({}, options, {
|
||||
Events.start({
|
||||
...(options as LaunchArgs),
|
||||
onFocusTests () {
|
||||
// @ts-ignore
|
||||
return app.focus({ steal: true }) || win.focus()
|
||||
},
|
||||
os: os.platform(),
|
||||
}), bus)
|
||||
os: os.platform() as PlatformName,
|
||||
}, bus)
|
||||
|
||||
return win
|
||||
})
|
||||
31
packages/server/lib/modes/internal-server.ts
Normal file
31
packages/server/lib/modes/internal-server.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import os from 'os'
|
||||
import { EventEmitter } from 'events'
|
||||
|
||||
import { makeDataContext } from '../makeDataContext'
|
||||
import { makeGraphQLServer } from '../gui/makeGraphQLServer'
|
||||
import { assertValidPlatform } from '@packages/types/src/platform'
|
||||
|
||||
export function runInternalServer (options) {
|
||||
const bus = new EventEmitter()
|
||||
const platform = os.platform()
|
||||
|
||||
assertValidPlatform(platform)
|
||||
|
||||
const ctx = makeDataContext({
|
||||
os: platform,
|
||||
rootBus: bus,
|
||||
launchArgs: options,
|
||||
})
|
||||
|
||||
// Initializing the data context, loading browsers, etc.
|
||||
ctx.initializeData()
|
||||
ctx.emitter.init()
|
||||
|
||||
const serverPortPromise = makeGraphQLServer(ctx)
|
||||
|
||||
serverPortPromise.then((port) => {
|
||||
ctx.setGqlServerPort(port)
|
||||
})
|
||||
|
||||
return { ctx, bus, serverPortPromise }
|
||||
}
|
||||
@@ -13,10 +13,10 @@ import * as session from './session'
|
||||
import { getSpecUrl } from './project_utils'
|
||||
import errors from './errors'
|
||||
import type { LaunchOpts, LaunchArgs, OpenProjectLaunchOptions, FoundBrowser } from '@packages/types'
|
||||
import { closeGraphQLServer } from '@packages/graphql/src/server'
|
||||
import { fs } from './util/fs'
|
||||
import path from 'path'
|
||||
import os from 'os'
|
||||
import { closeGraphQLServer } from './gui/makeGraphQLServer'
|
||||
|
||||
const debug = Debug('cypress:server:open_project')
|
||||
|
||||
@@ -229,6 +229,10 @@ export class OpenProject {
|
||||
session.clearSessions()
|
||||
})
|
||||
.then(() => {
|
||||
if (options.skipBrowserOpenForTest) {
|
||||
return
|
||||
}
|
||||
|
||||
return browsers.open(browser, options, automation)
|
||||
})
|
||||
}
|
||||
@@ -380,8 +384,6 @@ export class OpenProject {
|
||||
this.componentSpecsWatcher.close()
|
||||
this.componentSpecsWatcher = null
|
||||
}
|
||||
|
||||
return closeGraphQLServer()
|
||||
}
|
||||
|
||||
closeBrowser () {
|
||||
@@ -405,7 +407,10 @@ export class OpenProject {
|
||||
|
||||
this.stopSpecsWatcher()
|
||||
|
||||
return this.closeOpenProjectAndBrowsers()
|
||||
return Promise.all([
|
||||
closeGraphQLServer(),
|
||||
this.closeOpenProjectAndBrowsers(),
|
||||
]).then(() => null)
|
||||
}
|
||||
|
||||
async create (path: string, args: LaunchArgs, options: OpenProjectLaunchOptions, browsers: FoundBrowser[] = []) {
|
||||
|
||||
@@ -98,9 +98,11 @@ const init = (config, options) => {
|
||||
debug('forking to run %s', childIndexFilename)
|
||||
|
||||
if (inspector.url()) {
|
||||
const inspectType = process.argv.some((a) => a.startsWith('--inspect-brk')) ? '--inspect-brk' : '--inspect'
|
||||
|
||||
childOptions.execArgv = _.chain(process.execArgv.slice(0))
|
||||
.remove('--inspect-brk')
|
||||
.push(`--inspect=${process.debugPort + 1}`)
|
||||
.push(`${inspectType}=${process.debugPort + 1}`)
|
||||
.value()
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ import preprocessor from './plugins/preprocessor'
|
||||
import { SpecsStore } from './specs-store'
|
||||
import { checkSupportFile, getDefaultConfigFilePath } from './project_utils'
|
||||
import type { FoundBrowser, OpenProjectLaunchOptions } from '@packages/types'
|
||||
import { DataContextShell } from '@packages/data-context/src/DataContextShell'
|
||||
|
||||
// Cannot just use RuntimeConfigOptions as is because some types are not complete.
|
||||
// Instead, this is an interface of values that have been manually validated to exist
|
||||
@@ -65,6 +66,7 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
public id: string
|
||||
|
||||
protected watchers: Watchers
|
||||
protected ctx: DataContextShell
|
||||
protected _cfg?: Cfg
|
||||
protected _server?: TServer
|
||||
protected _automation?: Automation
|
||||
@@ -82,7 +84,7 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
constructor ({
|
||||
projectRoot,
|
||||
testingType,
|
||||
options,
|
||||
options = {},
|
||||
}: {
|
||||
projectRoot: string
|
||||
testingType: Cypress.TestingType
|
||||
@@ -104,6 +106,7 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
this.spec = null
|
||||
this.browser = null
|
||||
this.id = createHmac('sha256', 'secret-key').update(projectRoot).digest('hex')
|
||||
this.ctx = options.ctx ?? new DataContextShell()
|
||||
|
||||
debug('Project created %o', {
|
||||
testingType: this.testingType,
|
||||
@@ -162,8 +165,8 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
|
||||
createServer (testingType: Cypress.TestingType) {
|
||||
return testingType === 'e2e'
|
||||
? new ServerE2E() as TServer
|
||||
: new ServerCt() as TServer
|
||||
? new ServerE2E(this.ctx) as TServer
|
||||
: new ServerCt(this.ctx) as TServer
|
||||
}
|
||||
|
||||
async open () {
|
||||
@@ -186,7 +189,9 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
|
||||
this._server = this.createServer(this.testingType)
|
||||
|
||||
cfg = await this.initializePlugins(cfg, this.options)
|
||||
if (!this.options.skipPluginIntializeForTesting) {
|
||||
cfg = await this.initializePlugins(cfg, this.options)
|
||||
}
|
||||
|
||||
const {
|
||||
specsStore,
|
||||
@@ -209,6 +214,7 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
specsStore,
|
||||
})
|
||||
|
||||
this.ctx.setAppServerPort(port)
|
||||
this._isServerOpen = true
|
||||
|
||||
// if we didnt have a cfg.port
|
||||
@@ -337,7 +343,10 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
return
|
||||
}
|
||||
|
||||
const closePreprocessor = (this.testingType === 'e2e' && preprocessor.close) ?? undefined
|
||||
const closePreprocessor = this.testingType === 'e2e' ? preprocessor.close : undefined
|
||||
|
||||
this.ctx.setAppServerPort(undefined)
|
||||
this.ctx.emitter.setAppSocketServer(undefined)
|
||||
|
||||
await Promise.all([
|
||||
this.server?.close(),
|
||||
@@ -436,7 +445,7 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
config,
|
||||
}: {
|
||||
specs: Cypress.Cypress['spec'][]
|
||||
config: any
|
||||
config: Cfg
|
||||
}) {
|
||||
const specsStore = new SpecsStore(config, this.testingType)
|
||||
|
||||
@@ -458,7 +467,7 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
|
||||
let ctDevServerPort: number | undefined
|
||||
|
||||
if (this.testingType === 'component') {
|
||||
if (this.testingType === 'component' && !this.options.skipPluginIntializeForTesting) {
|
||||
const { port } = await this.startCtDevServer(specs, config)
|
||||
|
||||
ctDevServerPort = port
|
||||
@@ -595,7 +604,7 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
|
||||
this._automation = new Automation(namespace, socketIoCookie, screenshotsFolder, onBrowserPreRequest, onRequestEvent)
|
||||
|
||||
this.server.startWebsockets(this.automation, this.cfg, {
|
||||
const io = this.server.startWebsockets(this.automation, this.cfg, {
|
||||
onReloadBrowser: options.onReloadBrowser,
|
||||
onFocusTests: options.onFocusTests,
|
||||
onSpecChanged: options.onSpecChanged,
|
||||
@@ -651,6 +660,8 @@ export class ProjectBase<TServer extends Server> extends EE {
|
||||
return
|
||||
},
|
||||
})
|
||||
|
||||
this.ctx.emitter.setAppSocketServer(io)
|
||||
}
|
||||
|
||||
changeToUrl (url) {
|
||||
|
||||
@@ -5,6 +5,8 @@ import { Request, Response, Router } from 'express'
|
||||
import send from 'send'
|
||||
import { getPathToDist } from '@packages/resolve-dist'
|
||||
import type { InitializeRoutes } from './routes'
|
||||
import { fs } from './util/fs'
|
||||
import type { DataContextShell } from '@packages/data-context/src/DataContextShell'
|
||||
|
||||
const debug = Debug('cypress:server:routes-ct')
|
||||
|
||||
@@ -15,6 +17,7 @@ const serveChunk = (req: Request, res: Response, clientRoute: string) => {
|
||||
}
|
||||
|
||||
export const createRoutesCT = ({
|
||||
ctx,
|
||||
config,
|
||||
nodeProxy,
|
||||
getCurrentBrowser,
|
||||
@@ -23,20 +26,52 @@ export const createRoutesCT = ({
|
||||
const routesCt = Router()
|
||||
|
||||
if (process.env.CYPRESS_INTERNAL_VITE_APP_PORT) {
|
||||
const myProxy = httpProxy.createProxyServer({
|
||||
const proxy = httpProxy.createProxyServer({
|
||||
target: `http://localhost:${process.env.CYPRESS_INTERNAL_VITE_APP_PORT}/`,
|
||||
})
|
||||
const proxyIndex = httpProxy.createProxyServer({
|
||||
target: `http://localhost:${process.env.CYPRESS_INTERNAL_VITE_APP_PORT}/`,
|
||||
selfHandleResponse: true,
|
||||
})
|
||||
|
||||
proxyIndex.on('proxyRes', function (proxyRes, _req, _res) {
|
||||
const body: any[] = []
|
||||
|
||||
proxyRes.on('data', function (chunk) {
|
||||
let chunkData = String(chunk)
|
||||
|
||||
if (chunkData.includes('<head>')) {
|
||||
chunkData = chunkData.replace('<body>', replaceBody(ctx))
|
||||
}
|
||||
|
||||
body.push(chunkData)
|
||||
})
|
||||
|
||||
proxyRes.on('end', function () {
|
||||
(_res as Response).send(body.join(''))
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: can namespace this onto a "unified" route like __app-unified__
|
||||
// make sure to update the generated routes inside of vite.config.ts
|
||||
routesCt.get('/__vite__/*', (req, res) => {
|
||||
myProxy.web(req, res, {}, (e) => {
|
||||
})
|
||||
if (req.params[0] === '') {
|
||||
proxyIndex.web(req, res, {}, (e) => {})
|
||||
} else {
|
||||
proxy.web(req, res, {}, (e) => {})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
routesCt.get('/__vite__/*', (req, res) => {
|
||||
const pathToFile = getPathToDist('app', req.params[0])
|
||||
|
||||
if (req.params[0] === '') {
|
||||
return fs.readFile(pathToFile, 'utf8')
|
||||
.then((file) => {
|
||||
res.send(file.replace('<body>', replaceBody(ctx)))
|
||||
})
|
||||
}
|
||||
|
||||
return send(req, pathToFile).pipe(res)
|
||||
})
|
||||
}
|
||||
@@ -122,3 +157,7 @@ export const createRoutesCT = ({
|
||||
|
||||
return routesCt
|
||||
}
|
||||
|
||||
function replaceBody (ctx: DataContextShell) {
|
||||
return `<body><script>window.__CYPRESS_GRAPHQL_PORT__ = ${JSON.stringify(ctx.gqlServerPort)};</script>\n`
|
||||
}
|
||||
|
||||
@@ -9,10 +9,12 @@ import type { Cfg } from './project-base'
|
||||
import xhrs from './controllers/xhrs'
|
||||
import { runner } from './controllers/runner'
|
||||
import { iframesController } from './controllers/iframes'
|
||||
import type { DataContextShell } from '@packages/data-context/src/DataContextShell'
|
||||
|
||||
const debug = Debug('cypress:server:routes')
|
||||
|
||||
export interface InitializeRoutes {
|
||||
ctx: DataContextShell
|
||||
specsStore: SpecsStore
|
||||
config: Cfg
|
||||
getSpec: () => Cypress.Spec | null
|
||||
|
||||
@@ -31,6 +31,7 @@ import type { Browser } from '@packages/server/lib/browsers/types'
|
||||
import { InitializeRoutes, createCommonRoutes } from './routes'
|
||||
import { createRoutesE2E } from './routes-e2e'
|
||||
import { createRoutesCT } from './routes-ct'
|
||||
import type { DataContextShell } from '@packages/data-context/src/DataContextShell'
|
||||
|
||||
const ALLOWED_PROXY_BYPASS_URLS = [
|
||||
'/',
|
||||
@@ -126,7 +127,7 @@ export abstract class ServerBase<TSocket extends SocketE2E | SocketCt> {
|
||||
protected _remoteDomainName: unknown
|
||||
protected _remoteFileServer: unknown
|
||||
|
||||
constructor () {
|
||||
constructor (private ctx: DataContextShell) {
|
||||
this.isListening = false
|
||||
// @ts-ignore
|
||||
this.request = Request()
|
||||
@@ -211,6 +212,7 @@ export abstract class ServerBase<TSocket extends SocketE2E | SocketCt> {
|
||||
this.createHosts(config.hosts)
|
||||
|
||||
const routeOptions: InitializeRoutes = {
|
||||
ctx: this.ctx,
|
||||
config,
|
||||
specsStore,
|
||||
getRemoteState,
|
||||
@@ -621,9 +623,4 @@ export abstract class ServerBase<TSocket extends SocketE2E | SocketCt> {
|
||||
sendSpecList (specs: Cypress.Cypress['spec'][], testingType: Cypress.TestingType) {
|
||||
return this.socket.sendSpecList(specs, testingType)
|
||||
}
|
||||
|
||||
// used for testing
|
||||
__setMiddleware (middleware: any) {
|
||||
this._middleware = middleware
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import Debug from 'debug'
|
||||
import isHtml from 'is-html'
|
||||
import _ from 'lodash'
|
||||
import stream from 'stream'
|
||||
import { EventEmitter } from 'events'
|
||||
import url from 'url'
|
||||
import httpsProxy from '@packages/https-proxy'
|
||||
import { getRouteForRequest } from '@packages/net-stubbing'
|
||||
@@ -16,6 +17,7 @@ import * as ensureUrl from './util/ensure-url'
|
||||
import headersUtil from './util/headers'
|
||||
import statusCode from './util/status_code'
|
||||
import type { Cfg } from './project-base'
|
||||
import { DataContextShell } from '@packages/data-context/src/DataContextShell'
|
||||
|
||||
type WarningErr = Record<string, any>
|
||||
|
||||
@@ -44,8 +46,8 @@ const isResponseHtml = function (contentType, responseBuffer) {
|
||||
export class ServerE2E extends ServerBase<SocketE2E> {
|
||||
private _urlResolver: Bluebird<Record<string, any>> | null
|
||||
|
||||
constructor () {
|
||||
super()
|
||||
constructor (ctx: DataContextShell = new DataContextShell({ rootBus: new EventEmitter })) {
|
||||
super(ctx)
|
||||
|
||||
this._urlResolver = null
|
||||
}
|
||||
|
||||
@@ -21,15 +21,15 @@ export class SpecsStore {
|
||||
|
||||
constructor (
|
||||
private cypressConfig: Record<string, any>,
|
||||
private runner: Cypress.TestingType,
|
||||
private testingType: Cypress.TestingType,
|
||||
) {}
|
||||
|
||||
get specDirectory () {
|
||||
if (this.runner === 'e2e') {
|
||||
if (this.testingType === 'e2e') {
|
||||
return this.cypressConfig.resolved.integrationFolder.value
|
||||
}
|
||||
|
||||
if (this.runner === 'component') {
|
||||
if (this.testingType === 'component') {
|
||||
return this.cypressConfig.resolved.componentFolder.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
const debug = require('debug')('cypress:server:ts-node')
|
||||
// @ts-check
|
||||
const debugLib = require('debug')
|
||||
const path = require('path')
|
||||
const tsnode = require('ts-node')
|
||||
const resolve = require('./resolve')
|
||||
|
||||
const debug = debugLib('cypress:server:ts-node')
|
||||
|
||||
const getTsNodeOptions = (tsPath, registeredFile) => {
|
||||
return {
|
||||
compiler: tsPath, // use the user's installed typescript
|
||||
/**
|
||||
* @type {import('ts-node').RegisterOptions}
|
||||
*/
|
||||
const opts = {
|
||||
compiler: process.env.TS_NODE_COMPILER || tsPath, // use the user's installed typescript
|
||||
compilerOptions: {
|
||||
module: 'CommonJS',
|
||||
},
|
||||
@@ -14,6 +20,8 @@ const getTsNodeOptions = (tsPath, registeredFile) => {
|
||||
dir: path.dirname(registeredFile),
|
||||
transpileOnly: true, // transpile only (no type-check) for speed
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
const register = (projectRoot, registeredFile) => {
|
||||
|
||||
@@ -2,6 +2,8 @@ const _ = require('lodash')
|
||||
const debug = require('debug')('cypress:server:validation')
|
||||
const is = require('check-more-types')
|
||||
const { commaListsOr } = require('common-tags')
|
||||
const { URL } = require('url')
|
||||
|
||||
const configOptions = require('../config_options')
|
||||
const path = require('path')
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
"compression": "1.7.4",
|
||||
"content-type": "1.0.4",
|
||||
"cookie-parser": "1.4.5",
|
||||
"cors": "2.8.5",
|
||||
"data-uri-to-buffer": "2.0.1",
|
||||
"dayjs": "^1.9.3",
|
||||
"debug": "4.3.2",
|
||||
@@ -65,6 +66,7 @@
|
||||
"fluent-ffmpeg": "2.1.2",
|
||||
"fs-extra": "8.1.0",
|
||||
"get-port": "5.1.1",
|
||||
"getenv": "1.0.0",
|
||||
"getos": "3.2.1",
|
||||
"glob": "7.1.3",
|
||||
"graceful-fs": "4.2.0",
|
||||
@@ -94,6 +96,7 @@
|
||||
"node-machine-id": "1.1.12",
|
||||
"opn": "cypress-io/opn#2f4e9a216ca7bdb95dfae9d46d99ddf004b3cbb5",
|
||||
"ospath": "1.2.2",
|
||||
"p-defer": "^3.0.0",
|
||||
"p-queue": "6.1.0",
|
||||
"pluralize": "8.0.0",
|
||||
"ramda": "0.27.1",
|
||||
@@ -115,7 +118,7 @@
|
||||
"tough-cookie": "4.0.0",
|
||||
"trash": "5.2.0",
|
||||
"tree-kill": "1.2.2",
|
||||
"ts-node": "8.5.4",
|
||||
"ts-node": "^10.2.1",
|
||||
"tslib": "2.3.0",
|
||||
"underscore.string": "3.3.5",
|
||||
"url-parse": "1.5.2",
|
||||
@@ -131,10 +134,12 @@
|
||||
"@cypress/json-schemas": "5.39.0",
|
||||
"@cypress/sinon-chai": "2.9.1",
|
||||
"@ffprobe-installer/ffprobe": "1.1.0",
|
||||
"@packages/data-context": "0.0.0-development",
|
||||
"@packages/desktop-gui": "0.0.0-development",
|
||||
"@packages/electron": "0.0.0-development",
|
||||
"@packages/example": "0.0.0-development",
|
||||
"@packages/extension": "0.0.0-development",
|
||||
"@packages/graphql": "0.0.0-development",
|
||||
"@packages/https-proxy": "0.0.0-development",
|
||||
"@packages/launcher": "0.0.0-development",
|
||||
"@packages/net-stubbing": "0.0.0-development",
|
||||
@@ -156,7 +161,6 @@
|
||||
"chai-uuid": "1.0.6",
|
||||
"chokidar-cli": "2.1.0",
|
||||
"chrome-har-capturer": "0.13.4",
|
||||
"cors": "2.8.5",
|
||||
"cross-env": "6.0.3",
|
||||
"devtools-protocol": "0.0.839267",
|
||||
"eol": "0.9.1",
|
||||
|
||||
@@ -5,7 +5,7 @@ const ws = require('ws')
|
||||
const httpsProxyAgent = require('https-proxy-agent')
|
||||
const evilDns = require('evil-dns')
|
||||
const Promise = require('bluebird')
|
||||
const socketIo = require(`${root}../socket`)
|
||||
const socketIo = require(`${root}../socket/lib/browser`)
|
||||
const httpsServer = require(`${root}../https-proxy/test/helpers/https_server`)
|
||||
const config = require(`${root}lib/config`)
|
||||
const { ServerE2E } = require(`${root}lib/server-e2e`)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const { expect } = require('chai')
|
||||
const HttpsProxyAgent = require('https-proxy-agent')
|
||||
const os = require('os')
|
||||
const socketIo = require('@packages/socket')
|
||||
const socketIo = require('@packages/socket/lib/browser')
|
||||
|
||||
module.exports = (on) => {
|
||||
on('task', {
|
||||
|
||||
@@ -79,7 +79,7 @@ describe('lib/gui/events', () => {
|
||||
it('ipc attaches callback on request', () => {
|
||||
sinon.stub(events, 'handleEvent')
|
||||
|
||||
events.start({ foo: 'bar' }, {}, { startGraphQL: false })
|
||||
events.start({ foo: 'bar' }, {})
|
||||
|
||||
expect(electron.ipcMain.on).to.be.calledWith('request')
|
||||
})
|
||||
@@ -88,7 +88,7 @@ describe('lib/gui/events', () => {
|
||||
electron.ipcMain.on.yields('arg1', 'arg2')
|
||||
const handleEvent = sinon.stub(events, 'handleEvent')
|
||||
|
||||
events.start({ foo: 'bar' }, {}, { startGraphQL: false })
|
||||
events.start({ foo: 'bar' }, {})
|
||||
|
||||
expect(handleEvent).to.be.calledWith({ foo: 'bar' }, {}, 'arg1', 'arg2')
|
||||
})
|
||||
|
||||
@@ -47,7 +47,7 @@ describe('lib/gui/windows', () => {
|
||||
type: 'INDEX',
|
||||
}
|
||||
|
||||
return Windows.open('/path/to/project', options, () => this.win)
|
||||
return Windows.open('/path/to/project', undefined, options, () => this.win)
|
||||
.then((win) => {
|
||||
expect(options).to.include({
|
||||
height: 500,
|
||||
|
||||
@@ -3,7 +3,7 @@ require('../spec_helper')
|
||||
const _ = require('lodash')
|
||||
const path = require('path')
|
||||
const Promise = require('bluebird')
|
||||
const socketIo = require('@packages/socket')
|
||||
const socketIo = require('@packages/socket/lib/browser')
|
||||
const httpsAgent = require('https-proxy-agent')
|
||||
const errors = require(`${root}lib/errors`)
|
||||
const config = require(`${root}lib/config`)
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
"./../ts/index.d.ts"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2020"],
|
||||
"types": ["mocha", "node"],
|
||||
"importHelpers": true,
|
||||
"resolveJsonModule": true,
|
||||
"noUnusedLocals": false,
|
||||
}
|
||||
|
||||
@@ -5,12 +5,11 @@ This is a shared lib for holding both the `socket.io` server and client.
|
||||
## Using
|
||||
|
||||
```javascript
|
||||
const socket = require("packages/socket")
|
||||
const socket = require("@packages/socket")
|
||||
|
||||
// returns
|
||||
{
|
||||
server: require("socket.io"),
|
||||
client: require("socket.io-client"),
|
||||
getPathToClientSource: function () {
|
||||
// returns path to the client 'socket.io.js' file
|
||||
// for use in the browser
|
||||
@@ -19,7 +18,7 @@ const socket = require("packages/socket")
|
||||
```
|
||||
|
||||
```javascript
|
||||
const socket = require("packages/socket")
|
||||
const socket = require("@packages/socket")
|
||||
|
||||
// server usage
|
||||
const srv = require("http").createServer()
|
||||
@@ -27,6 +26,7 @@ const io = socket.server(srv)
|
||||
io.on("connection", function(){})
|
||||
|
||||
// client usage
|
||||
const { client } = require("@packages/socket/lib/client")
|
||||
const client = socket.client("http://localhost:2020")
|
||||
client.on("connect", function(){})
|
||||
client.on("event", function(){})
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
'use strict'
|
||||
let __createBinding = (this && this.__createBinding) || (Object.create ? (function (o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k
|
||||
|
||||
Object.defineProperty(o, k2, { enumerable: true, get () {
|
||||
return m[k]
|
||||
} })
|
||||
}) : (function (o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k
|
||||
|
||||
o[k2] = m[k]
|
||||
}))
|
||||
let __exportStar = (this && this.__exportStar) || function (m, exports) {
|
||||
for (let p in m) if (p !== 'default' && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p)
|
||||
if (process.env.CYPRESS_INTERNAL_ENV !== 'production') {
|
||||
require('@packages/ts/register')
|
||||
}
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
__exportStar(require('./lib/socket'), exports)
|
||||
module.exports = require('./lib/socket')
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export * from './lib/socket'
|
||||
@@ -1,11 +0,0 @@
|
||||
'use strict'
|
||||
let __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { 'default': mod }
|
||||
}
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
exports.client = void 0
|
||||
|
||||
const socket_io_client_1 = __importDefault(require('socket.io-client'))
|
||||
|
||||
exports.client = socket_io_client_1.default
|
||||
@@ -1,5 +1,7 @@
|
||||
import io from 'socket.io-client'
|
||||
|
||||
export type { Socket } from 'socket.io-client'
|
||||
|
||||
export {
|
||||
io as client,
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
'use strict'
|
||||
let __createBinding = (this && this.__createBinding) || (Object.create ? (function (o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k
|
||||
|
||||
Object.defineProperty(o, k2, { enumerable: true, get () {
|
||||
return m[k]
|
||||
} })
|
||||
}) : (function (o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k
|
||||
|
||||
o[k2] = m[k]
|
||||
}))
|
||||
let __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function (o, v) {
|
||||
Object.defineProperty(o, 'default', { enumerable: true, value: v })
|
||||
}) : function (o, v) {
|
||||
o['default'] = v
|
||||
})
|
||||
let __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod
|
||||
|
||||
let result = {}
|
||||
|
||||
if (mod != null) for (let k in mod) if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k)
|
||||
|
||||
__setModuleDefault(result, mod)
|
||||
|
||||
return result
|
||||
}
|
||||
let __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { 'default': mod }
|
||||
}
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true })
|
||||
exports.getClientSource = exports.getClientVersion = exports.getPathToClientSource = exports.SocketIOServer = exports.server = exports.client = void 0
|
||||
|
||||
const fs_1 = __importDefault(require('fs'))
|
||||
const socket_io_1 = __importStar(require('socket.io'))
|
||||
|
||||
exports.server = socket_io_1.default
|
||||
|
||||
const browser_1 = require('./browser')
|
||||
|
||||
Object.defineProperty(exports, 'client', { enumerable: true, get () {
|
||||
return browser_1.client
|
||||
} })
|
||||
|
||||
const HUNDRED_MEGABYTES = 1e8 // 100000000
|
||||
const { version } = require('socket.io-client/package.json')
|
||||
const clientSource = require.resolve('socket.io-client/dist/socket.io.js')
|
||||
|
||||
class SocketIOServer extends socket_io_1.Server {
|
||||
constructor (srv, opts) {
|
||||
let _a
|
||||
|
||||
// in socket.io v3, they reduced down the max buffer size
|
||||
// from 100mb to 1mb, so we reset it back to the previous value
|
||||
//
|
||||
// previous commit for reference:
|
||||
// https://github.com/socketio/engine.io/blame/61b949259ed966ef6fc8bfd61f14d1a2ef06d319/lib/server.js#L29
|
||||
opts = opts !== null && opts !== void 0 ? opts : {}
|
||||
opts.maxHttpBufferSize = (_a = opts.maxHttpBufferSize) !== null && _a !== void 0 ? _a : HUNDRED_MEGABYTES
|
||||
super(srv, opts)
|
||||
}
|
||||
}
|
||||
exports.SocketIOServer = SocketIOServer
|
||||
|
||||
const getPathToClientSource = () => {
|
||||
return clientSource
|
||||
}
|
||||
|
||||
exports.getPathToClientSource = getPathToClientSource
|
||||
|
||||
const getClientVersion = () => {
|
||||
return version
|
||||
}
|
||||
|
||||
exports.getClientVersion = getClientVersion
|
||||
|
||||
const getClientSource = () => {
|
||||
return fs_1.default.readFileSync(exports.getPathToClientSource(), 'utf8')
|
||||
}
|
||||
|
||||
exports.getClientSource = getClientSource
|
||||
@@ -1,7 +1,6 @@
|
||||
import fs from 'fs'
|
||||
import type http from 'http'
|
||||
import server, { Server as SocketIOBaseServer, ServerOptions, Socket } from 'socket.io'
|
||||
import { client } from './browser'
|
||||
|
||||
export type { Socket }
|
||||
|
||||
@@ -30,7 +29,6 @@ class SocketIOServer extends SocketIOBaseServer {
|
||||
}
|
||||
|
||||
export {
|
||||
client,
|
||||
server,
|
||||
SocketIOServer,
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"main": "index.js",
|
||||
"browser": "lib/browser.ts",
|
||||
"scripts": {
|
||||
"build-prod": "tsc || echo 'built, with type errors'",
|
||||
"build-prod": "tsc || echo 'built, with type errors' && rm lib/browser.js",
|
||||
"clean": "rimraf lib/*.js",
|
||||
"check-ts": "tsc --noEmit",
|
||||
"clean-deps": "rimraf node_modules",
|
||||
"postinstall": "patch-package",
|
||||
@@ -30,6 +31,7 @@
|
||||
"lib",
|
||||
"patches"
|
||||
],
|
||||
"types": "lib/socket.ts",
|
||||
"workspaces": {
|
||||
"nohoist": [
|
||||
"socket.io",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user