From 3ad71eaab78c1486b66365b039a211ac32187079 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Mon, 13 Feb 2023 10:00:50 +1000 Subject: [PATCH 01/24] chore: rework component onboarding in launchpad (#25713) * chore: refactoring and types * rework source of frameworks * revert rename * fix tests * fix more tests * types * update code * use same public API internally * rename interfaces * rename * work on dev server api * fix types * fix test * attempt to support getDevServerConfig * tests * add function to define framework [skip ci] * rework a lot of types * fix test * update tests and types * refactor * revert changes * lint * fix test * revert * remove * add "community" label [skip ci] * refactor * types * lint * fix bug * update function name * address feedback * improve types with Pick * refactor using type guard * correct label --------- Co-authored-by: Zachary Williams --- cli/index.mjs | 2 + cli/lib/cypress.js | 18 ++ cli/types/cypress-npm-api.d.ts | 16 ++ cli/types/cypress.d.ts | 171 +++++++++++++++ cli/types/tests/cypress-npm-api-test.ts | 30 ++- npm/webpack-dev-server/src/devServer.ts | 9 +- .../src/actions/CodegenActions.ts | 5 +- .../data-context/src/actions/WizardActions.ts | 39 +++- .../data-context/src/codegen/spec-options.ts | 3 +- .../src/data/ProjectConfigManager.ts | 17 +- .../data-context/src/data/coreDataShape.ts | 9 +- .../src/sources/WizardDataSource.ts | 5 +- .../test/unit/codegen/code-generator.spec.ts | 4 +- .../test/unit/codegen/spec-options.spec.ts | 16 +- .../unit/sources/WizardDataSource.spec.ts | 6 +- packages/data-context/tsconfig.json | 2 +- packages/errors/src/errors.ts | 3 +- .../frontend-shared/src/locales/en-US.json | 5 +- packages/graphql/schemas/cloud.graphql | 50 +++++ packages/graphql/schemas/schema.graphql | 64 ++++-- .../schemaTypes/enumTypes/gql-WizardEnums.ts | 9 +- .../inputTypes/gql-WizardUpdateInput.ts | 6 +- .../schemaTypes/objectTypes/gql-Mutation.ts | 5 +- .../src/schemaTypes/objectTypes/gql-Wizard.ts | 4 +- .../gql-WizardFrontendFramework.ts | 44 ++-- .../launchpad/cypress/e2e/project-setup.cy.ts | 2 +- .../cypress/e2e/scaffold-project.cy.ts | 5 +- packages/launchpad/package.json | 1 + .../launchpad/src/setup/CommunityLabel.vue | 15 ++ .../src/setup/EnvironmentSetup.cy.tsx | 2 +- .../launchpad/src/setup/EnvironmentSetup.vue | 16 +- .../src/setup/SelectFwOrBundler.cy.tsx | 24 +- .../launchpad/src/setup/SelectFwOrBundler.vue | 29 +-- packages/launchpad/src/setup/types.ts | 21 ++ packages/launchpad/src/utils/icons.ts | 4 +- packages/scaffold-config/src/dependencies.ts | 2 +- packages/scaffold-config/src/detect.ts | 16 +- packages/scaffold-config/src/frameworks.ts | 206 ++++++++++-------- packages/scaffold-config/src/supportFile.ts | 3 +- .../unit/component-index-template.spec.ts | 6 +- .../scaffold-config/test/unit/detect.spec.ts | 83 ++++--- .../scaffold-config/test/unit/fixtures.ts | 28 +++ 42 files changed, 744 insertions(+), 261 deletions(-) create mode 100644 packages/launchpad/src/setup/CommunityLabel.vue create mode 100644 packages/launchpad/src/setup/types.ts create mode 100644 packages/scaffold-config/test/unit/fixtures.ts diff --git a/cli/index.mjs b/cli/index.mjs index 7b616f65a344..dcf09178f398 100644 --- a/cli/index.mjs +++ b/cli/index.mjs @@ -8,6 +8,8 @@ export default cypress export const defineConfig = cypress.defineConfig +export const defineComponentFramework = cypress.defineComponentFramework + export const run = cypress.run export const open = cypress.open diff --git a/cli/lib/cypress.js b/cli/lib/cypress.js index 02348266aa54..ff140859ff22 100644 --- a/cli/lib/cypress.js +++ b/cli/lib/cypress.js @@ -87,6 +87,24 @@ const cypressModuleApi = { defineConfig (config) { return config }, + + /** + * Provides automatic code completion for Component Frameworks Definitions. + * While it's not strictly necessary for Cypress to parse your configuration, we + * recommend wrapping your Component Framework Definition object with `defineComponentFramework()` + * @example + * module.exports = defineComponentFramework({ + * type: 'cypress-ct-solid-js' + * // ... + * }) + * + * @see ../types/cypress-npm-api.d.ts + * @param {Cypress.ThirdPartyComponentFrameworkDefinition} config + * @returns {Cypress.ThirdPartyComponentFrameworkDefinition} the configuration passed in parameter + */ + defineComponentFramework (config) { + return config + }, } module.exports = cypressModuleApi diff --git a/cli/types/cypress-npm-api.d.ts b/cli/types/cypress-npm-api.d.ts index 23cb8d4e3f13..0f93e802edeb 100644 --- a/cli/types/cypress-npm-api.d.ts +++ b/cli/types/cypress-npm-api.d.ts @@ -397,6 +397,22 @@ declare module 'cypress' { * @returns {Cypress.ConfigOptions} the configuration passed in parameter */ defineConfig(config: Cypress.ConfigOptions): Cypress.ConfigOptions + + /** + * Provides automatic code completion for Component Frameworks Definitions. + * While it's not strictly necessary for Cypress to parse your configuration, we + * recommend wrapping your Component Framework Definition object with `defineComponentFramework()` + * @example + * module.exports = defineComponentFramework({ + * type: 'cypress-ct-solid-js' + * // ... + * }) + * + * @see ../types/cypress-npm-api.d.ts + * @param {Cypress.ThirdPartyComponentFrameworkDefinition} config + * @returns {Cypress.ThirdPartyComponentFrameworkDefinition} the configuration passed in parameter + */ + defineComponentFramework(config: Cypress.ThirdPartyComponentFrameworkDefinition): Cypress.ThirdPartyComponentFrameworkDefinition } // export Cypress NPM module interface diff --git a/cli/types/cypress.d.ts b/cli/types/cypress.d.ts index f18ffe8af444..4002b1f5734d 100644 --- a/cli/types/cypress.d.ts +++ b/cli/types/cypress.d.ts @@ -3244,6 +3244,177 @@ declare namespace Cypress { type PickConfigOpt = T extends keyof DefineDevServerConfig ? DefineDevServerConfig[T] : any + interface DependencyToInstall { + dependency: CypressComponentDependency + satisfied: boolean + loc: string | null + detectedVersion: string | null + } + + interface CypressComponentDependency { + /** + * Unique idenitifer. + * @example 'reactscripts' + */ + type: string + + /** + * Name to display in the user interface. + * @example "React Scripts" + */ + name: string + + /** + * Package name on npm. + * @example react-scripts + */ + package: string + + /** + * Code to run when installing. Version is optional. + * + * Should be @. + * + * @example `react` + * @example `react@18` + * @example `react-scripts` + */ + installer: string + + /** + * Description shown in UI. It is recommended to use the same one the package uses on npm. + * @example 'Create React apps with no build configuration' + */ + description: string + + /** + * Minimum version supported. Should conform to Semantic Versioning as used in `package.json`. + * @see https://docs.npmjs.com/cli/v9/configuring-npm/package-json#dependencies + * @example '^=4.0.0 || ^=5.0.0' + * @example '^2.0.0' + */ + minVersion: string + } + + interface ResolvedComponentFrameworkDefinition { + /** + * A semantic, unique identifier. Must begin with `cypress-ct-` for third party implementations. + * @example: 'reactscripts', 'nextjs', 'cypress-ct-solid-js' + */ + type: string + + /** + * Used as the flag for `getPreset` for meta framworks, such as finding the webpack config for CRA, Angular, etc. + * + * configFramwork: () => { + * return getSolidJsMetaFrameworkBundlerConfig() + * } + * It is also the name of the string added to `cypress.config` + * + * @example + * + * export default { + * component: { + * devServer: { + * framework: 'create-react-app' // can be 'next', 'create-react-app', etc etc. + * } + * } + * } + */ + configFramework: string + + /** + * Library (React, Vue) or template (aka "meta framework") (CRA, Next.js, Angular) + */ + category: 'library' | 'template' + + /** + * Name displayed in Launchpad when doing initial setup. + * @example 'Solid.js', 'Create React App' + */ + name: string + + /** + * Supported bundlers. + */ + supportedBundlers: Array<'webpack' | 'vite'> + + /** + * Used to attempt to automatically select the correct framework/bundler from the dropdown. + * @example + * + * const SOLID_DETECTOR: Dependency = { + * type: 'solid', + * name: 'Solid.js', + * package: 'solid-js', + * installer: 'solid-js', + * description: 'Solid is a declarative JavaScript library for creating user interfaces', + * minVersion: '^1.0.0', + * } + */ + detectors: CypressComponentDependency[] + + /** + * Array of required dependencies. This could be the bundler and JavaScript library. + * It's the same type as `detectors`. + */ + dependencies: (bundler: 'webpack' | 'vite', projectPath: string) => Promise + + /** + * @internal + * This is used interally by Cypress for the "Create From Component" feature. + */ + codeGenFramework?: 'react' | 'vue' | 'svelte' | 'angular' + + /** + * @internal + * This is used interally by Cypress for the "Create From Component" feature. + * @example '*.{js,jsx,tsx}' + */ + glob?: string + + /** + * This is the path to get mount, eg `import { mount } from , + * @example: `cypress-ct-solidjs/src/mount` + */ + mountModule: (projectPath: string) => Promise + + /** + * Support status. Internally alpha | beta | full. + * Community integrations are "community". + * @internal + */ + supportStatus: 'alpha' | 'beta' | 'full' | 'community' + + /** + * Function returning string for used for the component-index.html file. + * Cypress provides a default if one isn't specified for third party integrations. + */ + componentIndexHtml?: () => string + + /** + * Used for the Create From Comopnent feature. + * This is currently not supported for third party frameworks. + * @internal + */ + specPattern?: '**/*.cy.ts' + } + + type ComponentFrameworkDefinition = Omit & { + dependencies: (bundler: 'webpack' | 'vite') => CypressComponentDependency[] + } + + // Certain properties are not supported for third party frameworks right now, such as ones related to the "Create From" feature. + type ThirdPartyComponentFrameworkDefinition = Pick & { + type: `cypress-ct-${string}` | string + + /** + * Only `library` is supported for third party definitions. + * `template` will be supported in the future. + */ + category: 'library' + } + interface AngularDevServerProjectConfig { root: string sourceRoot: string diff --git a/cli/types/tests/cypress-npm-api-test.ts b/cli/types/tests/cypress-npm-api-test.ts index 3a0feebd7df6..85251d5b335c 100644 --- a/cli/types/tests/cypress-npm-api-test.ts +++ b/cli/types/tests/cypress-npm-api-test.ts @@ -1,6 +1,6 @@ // type tests for Cypress NPM module // https://on.cypress.io/module-api -import cypress, { defineConfig } from 'cypress' +import cypress, { defineComponentFramework, defineConfig } from 'cypress' cypress.run // $ExpectType (options?: Partial | undefined) => Promise cypress.open // $ExpectType (options?: Partial | undefined) => Promise @@ -55,6 +55,34 @@ const config = defineConfig({ modifyObstructiveCode: true }) +const solid = { + type: 'solid-js', + name: 'Solid.js', + package: 'solid-js', + installer: 'solid-js', + description: 'Solid is a declarative JavaScript library for creating user interfaces', + minVersion: '^1.0.0' +} + +const thirdPartyFrameworkDefinition = defineComponentFramework({ + type: 'cypress-ct-third-party', + name: 'Third Party', + category: 'library', + dependencies: (bundler) => [solid], + detectors: [solid], + supportedBundlers: ['vite', 'webpack'] +}) + +const thirdPartyFrameworkDefinitionInvalidStrings = defineComponentFramework({ + type: 'cypress-ct-third-party', + name: 'Third Party', + // only library supported for third party definitions + category: 'template', // $ExpectError + dependencies: (bundler) => [], + detectors: [{}], // $ExpectError + supportedBundlers: ['metro', 'webpack'] // $ExpectError +}) + // component options const componentConfigNextWebpack: Cypress.ConfigOptions = { component: { diff --git a/npm/webpack-dev-server/src/devServer.ts b/npm/webpack-dev-server/src/devServer.ts index e7cabad50c17..4e0d90d81148 100644 --- a/npm/webpack-dev-server/src/devServer.ts +++ b/npm/webpack-dev-server/src/devServer.ts @@ -115,6 +115,13 @@ export type PresetHandlerResult = { frameworkConfig: Configuration, sourceWebpac type Optional = Pick, K> & Omit async function getPreset (devServerConfig: WebpackDevServerConfig): Promise> { + const defaultWebpackModules = () => ({ sourceWebpackModulesResult: sourceDefaultWebpackDependencies(devServerConfig) }) + + // Third party library (eg solid-js, lit, etc) + if (devServerConfig.framework?.startsWith('cypress-ct-')) { + return defaultWebpackModules() + } + switch (devServerConfig.framework) { case 'create-react-app': return createReactAppHandler(devServerConfig) @@ -134,7 +141,7 @@ async function getPreset (devServerConfig: WebpackDevServerConfig): Promise framework.configFramework === config?.component?.devServer.framework) + return this.ctx.coreData.wizard.frameworks.find((framework) => framework.configFramework === config?.component?.devServer.framework) } } diff --git a/packages/data-context/src/actions/WizardActions.ts b/packages/data-context/src/actions/WizardActions.ts index 4436a865b7fa..ed2322c6edf4 100644 --- a/packages/data-context/src/actions/WizardActions.ts +++ b/packages/data-context/src/actions/WizardActions.ts @@ -1,5 +1,5 @@ import type { NexusGenObjects } from '@packages/graphql/src/gen/nxs.gen' -import { detectFramework, WIZARD_FRAMEWORKS, commandsFileBody, supportFileComponent, supportFileE2E, WizardBundler, WizardFrontendFramework } from '@packages/scaffold-config' +import { detectFramework, commandsFileBody, supportFileComponent, supportFileE2E, getBundler } from '@packages/scaffold-config' import assert from 'assert' import path from 'path' import Debug from 'debug' @@ -9,6 +9,7 @@ const debug = Debug('cypress:data-context:wizard-actions') import type { DataContext } from '..' import { addTestingTypeToCypressConfig, AddTestingTypeToCypressConfigOptions } from '@packages/config' +import componentIndexHtmlGenerator from '@packages/scaffold-config/src/component-index-template' export class WizardActions { constructor (private ctx: DataContext) {} @@ -23,14 +24,14 @@ export class WizardActions { return this.ctx.wizardData } - setFramework (framework: WizardFrontendFramework | null): void { - const next = WIZARD_FRAMEWORKS.find((x) => x.type === framework?.type) + setFramework (framework: Cypress.ResolvedComponentFrameworkDefinition | null): void { + const next = this.ctx.coreData.wizard.frameworks.find((x) => x.type === framework?.type) this.ctx.update((coreData) => { coreData.wizard.chosenFramework = framework }) - if (next?.supportedBundlers?.length === 1) { + if (next?.supportedBundlers?.[0] && next.supportedBundlers.length === 1) { this.setBundler(next?.supportedBundlers?.[0]) return @@ -41,7 +42,7 @@ export class WizardActions { // if the previous bundler was incompatible with the // new framework that was selected, we need to reset it const doesNotSupportChosenBundler = (chosenBundler && !new Set( - this.ctx.coreData.wizard.chosenFramework?.supportedBundlers.map((x) => x.type) || [], + this.ctx.coreData.wizard.chosenFramework?.supportedBundlers ?? [], ).has(chosenBundler.type)) ?? false const prevFramework = this.ctx.coreData.wizard.chosenFramework?.type ?? null @@ -51,9 +52,21 @@ export class WizardActions { } } - setBundler (bundler: WizardBundler | null) { + getNullableBundler (bundler: 'vite' | 'webpack' | null) { + if (!bundler) { + return null + } + + try { + return getBundler(bundler) + } catch (e) { + return null + } + } + + setBundler (bundler: 'vite' | 'webpack' | null) { this.ctx.update((coreData) => { - coreData.wizard.chosenBundler = bundler + coreData.wizard.chosenBundler = this.getNullableBundler(bundler) }) return this.ctx.coreData.wizard @@ -87,7 +100,7 @@ export class WizardActions { this.resetWizard() - const detected = await detectFramework(this.ctx.currentProject) + const detected = await detectFramework(this.ctx.currentProject, this.ctx.coreData.wizard.frameworks) debug('detected %o', detected) @@ -100,8 +113,8 @@ export class WizardActions { return } - coreData.wizard.detectedBundler = detected.bundler || detected.framework.supportedBundlers[0] - coreData.wizard.chosenBundler = detected.bundler || detected.framework.supportedBundlers[0] + coreData.wizard.detectedBundler = this.getNullableBundler(detected.bundler || detected.framework.supportedBundlers[0]) + coreData.wizard.chosenBundler = this.getNullableBundler(detected.bundler || detected.framework.supportedBundlers[0]) }) } } @@ -295,14 +308,16 @@ export class WizardActions { } } - private async scaffoldComponentIndexHtml (chosenFramework: WizardFrontendFramework): Promise { + private async scaffoldComponentIndexHtml (chosenFramework: Cypress.ResolvedComponentFrameworkDefinition): Promise { const componentIndexHtmlPath = path.join(this.projectRoot, 'cypress', 'support', 'component-index.html') await this.ensureDir('support') + const defaultComponentIndex = componentIndexHtmlGenerator() + return this.scaffoldFile( componentIndexHtmlPath, - chosenFramework.componentIndexHtml(), + chosenFramework.componentIndexHtml?.() ?? defaultComponentIndex(), 'The HTML wrapper that each component is served with. Used for global fonts, CSS, JS, HTML, etc.', ) } diff --git a/packages/data-context/src/codegen/spec-options.ts b/packages/data-context/src/codegen/spec-options.ts index dea6618626ff..1f9cdac94fbc 100644 --- a/packages/data-context/src/codegen/spec-options.ts +++ b/packages/data-context/src/codegen/spec-options.ts @@ -1,6 +1,5 @@ import type { ParsedPath } from 'path' import type { CodeGenType } from '@packages/graphql/src/gen/nxs.gen' -import type { WizardFrontendFramework } from '@packages/scaffold-config' import fs from 'fs-extra' import { uniq, upperFirst } from 'lodash' import path from 'path' @@ -14,7 +13,7 @@ interface CodeGenOptions { isDefaultSpecPattern: boolean specPattern: string[] currentProject: string | null - framework?: WizardFrontendFramework + framework?: Cypress.ResolvedComponentFrameworkDefinition specs?: FoundSpec[] componentName?: string isDefault?: boolean diff --git a/packages/data-context/src/data/ProjectConfigManager.ts b/packages/data-context/src/data/ProjectConfigManager.ts index 30508f02ff49..58e2a3a2206d 100644 --- a/packages/data-context/src/data/ProjectConfigManager.ts +++ b/packages/data-context/src/data/ProjectConfigManager.ts @@ -18,7 +18,7 @@ import { CypressEnv } from './CypressEnv' import { autoBindDebug } from '../util/autoBindDebug' import type { EventRegistrar } from './EventRegistrar' import type { DataContext } from '../DataContext' -import { DependencyToInstall, isDependencyInstalled, WIZARD_BUNDLERS, WIZARD_DEPENDENCIES, WIZARD_FRAMEWORKS } from '@packages/scaffold-config' +import { isDependencyInstalled, WIZARD_BUNDLERS } from '@packages/scaffold-config' const debug = debugLib(`cypress:lifecycle:ProjectConfigManager`) @@ -191,14 +191,19 @@ export class ProjectConfigManager { // Use a map since sometimes the same dependency can appear in `bundler` and `framework`, // for example webpack appears in both `bundler: 'webpack', framework: 'react-scripts'` - const unsupportedDeps = new Map() + const unsupportedDeps = new Map() if (!bundler) { return } - const isFrameworkSatisfied = async (bundler: typeof WIZARD_BUNDLERS[number], framework: typeof WIZARD_FRAMEWORKS[number]) => { - for (const dep of await (framework.dependencies(bundler.type, this.options.projectRoot))) { + const isFrameworkSatisfied = async (bundler: typeof WIZARD_BUNDLERS[number], framework: Cypress.ResolvedComponentFrameworkDefinition) => { + const deps = await framework.dependencies(bundler.type, this.options.projectRoot) + + debug('deps are %o', deps) + + for (const dep of deps) { + debug('detecting %s in %s', dep.dependency.name, this.options.projectRoot) const res = await isDependencyInstalled(dep.dependency, this.options.projectRoot) if (!res.satisfied) { @@ -209,9 +214,9 @@ export class ProjectConfigManager { return true } - const frameworks = WIZARD_FRAMEWORKS.filter((x) => x.configFramework === devServerOptions.framework) + const frameworks = this.options.ctx.coreData.wizard.frameworks.filter((x) => x.configFramework === devServerOptions.framework) - const mismatchedFrameworkDeps = new Map() + const mismatchedFrameworkDeps = new Map() let isSatisfied = false diff --git a/packages/data-context/src/data/coreDataShape.ts b/packages/data-context/src/data/coreDataShape.ts index 8f6c66e85c42..3bed2cc4860d 100644 --- a/packages/data-context/src/data/coreDataShape.ts +++ b/packages/data-context/src/data/coreDataShape.ts @@ -1,5 +1,5 @@ import { FoundBrowser, Editor, AllowedState, AllModeOptions, TestingType, BrowserStatus, PACKAGE_MANAGERS, AuthStateName, MIGRATION_STEPS, MigrationStep, BannerState } from '@packages/types' -import type { WizardFrontendFramework, WizardBundler } from '@packages/scaffold-config' +import { WizardBundler, CT_FRAMEWORKS, resolveComponentFrameworkDefinition } from '@packages/scaffold-config' import type { NexusGenObjects } from '@packages/graphql/src/gen/nxs.gen' import type { App, BrowserWindow } from 'electron' import type { ChildProcess } from 'child_process' @@ -66,10 +66,11 @@ export interface AppDataShape { export interface WizardDataShape { chosenBundler: WizardBundler | null - chosenFramework: WizardFrontendFramework | null + chosenFramework: Cypress.ResolvedComponentFrameworkDefinition | null chosenManualInstall: boolean detectedBundler: WizardBundler | null - detectedFramework: WizardFrontendFramework | null + detectedFramework: Cypress.ResolvedComponentFrameworkDefinition | null + frameworks: Cypress.ResolvedComponentFrameworkDefinition[] } export interface MigrationDataShape { @@ -197,6 +198,8 @@ export function makeCoreData (modeOptions: Partial = {}): CoreDa chosenManualInstall: false, detectedBundler: null, detectedFramework: null, + // TODO: API to add third party frameworks to this list. + frameworks: CT_FRAMEWORKS.map((framework) => resolveComponentFrameworkDefinition(framework)), }, migration: { step: 'renameAuto', diff --git a/packages/data-context/src/sources/WizardDataSource.ts b/packages/data-context/src/sources/WizardDataSource.ts index ea287193db87..9a400a32177c 100644 --- a/packages/data-context/src/sources/WizardDataSource.ts +++ b/packages/data-context/src/sources/WizardDataSource.ts @@ -1,6 +1,5 @@ import { WIZARD_DEPENDENCY_TYPESCRIPT, - DependencyToInstall, isDependencyInstalled, } from '@packages/scaffold-config' import type { DataContext } from '..' @@ -8,12 +7,12 @@ import type { DataContext } from '..' export class WizardDataSource { constructor (private ctx: DataContext) {} - async packagesToInstall (): Promise { + async packagesToInstall (): Promise { if (!this.ctx.coreData.wizard.chosenFramework || !this.ctx.coreData.wizard.chosenBundler || !this.ctx.currentProject) { return [] } - const packages: DependencyToInstall[] = [ + const packages: Cypress.DependencyToInstall[] = [ ...(await this.ctx.coreData.wizard.chosenFramework.dependencies( this.ctx.coreData.wizard.chosenBundler.type, this.ctx.currentProject, )), diff --git a/packages/data-context/test/unit/codegen/code-generator.spec.ts b/packages/data-context/test/unit/codegen/code-generator.spec.ts index be244325e826..484e0956dff2 100644 --- a/packages/data-context/test/unit/codegen/code-generator.spec.ts +++ b/packages/data-context/test/unit/codegen/code-generator.spec.ts @@ -10,7 +10,7 @@ import { import { SpecOptions } from '../../../src/codegen/spec-options' import templates from '../../../src/codegen/templates' import { createTestDataContext } from '../helper' -import { WIZARD_FRAMEWORKS } from '@packages/scaffold-config' +import { CT_FRAMEWORKS } from '@packages/scaffold-config' import { defaultSpecPattern } from '@packages/config' const tmpPath = path.join(__dirname, 'tmp/test-code-gen') @@ -352,7 +352,7 @@ describe('code-generator', () => { currentProject: 'path/to/myProject', codeGenPath: path.join(__dirname, 'files', 'react', 'Button.jsx'), codeGenType: 'component', - framework: WIZARD_FRAMEWORKS[1], + framework: CT_FRAMEWORKS[1], isDefaultSpecPattern: true, specPattern: [defaultSpecPattern.component], }) diff --git a/packages/data-context/test/unit/codegen/spec-options.spec.ts b/packages/data-context/test/unit/codegen/spec-options.spec.ts index 083f85303771..1027ca06a020 100644 --- a/packages/data-context/test/unit/codegen/spec-options.spec.ts +++ b/packages/data-context/test/unit/codegen/spec-options.spec.ts @@ -1,5 +1,5 @@ import { defaultSpecPattern } from '@packages/config' -import { WIZARD_FRAMEWORKS } from '@packages/scaffold-config' +import { CT_FRAMEWORKS } from '@packages/scaffold-config' import { expect } from 'chai' import fs from 'fs-extra' import path from 'path' @@ -89,7 +89,7 @@ describe('spec-options', () => { codeGenPath: `${tmpPath}/MyComponent.vue`, codeGenType: 'component', isDefaultSpecPattern: true, - framework: WIZARD_FRAMEWORKS[1], + framework: CT_FRAMEWORKS[1], specPattern: [defaultSpecPattern.component], }) @@ -108,7 +108,7 @@ describe('spec-options', () => { codeGenPath: `${tmpPath}/MyComponent.vue`, codeGenType: 'component', isDefaultSpecPattern: true, - framework: WIZARD_FRAMEWORKS[1], + framework: CT_FRAMEWORKS[1], specPattern: [defaultSpecPattern.component], }) @@ -127,7 +127,7 @@ describe('spec-options', () => { codeGenPath: `${tmpPath}/Counter.tsx`, codeGenType: 'component', isDefaultSpecPattern: true, - framework: WIZARD_FRAMEWORKS[0], + framework: CT_FRAMEWORKS[0], specPattern: [defaultSpecPattern.component], componentName: 'Counter', isDefault: true, @@ -146,7 +146,7 @@ describe('spec-options', () => { codeGenPath: `${tmpPath}/Counter.tsx`, codeGenType: 'component', isDefaultSpecPattern: true, - framework: WIZARD_FRAMEWORKS[0], + framework: CT_FRAMEWORKS[0], specPattern: [defaultSpecPattern.component], componentName: 'View', }) @@ -166,7 +166,7 @@ describe('spec-options', () => { codeGenPath: `${tmpPath}/Counter.tsx`, codeGenType: 'component', isDefaultSpecPattern: true, - framework: WIZARD_FRAMEWORKS[0], + framework: CT_FRAMEWORKS[0], specPattern: [defaultSpecPattern.component], componentName: 'View', }) @@ -212,7 +212,7 @@ describe('spec-options', () => { codeGenPath: `${tmpPath}/${componentPath}`, codeGenType: 'component', isDefaultSpecPattern: false, - framework: WIZARD_FRAMEWORKS[1], + framework: CT_FRAMEWORKS[1], specPattern, specs, }) @@ -322,7 +322,7 @@ describe('spec-options', () => { codeGenType: 'component', isDefaultSpecPattern: true, specPattern: [defaultSpecPattern.component], - framework: WIZARD_FRAMEWORKS[1], + framework: CT_FRAMEWORKS[1], }) await fs.outputFile(`${tmpPath}/${fileName}`, '// foo') diff --git a/packages/data-context/test/unit/sources/WizardDataSource.spec.ts b/packages/data-context/test/unit/sources/WizardDataSource.spec.ts index 6bb6367d8877..d29d5259447c 100644 --- a/packages/data-context/test/unit/sources/WizardDataSource.spec.ts +++ b/packages/data-context/test/unit/sources/WizardDataSource.spec.ts @@ -1,9 +1,9 @@ -import { WizardBundler, WizardFrontendFramework, WIZARD_BUNDLERS, WIZARD_FRAMEWORKS } from '@packages/scaffold-config' +import { WizardBundler, WIZARD_BUNDLERS, CT_FRAMEWORKS, resolveComponentFrameworkDefinition } from '@packages/scaffold-config' import { expect } from 'chai' import { createTestDataContext, scaffoldMigrationProject, removeCommonNodeModules } from '../helper' -function findFramework (type: WizardFrontendFramework['type']) { - return WIZARD_FRAMEWORKS.find((x) => x.type === type)! +function findFramework (type: Cypress.ResolvedComponentFrameworkDefinition['type']) { + return resolveComponentFrameworkDefinition(CT_FRAMEWORKS.find((x) => x.type === type)!) } function findBundler (type: WizardBundler['type']) { diff --git a/packages/data-context/tsconfig.json b/packages/data-context/tsconfig.json index 5dfb0e8b808c..aad9aff5db78 100644 --- a/packages/data-context/tsconfig.json +++ b/packages/data-context/tsconfig.json @@ -17,6 +17,6 @@ "noUnusedLocals": false, "noUncheckedIndexedAccess": true, "importsNotUsedAsValues": "error", - "types": [], + "types": ["cypress"], } } \ No newline at end of file diff --git a/packages/errors/src/errors.ts b/packages/errors/src/errors.ts index 4cc53bfa50d6..c82eaeb0696c 100644 --- a/packages/errors/src/errors.ts +++ b/packages/errors/src/errors.ts @@ -9,7 +9,6 @@ import type { BreakingErrResult } from '@packages/config' import { humanTime, logError, parseResolvedPattern, pluralize } from './errorUtils' import { errPartial, errTemplate, fmt, theme, PartialErr } from './errTemplate' import { stackWithoutMessage } from './stackUtils' -import type { DependencyToInstall } from '@packages/scaffold-config' import type { ClonedError, ConfigValidationFailureInfo, CypressError, ErrTemplateResult, ErrorLike } from './errorTypes' const ansi_up = new AU() @@ -1708,7 +1707,7 @@ export const AllCypressErrors = { ` }, - COMPONENT_TESTING_MISMATCHED_DEPENDENCIES: (dependencies: DependencyToInstall[]) => { + COMPONENT_TESTING_MISMATCHED_DEPENDENCIES: (dependencies: Cypress.DependencyToInstall[]) => { const deps = dependencies.map((dep) => { if (dep.detectedVersion) { return `\`${dep.dependency.installer}\`. Expected ${dep.dependency.minVersion}, found ${dep.detectedVersion}.` diff --git a/packages/frontend-shared/src/locales/en-US.json b/packages/frontend-shared/src/locales/en-US.json index 73a759357e2c..947962448157 100644 --- a/packages/frontend-shared/src/locales/en-US.json +++ b/packages/frontend-shared/src/locales/en-US.json @@ -352,7 +352,6 @@ "frameworkLabel": "Front-end framework", "frameworkPlaceholder": "Pick a framework", "bundlerLabel": "Bundler", - "bundlerLabelDescription": "(dev server)", "bundlerPlaceholder": "Pick a bundler", "languageLabel": "Language", "configFileLanguageLabel": "Cypress config file", @@ -937,7 +936,9 @@ }, "versions": { "alpha": "Alpha", + "community": "Community", "beta": "Beta", - "new": "New" + "new": "New", + "communityNote": "This is a community provided definition." } } diff --git a/packages/graphql/schemas/cloud.graphql b/packages/graphql/schemas/cloud.graphql index 0dae909ab716..d3a9d5734d71 100644 --- a/packages/graphql/schemas/cloud.graphql +++ b/packages/graphql/schemas/cloud.graphql @@ -347,6 +347,16 @@ type CloudProjectSpec implements Node { """ fromBranch: String! ): Float + + """ + Average duration the spec takes to run within the context of the provided CloudRun ids. + """ + averageDurationForRunIds( + """ + The ids for the CloudRuns to use to derive the average duration. When provided, the fromBranch argument is ignored, as the provided run ids define the search space. + """ + cloudRunIds: [ID!]! + ): Float flakyStatus( """ The number of runs to consider when counting flaky runs. @@ -359,6 +369,16 @@ type CloudProjectSpec implements Node { fromBranch: String! ): CloudProjectSpecFlakyResult + """ + The flaky metadata for the spec within the context of the provided CloudRun ids. + """ + flakyStatusForRunIds( + """ + The ids for the CloudRuns, ordered from most to least relevant, to use to derive the flaky status. + """ + cloudRunIds: [ID!]! + ): CloudProjectSpecFlakyResult + """ Globally unique identifier representing a concrete GraphQL ObjectType """ @@ -370,6 +390,16 @@ type CloudProjectSpec implements Node { fromBranch: String! ): Boolean + """ + Indicator that a spec is considered flaky within the context of the provided CloudRun ids. + """ + isConsideredFlakyForRunIds( + """ + The ids for the CloudRuns to use to derive the flake indicator. When provided, the fromBranch argument is ignored, as the provided run ids define the search space. + """ + cloudRunIds: [ID!]! + ): Boolean + """ Current DateTime on the server. Used in connection with CloudLatestRunUpdateSpecData. """ @@ -445,6 +475,16 @@ type CloudProjectSpecFlakyStatus { The last flaky run occurrence, interpreted as "n runs ago" - ex: a value of 5 means a flaky run last occurred 5 runs ago """ lastFlaky: Int + + """ + The associated commit_sha of the CloudRun containing the most recent flaky occurrence of the spec. + """ + lastFlakyRunCommitSha: String + + """ + The run number of the CloudRun containing the most recent flaky occurrence of the spec. + """ + lastFlakyRunNumber: Int severity: String } @@ -520,6 +560,11 @@ type CloudRun implements Node { commitInfo: CloudRunCommitInfo completedAt: DateTime + """ + Number of specs instances that have been completed within a run + """ + completedInstanceCount: Int + """ When the run was created """ @@ -588,6 +633,11 @@ type CloudRun implements Node { """ totalFlakyTests: Int + """ + Number of instances within a run + """ + totalInstanceCount: Int + """ This is the number of passed tests across all groups in the run """ diff --git a/packages/graphql/schemas/schema.graphql b/packages/graphql/schemas/schema.graphql index f1e6bd0448ee..8121f807217a 100644 --- a/packages/graphql/schemas/schema.graphql +++ b/packages/graphql/schemas/schema.graphql @@ -311,6 +311,16 @@ type CloudProjectSpec implements Node { """ fromBranch: String! ): Float + + """ + Average duration the spec takes to run within the context of the provided CloudRun ids. + """ + averageDurationForRunIds( + """ + The ids for the CloudRuns to use to derive the average duration. When provided, the fromBranch argument is ignored, as the provided run ids define the search space. + """ + cloudRunIds: [ID!]! + ): Float flakyStatus( """The number of runs to consider when counting flaky runs.""" flakyRunsWindow: Int! @@ -321,6 +331,16 @@ type CloudProjectSpec implements Node { fromBranch: String! ): CloudProjectSpecFlakyResult + """ + The flaky metadata for the spec within the context of the provided CloudRun ids. + """ + flakyStatusForRunIds( + """ + The ids for the CloudRuns, ordered from most to least relevant, to use to derive the flaky status. + """ + cloudRunIds: [ID!]! + ): CloudProjectSpecFlakyResult + """Globally unique identifier representing a concrete GraphQL ObjectType""" id: ID! isConsideredFlaky( @@ -328,6 +348,16 @@ type CloudProjectSpec implements Node { fromBranch: String! ): Boolean + """ + Indicator that a spec is considered flaky within the context of the provided CloudRun ids. + """ + isConsideredFlakyForRunIds( + """ + The ids for the CloudRuns to use to derive the flake indicator. When provided, the fromBranch argument is ignored, as the provided run ids define the search space. + """ + cloudRunIds: [ID!]! + ): Boolean + """ Current DateTime on the server. Used in connection with CloudLatestRunUpdateSpecData. """ @@ -380,6 +410,16 @@ type CloudProjectSpecFlakyStatus { The last flaky run occurrence, interpreted as "n runs ago" - ex: a value of 5 means a flaky run last occurred 5 runs ago """ lastFlaky: Int + + """ + The associated commit_sha of the CloudRun containing the most recent flaky occurrence of the spec. + """ + lastFlakyRunCommitSha: String + + """ + The run number of the CloudRun containing the most recent flaky occurrence of the spec. + """ + lastFlakyRunNumber: Int severity: String } @@ -430,6 +470,9 @@ type CloudRun implements Node { commitInfo: CloudRunCommitInfo completedAt: DateTime + """Number of specs instances that have been completed within a run""" + completedInstanceCount: Int + """When the run was created""" createdAt: DateTime! @@ -480,6 +523,9 @@ type CloudRun implements Node { """Number of flaky tests, null if flake detection is not enabled""" totalFlakyTests: Int + """Number of instances within a run""" + totalInstanceCount: Int + """This is the number of passed tests across all groups in the run""" totalPassed: Int @@ -1278,19 +1324,6 @@ type FileParts implements Node { relative: String! } -enum FrontendFrameworkEnum { - angular - nextjs - nuxtjs - react - reactscripts - svelte - vue2 - vue3 - vueclivue2 - vueclivue3 -} - """Error from generated spec""" type GenerateSpecResponse { """The currently opened project""" @@ -2241,6 +2274,7 @@ type Subscription { enum SupportStatusEnum { alpha beta + community full } @@ -2369,7 +2403,7 @@ type WizardFrontendFramework implements Node { supportedBundlers: [WizardBundler!]! """The unique identifier for a framework or library""" - type: FrontendFrameworkEnum! + type: String! } """Details about an NPM Package listed during the wizard install""" @@ -2400,5 +2434,5 @@ type WizardNpmPackage implements Node { input WizardUpdateInput { bundler: SupportedBundlers - framework: FrontendFrameworkEnum + framework: String } diff --git a/packages/graphql/src/schemaTypes/enumTypes/gql-WizardEnums.ts b/packages/graphql/src/schemaTypes/enumTypes/gql-WizardEnums.ts index 02f03f3a0c91..c8fd1d02c706 100644 --- a/packages/graphql/src/schemaTypes/enumTypes/gql-WizardEnums.ts +++ b/packages/graphql/src/schemaTypes/enumTypes/gql-WizardEnums.ts @@ -1,5 +1,5 @@ import { CODE_LANGUAGES } from '@packages/types' -import { WIZARD_FRAMEWORKS, WIZARD_BUNDLERS } from '@packages/scaffold-config' +import { WIZARD_BUNDLERS, SUPPORT_STATUSES } from '@packages/scaffold-config' import { enumType } from 'nexus' export const SupportedBundlerEnum = enumType({ @@ -13,14 +13,9 @@ export const WizardConfigFileStatusEnum = enumType({ members: ['changes', 'valid', 'skipped', 'error'], }) -export const FrontendFrameworkEnum = enumType({ - name: 'FrontendFrameworkEnum', - members: WIZARD_FRAMEWORKS.map((t) => t.type), -}) - export const SupportStatusEnum = enumType({ name: 'SupportStatusEnum', - members: ['alpha', 'beta', 'full'], + members: SUPPORT_STATUSES, }) export const CodeLanguageEnum = enumType({ diff --git a/packages/graphql/src/schemaTypes/inputTypes/gql-WizardUpdateInput.ts b/packages/graphql/src/schemaTypes/inputTypes/gql-WizardUpdateInput.ts index 988ca5d43009..dcc0a2587fd9 100644 --- a/packages/graphql/src/schemaTypes/inputTypes/gql-WizardUpdateInput.ts +++ b/packages/graphql/src/schemaTypes/inputTypes/gql-WizardUpdateInput.ts @@ -1,12 +1,10 @@ import { inputObjectType } from 'nexus' -import { FrontendFrameworkEnum, SupportedBundlerEnum } from '../enumTypes/gql-WizardEnums' +import { SupportedBundlerEnum } from '../enumTypes/gql-WizardEnums' export const WizardUpdateInput = inputObjectType({ name: 'WizardUpdateInput', definition (t) { - t.field('framework', { - type: FrontendFrameworkEnum, - }) + t.string('framework') t.field('bundler', { type: SupportedBundlerEnum, diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts index daf950a4ea0f..11d4f690921f 100644 --- a/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Mutation.ts @@ -10,7 +10,6 @@ import { GenerateSpecResponse } from './gql-GenerateSpecResponse' import { Cohort, CohortInput } from './gql-Cohorts' import { Query } from './gql-Query' import { ScaffoldedFile } from './gql-ScaffoldedFile' -import { WIZARD_BUNDLERS, WIZARD_FRAMEWORKS } from '@packages/scaffold-config' import debugLib from 'debug' import { ReactComponentResponse } from './gql-ReactComponentResponse' import { TestsBySpecInput } from '../inputTypes' @@ -218,11 +217,11 @@ export const mutation = mutationType({ }, resolve: async (source, args, ctx) => { if (args.input.framework) { - ctx.actions.wizard.setFramework(WIZARD_FRAMEWORKS.find((x) => x.type === args.input.framework) ?? null) + ctx.actions.wizard.setFramework(ctx.coreData.wizard.frameworks.find((x) => x.type === args.input.framework) ?? null) } if (args.input.bundler) { - ctx.actions.wizard.setBundler(WIZARD_BUNDLERS.find((x) => x.type === args.input.bundler) ?? null) + ctx.actions.wizard.setBundler(args.input.bundler) } // TODO: remove when live-mutations are implements diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-Wizard.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-Wizard.ts index 65092d21a6b6..dae2afb2bcb2 100644 --- a/packages/graphql/src/schemaTypes/objectTypes/gql-Wizard.ts +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-Wizard.ts @@ -2,7 +2,7 @@ import { WizardBundler } from './gql-WizardBundler' import { WizardFrontendFramework } from './gql-WizardFrontendFramework' import { WizardNpmPackage } from './gql-WizardNpmPackage' import { objectType } from 'nexus' -import { WIZARD_BUNDLERS, WIZARD_FRAMEWORKS } from '@packages/scaffold-config' +import { WIZARD_BUNDLERS } from '@packages/scaffold-config' export const Wizard = objectType({ name: 'Wizard', @@ -27,7 +27,7 @@ export const Wizard = objectType({ t.nonNull.list.nonNull.field('frameworks', { type: WizardFrontendFramework, description: 'All of the component testing frameworks to choose from', - resolve: () => Array.from(WIZARD_FRAMEWORKS), // TODO(tim): fix this in nexus to accept Readonly + resolve: (source, args, ctx) => Array.from(ctx.coreData.wizard.frameworks), }) t.nonNull.list.nonNull.field('packagesToInstall', { diff --git a/packages/graphql/src/schemaTypes/objectTypes/gql-WizardFrontendFramework.ts b/packages/graphql/src/schemaTypes/objectTypes/gql-WizardFrontendFramework.ts index 50a34855fd4d..98df48562b3f 100644 --- a/packages/graphql/src/schemaTypes/objectTypes/gql-WizardFrontendFramework.ts +++ b/packages/graphql/src/schemaTypes/objectTypes/gql-WizardFrontendFramework.ts @@ -1,22 +1,30 @@ import { WizardBundler } from './gql-WizardBundler' -import { FrontendFrameworkEnum, SupportStatusEnum } from '../enumTypes/gql-WizardEnums' import { objectType } from 'nexus' +import { WIZARD_BUNDLERS } from '@packages/scaffold-config' +import { SupportStatusEnum } from '../enumTypes' export const WizardFrontendFramework = objectType({ name: 'WizardFrontendFramework', description: 'A frontend framework that we can setup within the app', node: 'type', definition (t) { - t.nonNull.field('type', { - type: FrontendFrameworkEnum, + t.nonNull.string('type', { description: 'The unique identifier for a framework or library', }), - t.nonNull.field('category', { - type: 'String', + t.nonNull.string('category', { description: 'The category (framework, like react-scripts, or library, like react', }), + t.nonNull.string('name', { + description: 'The display name of the framework', + }) + + t.nonNull.field('supportStatus', { + description: 'Current support status of the framework', + type: SupportStatusEnum, + }) + t.nonNull.boolean('isSelected', { description: 'Whether this is the selected framework in the wizard', resolve: (source, args, ctx) => ctx.wizardData.chosenFramework?.type === source.type, @@ -27,26 +35,22 @@ export const WizardFrontendFramework = objectType({ resolve: (source, args, ctx) => ctx.wizardData.detectedFramework?.type === source.type, }) - t.nonNull.string('name', { - description: 'The display name of the framework', - }) - - t.nonNull.field('supportStatus', { - description: 'Current support status of the framework', - type: SupportStatusEnum, - }) - t.nonNull.list.nonNull.field('supportedBundlers', { type: WizardBundler, description: 'All of the supported bundlers for this framework', resolve: (source, args, ctx) => { - return [...source.supportedBundlers] + const findBundler = (type: 'webpack' | 'vite') => { + const b = WIZARD_BUNDLERS.find((b) => b.type === type) + + if (!b) { + throw Error(`Invalid bundler: ${type}`) + } + + return b + } + + return ctx.wizardData.chosenFramework?.supportedBundlers.map(findBundler) ?? [] }, }) }, - - sourceType: { - module: '@packages/scaffold-config', - export: 'WizardFrontendFramework', - }, }) diff --git a/packages/launchpad/cypress/e2e/project-setup.cy.ts b/packages/launchpad/cypress/e2e/project-setup.cy.ts index dab37fce599e..2ba23a94e0f2 100644 --- a/packages/launchpad/cypress/e2e/project-setup.cy.ts +++ b/packages/launchpad/cypress/e2e/project-setup.cy.ts @@ -508,7 +508,7 @@ describe('Launchpad: Setup Project', () => { cy.contains('Pick a framework').click() cy.findByRole('option', { name: 'Vue.js 3' }).click() - cy.findByRole('button', { name: 'Bundler(dev server) Pick a bundler' }).click() + cy.findByRole('button', { name: 'Bundler Pick a bundler' }).click() cy.findByRole('option', { name: 'Vite' }).click() cy.findByRole('button', { name: 'Next step' }).should('not.have.disabled') diff --git a/packages/launchpad/cypress/e2e/scaffold-project.cy.ts b/packages/launchpad/cypress/e2e/scaffold-project.cy.ts index 92085d5e9e13..855f25ed4b81 100644 --- a/packages/launchpad/cypress/e2e/scaffold-project.cy.ts +++ b/packages/launchpad/cypress/e2e/scaffold-project.cy.ts @@ -1,4 +1,3 @@ -import type { WizardFrontendFramework } from '@packages/scaffold-config' import type { SnapshotScaffoldTestResult } from '@packages/launchpad/cypress/tasks/snapshotsScaffold' // The tests in this file take an existing project without Cypress Configured @@ -56,8 +55,8 @@ function scaffoldAndOpenE2EProject (opts: { function scaffoldAndOpenCTProject (opts: { name: Parameters[0] - framework: WizardFrontendFramework['name'] - bundler?: WizardFrontendFramework['supportedBundlers'][number]['name'] + framework: Cypress.ResolvedComponentFrameworkDefinition['name'] + bundler?: Cypress.ResolvedComponentFrameworkDefinition['supportedBundlers'][number] args?: Parameters[1] removeFixturesFolder?: boolean }) { diff --git a/packages/launchpad/package.json b/packages/launchpad/package.json index 72aba3e73b74..76e27db14a42 100644 --- a/packages/launchpad/package.json +++ b/packages/launchpad/package.json @@ -28,6 +28,7 @@ "@iconify/vue": "3.0.0-beta.1", "@intlify/vite-plugin-vue-i18n": "2.4.0", "@packages/frontend-shared": "0.0.0-development", + "@packages/scaffold-config": "0.0.0-development", "@percy/cypress": "^3.1.0", "@purge-icons/generated": "0.8.1", "@testing-library/cypress": "9.0.0", diff --git a/packages/launchpad/src/setup/CommunityLabel.vue b/packages/launchpad/src/setup/CommunityLabel.vue new file mode 100644 index 000000000000..bac87d4e75b6 --- /dev/null +++ b/packages/launchpad/src/setup/CommunityLabel.vue @@ -0,0 +1,15 @@ + + + diff --git a/packages/launchpad/src/setup/EnvironmentSetup.cy.tsx b/packages/launchpad/src/setup/EnvironmentSetup.cy.tsx index 30e68dff59b6..b7f90fdd5628 100644 --- a/packages/launchpad/src/setup/EnvironmentSetup.cy.tsx +++ b/packages/launchpad/src/setup/EnvironmentSetup.cy.tsx @@ -97,6 +97,6 @@ describe('', { viewportWidth: 800 }, () => { ), }) - cy.findByLabelText('Bundler(dev server)').should('be.visible') + cy.findByLabelText('Bundler').should('be.visible') }) }) diff --git a/packages/launchpad/src/setup/EnvironmentSetup.vue b/packages/launchpad/src/setup/EnvironmentSetup.vue index b948be9ba137..dbd58ef62b84 100644 --- a/packages/launchpad/src/setup/EnvironmentSetup.vue +++ b/packages/launchpad/src/setup/EnvironmentSetup.vue @@ -22,7 +22,6 @@ :value="props.gql.bundler?.type ?? undefined" :placeholder="t('setupPage.projectSetup.bundlerPlaceholder')" :label="t('setupPage.projectSetup.bundlerLabel')" - :description="t('setupPage.projectSetup.bundlerLabelDescription')" selector-type="bundler" data-testid="select-bundler" @select-bundler="val => onWizardSetup('bundler', val)" @@ -44,6 +43,7 @@ import { import { useI18n } from '@cy/i18n' import { useMutation } from '@urql/vue' +import type { FrameworkOption } from './types' gql` fragment EnvironmentSetup on Wizard { @@ -97,7 +97,19 @@ const bundlers = computed(() => { }) const frameworks = computed(() => { - return (props.gql.frameworks || []).map((x) => ({ ...x })).sort((x, y) => x.name.localeCompare(y.name)) + const data = (props.gql.frameworks || []).map((x) => { + return { + type: x.type, + supportStatus: x.supportStatus, + name: x.name, + id: x.id, + isDetected: x.isDetected, + } + }) + + data.sort((x, y) => x.name.localeCompare(y.name)) + + return data }) gql` diff --git a/packages/launchpad/src/setup/SelectFwOrBundler.cy.tsx b/packages/launchpad/src/setup/SelectFwOrBundler.cy.tsx index 76431138ea84..ed9de47457c0 100644 --- a/packages/launchpad/src/setup/SelectFwOrBundler.cy.tsx +++ b/packages/launchpad/src/setup/SelectFwOrBundler.cy.tsx @@ -1,5 +1,6 @@ import { ref } from 'vue' -import SelectFwOrBundler, { Option } from './SelectFwOrBundler.vue' +import SelectFwOrBundler from './SelectFwOrBundler.vue' +import type { Option } from './types' const manyOptions: Readonly = [ { @@ -11,7 +12,6 @@ const manyOptions: Readonly = [ }, { name: 'React.js', - description: '(detected)', id: 'react', type: 'react', supportStatus: 'alpha', @@ -72,6 +72,26 @@ describe('', () => { cy.contains('button', 'placeholder').should('exist') }) + it('shows a community integration', () => { + cy.mount(() => ( + + )) + + cy.percySnapshot() + }) + it('should select the value', () => { cy.mount(() => ( diff --git a/packages/launchpad/src/setup/SelectFwOrBundler.vue b/packages/launchpad/src/setup/SelectFwOrBundler.vue index 8fd5947bb00b..4d22dbfba70a 100644 --- a/packages/launchpad/src/setup/SelectFwOrBundler.vue +++ b/packages/launchpad/src/setup/SelectFwOrBundler.vue @@ -34,6 +34,7 @@ {{ selectedOptionName }} + + - - diff --git a/packages/launchpad/src/setup/SelectFwOrBundler.vue b/packages/launchpad/src/setup/SelectFwOrBundler.vue index 26519a526b63..45c9e530d809 100644 --- a/packages/launchpad/src/setup/SelectFwOrBundler.vue +++ b/packages/launchpad/src/setup/SelectFwOrBundler.vue @@ -74,6 +74,12 @@ v-html="itemValue.icon" /> + @@ -88,6 +94,7 @@ import type { import { useI18n } from '@cy/i18n' import AlphaLabel from './AlphaLabel.vue' import CommunityLabel from './CommunityLabel.vue' +import FrameworkOptionsFooter from './FrameworkOptionsFooter.vue' const { t } = useI18n() From 14d131d8ab10ebba7a5c99c3be483b76b251f136 Mon Sep 17 00:00:00 2001 From: astone123 Date: Mon, 20 Feb 2023 17:57:54 -0700 Subject: [PATCH 17/24] remove test project dependencies --- .../cypress-ct-solid-js/index.js | 26 ++----------------- .../cypress-ct-solid-js/package.json | 3 --- 2 files changed, 2 insertions(+), 27 deletions(-) diff --git a/system-tests/projects/ct-public-api-solid-js/cypress-ct-solid-js/index.js b/system-tests/projects/ct-public-api-solid-js/cypress-ct-solid-js/index.js index b8cad59195f5..0c91719efdcf 100644 --- a/system-tests/projects/ct-public-api-solid-js/cypress-ct-solid-js/index.js +++ b/system-tests/projects/ct-public-api-solid-js/cypress-ct-solid-js/index.js @@ -1,25 +1,3 @@ -import { getContainerEl, setupHooks } from '@cypress/mount-utils' -import { render } from 'solid-js/web' -let dispose - -function cleanup () { - dispose === null || dispose === void 0 ? void 0 : dispose() +export default function mount () { + return 'Legit mount function' } -export function mount (component, options = {}) { - // rendering/mounting function. - const root = getContainerEl() - - // Render component with your library's relevant - dispose = render(component, root) - - return cy.wait(0, { log: false }).then(() => { - if (options.log !== false) { - Cypress.log({ - name: 'mount', - message: 'Mounted component', - }) - } - }) -} - -setupHooks(cleanup) diff --git a/system-tests/projects/ct-public-api-solid-js/cypress-ct-solid-js/package.json b/system-tests/projects/ct-public-api-solid-js/cypress-ct-solid-js/package.json index 436787428394..48d51f945514 100644 --- a/system-tests/projects/ct-public-api-solid-js/cypress-ct-solid-js/package.json +++ b/system-tests/projects/ct-public-api-solid-js/cypress-ct-solid-js/package.json @@ -7,9 +7,6 @@ "build:mount": "tsc --project tsconfig.mount.json", "build:definition": "tsc --project tsconfig.definition.json" }, - "dependencies": { - "@cypress/mount-utils": "^4.0.0" - }, "files": [ "package.json", "definition.js", From 25733dbd37f94a5f86612a4d78482020bad30fec Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Tue, 21 Feb 2023 13:34:47 +1000 Subject: [PATCH 18/24] rebase --- .circleci/workflows.yml | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml index 6cac820d83b4..590066dd9a39 100644 --- a/.circleci/workflows.yml +++ b/.circleci/workflows.yml @@ -28,13 +28,9 @@ mainBuildFilters: &mainBuildFilters only: - develop - /^release\/\d+\.\d+\.\d+$/ - - 'feature/ct-public-api' - # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - - 'update-v8-snapshot-cache-on-develop' - - 'tgriesser/spike/spike' - - 'fix-duplicate-and-expired-cookies' # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - 'update-v8-snapshot-cache-on-develop' + - 'feature/ct-public-api' # usually we don't build Mac app - it takes a long time # but sometimes we want to really confirm we are doing the right thing @@ -43,10 +39,9 @@ macWorkflowFilters: &darwin-workflow-filters when: or: - equal: [ develop, << pipeline.git.branch >> ] - - equal: [ 'feature/ct-public-api', << pipeline.git.branch >> ] + # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'tgriesser/spike/spike', << pipeline.git.branch >> ] - - equal: [ 'fix-duplicate-and-expired-cookies', << pipeline.git.branch >> ] + - equal: [ 'feature/ct-public-api', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -55,11 +50,9 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters when: or: - equal: [ develop, << pipeline.git.branch >> ] - - equal: [ 'feature/ct-public-api', << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'tgriesser/spike/spike', << pipeline.git.branch >> ] - - equal: [ 'fix-duplicate-and-expired-cookies', << pipeline.git.branch >> ] + - equal: [ 'feature/ct-public-api', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -78,7 +71,7 @@ windowsWorkflowFilters: &windows-workflow-filters or: - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - - equal: [ 'update-v8-snapshot-cache-on-develop', 'fix-duplicate-and-expired-cookies', << pipeline.git.branch >> ] + - equal: [ 'update-v8-snapshot-cache-on-develop', 'feature/ct-public-api', 'fix-duplicate-and-expired-cookies', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -144,7 +137,7 @@ commands: - run: name: Check current branch to persist artifacts command: | - if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "feature/ct-public-api" ]]; then + if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "fix-duplicate-and-expired-cookies" ]]; then echo "Not uploading artifacts or posting install comment for this branch." circleci-agent step halt fi From 52e2f7fb9c3ce3f0a041ca5a95358dfeaef34773 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Tue, 21 Feb 2023 13:39:40 +1000 Subject: [PATCH 19/24] windows --- .circleci/workflows.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml index 590066dd9a39..d9cec0edd044 100644 --- a/.circleci/workflows.yml +++ b/.circleci/workflows.yml @@ -71,7 +71,8 @@ windowsWorkflowFilters: &windows-workflow-filters or: - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - - equal: [ 'update-v8-snapshot-cache-on-develop', 'feature/ct-public-api', 'fix-duplicate-and-expired-cookies', << pipeline.git.branch >> ] + - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] + - equal: ['feature/ct-public-api', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> From e1ee825f926515d655a53d4b906cdebb111d61d3 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Tue, 21 Feb 2023 14:17:03 +1000 Subject: [PATCH 20/24] windows again --- .circleci/workflows.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml index d9cec0edd044..aa896ddd71b5 100644 --- a/.circleci/workflows.yml +++ b/.circleci/workflows.yml @@ -72,7 +72,7 @@ windowsWorkflowFilters: &windows-workflow-filters - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: ['feature/ct-public-api', << pipeline.git.branch >> ] + - equal: [ 'feature/ct-public-api', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -138,7 +138,7 @@ commands: - run: name: Check current branch to persist artifacts command: | - if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "fix-duplicate-and-expired-cookies" ]]; then + if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "feature/ct-public-api" ]]; then echo "Not uploading artifacts or posting install comment for this branch." circleci-agent step halt fi From 9d3a00bbf98f424e7c5eb15dbfc60988263d0486 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Tue, 21 Feb 2023 15:52:52 +1000 Subject: [PATCH 21/24] add changelog entry --- cli/CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 8c9b11482dac..594c8b6e117b 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -1,11 +1,13 @@ -## 12.6.1 + +## 12.7.0 _Released 03/1/2023 (PENDING)_ **Features:** - It is now possible to set `hostOnly` cookies with [`cy.setCookie()`](https://docs.cypress.io/api/commands/setcookie) for a given domain. Addresses [#16856](https://github.com/cypress-io/cypress/issues/16856) and [#17527](https://github.com/cypress-io/cypress/issues/17527). +- Added a Public API for third party component libraries to define a Framework Definition, embedding their library into the Cypress onboarding workflow. Learn more [here](https://docs.cypress.io/guides/component-testing/third-party-definitions). Implemented in [#25780](https://github.com/cypress-io/cypress/pull/25780) and closes [#25638](https://github.com/cypress-io/cypress/issues/25638). **Bugfixes:** From 84bc2156a986c9add86915da005a2ad8f09d0d49 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Tue, 21 Feb 2023 15:53:48 +1000 Subject: [PATCH 22/24] changelog --- cli/CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/cli/CHANGELOG.md b/cli/CHANGELOG.md index 594c8b6e117b..9a237df1f8b7 100644 --- a/cli/CHANGELOG.md +++ b/cli/CHANGELOG.md @@ -1,5 +1,4 @@ - ## 12.7.0 _Released 03/1/2023 (PENDING)_ From f0d95422d464b523dbc0a26d2f0e7e4aef194fec Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Tue, 21 Feb 2023 15:57:11 +1000 Subject: [PATCH 23/24] revert workflow --- .circleci/workflows.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml index aa896ddd71b5..ac8ca9316fc2 100644 --- a/.circleci/workflows.yml +++ b/.circleci/workflows.yml @@ -41,7 +41,6 @@ macWorkflowFilters: &darwin-workflow-filters - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'feature/ct-public-api', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -52,7 +51,6 @@ linuxArm64WorkflowFilters: &linux-arm64-workflow-filters - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'feature/ct-public-api', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -72,7 +70,6 @@ windowsWorkflowFilters: &windows-workflow-filters - equal: [ develop, << pipeline.git.branch >> ] # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - equal: [ 'update-v8-snapshot-cache-on-develop', << pipeline.git.branch >> ] - - equal: [ 'feature/ct-public-api', << pipeline.git.branch >> ] - matches: pattern: /^release\/\d+\.\d+\.\d+$/ value: << pipeline.git.branch >> @@ -138,7 +135,7 @@ commands: - run: name: Check current branch to persist artifacts command: | - if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* && "$CIRCLE_BRANCH" != "feature/ct-public-api" ]]; then + if [[ "$CIRCLE_BRANCH" != "develop" && "$CIRCLE_BRANCH" != "release/"* ]]; then echo "Not uploading artifacts or posting install comment for this branch." circleci-agent step halt fi From 75733be311bf5734c61fdc677c062eb649f509a5 Mon Sep 17 00:00:00 2001 From: Lachlan Miller Date: Tue, 21 Feb 2023 15:57:58 +1000 Subject: [PATCH 24/24] remove worklfow --- .circleci/workflows.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.circleci/workflows.yml b/.circleci/workflows.yml index ac8ca9316fc2..686e662911a3 100644 --- a/.circleci/workflows.yml +++ b/.circleci/workflows.yml @@ -30,7 +30,6 @@ mainBuildFilters: &mainBuildFilters - /^release\/\d+\.\d+\.\d+$/ # use the following branch as well to ensure that v8 snapshot cache updates are fully tested - 'update-v8-snapshot-cache-on-develop' - - 'feature/ct-public-api' # usually we don't build Mac app - it takes a long time # but sometimes we want to really confirm we are doing the right thing