chore: additional app shape cleanup (#18826)

This commit is contained in:
Tim Griesser
2021-11-11 20:44:13 -05:00
committed by GitHub
parent 5165a8ee31
commit 88280153e9
24 changed files with 59 additions and 226 deletions
@@ -27,7 +27,6 @@ exports['@packages/data-context initializeData initializes 1'] = {
"app": {
"currentTestingType": null,
"refreshingBrowsers": {},
"navItem": "settings",
"browsers": [
{
"path": "/dev/chrome"
+2 -2
View File
@@ -97,7 +97,7 @@ export class DataContext {
if (this._config.launchArgs.projectRoot) {
await this.actions.project.setActiveProject(this._config.launchArgs.projectRoot)
if (this.coreData.app.currentProject?.preferences) {
if (this.coreData.currentProject?.preferences) {
toAwait.push(this.actions.project.launchProjectWithoutElectron())
}
}
@@ -206,7 +206,7 @@ export class DataContext {
}
get currentProject () {
return this.coreData.app.currentProject
return this.coreData.currentProject
}
@cached
@@ -56,8 +56,8 @@ export class AppActions {
this.ctx.coreData.app.browsers = browsers
if (this.ctx.coreData.app.currentProject) {
this.ctx.coreData.app.currentProject.browsers = browsers
if (this.ctx.coreData.currentProject) {
this.ctx.coreData.currentProject.browsers = browsers
}
// If we don't have a chosen browser, assign to the first one in the list
@@ -37,12 +37,12 @@ export class ProjectActions {
}
async clearActiveProject () {
this.ctx.appData.currentProject = null
this.ctx.coreData.currentProject = null
await this.api.closeActiveProject()
// TODO(tim): Improve general state management w/ immutability (immer) & updater fn
this.ctx.coreData.app.isInGlobalMode = true
this.ctx.coreData.app.currentProject = null
this.ctx.coreData.currentProject = null
this.ctx.coreData.app.currentTestingType = null
}
@@ -79,9 +79,9 @@ export class ProjectActions {
}
private setCurrentProjectProperties (currentProjectProperties: Partial<ActiveProjectShape>) {
this.ctx.coreData.app.currentProject = {
this.ctx.coreData.currentProject = {
browsers: this.ctx.coreData.app.browsers,
...this.ctx.coreData.app.currentProject,
...this.ctx.coreData.currentProject,
...currentProjectProperties,
} as ActiveProjectShape
}
@@ -54,8 +54,6 @@ export class WizardActions {
//
}
setSelectedNavItem (navItem: NexusGenEnums['NavItem']) {}
setTestingType (type: 'component' | 'e2e') {
this.ctx.coreData.wizard.chosenTestingType = type
@@ -38,10 +38,8 @@ export interface ActiveProjectShape extends ProjectShape {
}
export interface AppDataShape {
navItem: NexusGenEnums['NavItem']
browsers: ReadonlyArray<FoundBrowser> | null
projects: ProjectShape[]
currentProject: ActiveProjectShape | null
isInGlobalMode: boolean
isAuthBrowserOpened: boolean
currentTestingType: Maybe<TestingTypeEnum>
@@ -75,6 +73,7 @@ export interface CoreDataShape {
baseError: BaseErrorDataShape | null
dev: DevStateShape
app: AppDataShape
currentProject: ActiveProjectShape | null
wizard: WizardDataShape
user: AuthenticatedUserShape | null
electron: ElectronShape
@@ -90,15 +89,14 @@ export function makeCoreData (): CoreDataShape {
refreshState: null,
},
app: {
refreshingBrowsers: null,
currentTestingType: null,
navItem: 'settings',
refreshingBrowsers: null,
browsers: null,
projects: [],
currentProject: null,
isInGlobalMode: false,
isAuthBrowserOpened: false,
},
currentProject: null,
wizard: {
chosenTestingType: null,
chosenBundler: null,
@@ -5,19 +5,19 @@ export class ConfigDataSource {
constructor (private ctx: DataContext) {}
async getConfigForProject (projectRoot: string): Promise<FullConfig> {
if (!this.ctx.coreData.app.currentProject) {
if (!this.ctx.coreData.currentProject) {
throw new Error(`Cannot access config without currentProject`)
}
if (!this.ctx.coreData.app.currentProject.config) {
this.ctx.coreData.app.currentProject.config = Promise.resolve().then(async () => {
if (!this.ctx.coreData.currentProject.config) {
this.ctx.coreData.currentProject.config = Promise.resolve().then(async () => {
const configFile = await this.ctx.config.getDefaultConfigBasename(projectRoot)
return this.ctx._apis.projectApi.getConfig(projectRoot, { configFile })
})
}
return this.ctx.coreData.app.currentProject.config
return this.ctx.coreData.currentProject.config
}
async getDefaultConfigBasename (projectRoot: string) {
@@ -53,10 +53,10 @@ export class ConfigDataSource {
}
async cleanupCachedConfigForActiveProject () {
if (!this.ctx.coreData.app.currentProject?.config) {
if (!this.ctx.coreData.currentProject?.config) {
return
}
this.ctx.coreData.app.currentProject.config = null
this.ctx.coreData.currentProject.config = null
}
}
@@ -34,7 +34,7 @@ const makeDataContext = (options) => {
getProjectRootsFromCache: () => ([]),
getProjectPreferencesFromCache: () => {
return {
[options.coreData.app.currentProject.title]: {
[options.coreData.currentProject.title]: {
browserPath: chromeTestPath,
testingType: 'component',
},
@@ -76,6 +76,8 @@ beforeEach(() => {
// function setup
function setupE2E (projectName?: ProjectFixture) {
const _log = Cypress.log({ name: 'setupE2E', message: projectName ?? '' })
if (projectName && !e2eProjectDirs.includes(projectName)) {
throw new Error(`Unknown project ${projectName}`)
}
@@ -94,6 +96,7 @@ function setupE2E (projectName?: ProjectFixture) {
ctx.appServerPort,
]
}, { projectName, log: false }).then(([gqlPort, serverPort]) => {
_log.end()
Cypress.env('e2e_gqlPort', gqlPort)
Cypress.env('e2e_serverPort', serverPort)
})
@@ -1,10 +1,8 @@
import { cloneDeep } from 'lodash'
import type { CloudUser } from '../generated/test-cloud-graphql-types.gen'
import type { WizardStep, NavItem, CurrentProject, Browser, WizardBundler, WizardFrontendFramework, TestingTypeEnum, GlobalProject } from '../generated/test-graphql-types.gen'
import type { WizardStep, CurrentProject, Browser, WizardBundler, WizardFrontendFramework, TestingTypeEnum, GlobalProject } from '../generated/test-graphql-types.gen'
import { resetTestNodeIdx } from './clientTestUtils'
import { stubBrowsers } from './stubgql-Browser'
import * as cloudTypes from './stubgql-CloudTypes'
import { stubNavigationMenu } from './stubgql-NavigationMenu'
import { createTestCurrentProject, createTestGlobalProject, stubGlobalProject } from './stubgql-Project'
import { allBundlers } from './stubgql-Wizard'
@@ -12,7 +10,6 @@ export interface ClientTestContext {
currentProject: CurrentProject | null
projects: GlobalProject[]
app: {
navItem: NavItem
currentBrowser: Browser | null
browsers: Browser[] | null
isInGlobalMode: boolean
@@ -33,7 +30,6 @@ export interface ClientTestContext {
}
user: Partial<CloudUser> | null
cloudTypes: typeof cloudTypes
navigationMenu: typeof stubNavigationMenu
__mockPartial: any
}
@@ -50,7 +46,6 @@ export function makeClientTestContext (): ClientTestContext {
currentProject: testProject,
projects: [stubGlobalProject, createTestGlobalProject('another-test-project')],
app: {
navItem: 'settings',
browsers: stubBrowsers,
currentBrowser: stubBrowsers[0],
isInGlobalMode: false,
@@ -71,7 +66,6 @@ export function makeClientTestContext (): ClientTestContext {
},
user: null,
cloudTypes,
navigationMenu: cloneDeep(stubNavigationMenu),
__mockPartial: {},
}
}
@@ -10,7 +10,6 @@ import { stubApp } from './stubgql-App'
import { stubWizard } from './stubgql-Wizard'
import type { CodegenTypeMap } from '../generated/test-graphql-types.gen'
import type { MaybeResolver } from './clientTestUtils'
import { stubNavigationItem, stubNavigationMenu } from './stubgql-NavigationMenu'
import { stubMutation } from './stubgql-Mutation'
import { pathToArray } from 'graphql/jsutils/Path'
import dedent from 'dedent'
@@ -23,12 +22,10 @@ type MaybeResolveMap = {[K in keyof CodegenTypeMap]: MaybeResolver<CodegenTypeMa
const GQLStubRegistry: Partial<MaybeResolveMap> = {
App: stubApp,
Wizard: stubWizard,
NavigationMenu: stubNavigationMenu,
ProjectLike: stubProject,
GlobalProject: stubGlobalProject,
CurrentProject: stubProject,
Mutation: stubMutation,
NavigationItem: stubNavigationItem,
Query: stubQuery,
CloudOrganization: CloudOrganizationStubs.cyOrg,
CloudProject: CloudProjectStubs.componentProject,
@@ -1,20 +0,0 @@
import type { NavigationItem, NavigationMenu } from '../generated/test-graphql-types.gen'
import { NAV_ITEMS } from '@packages/types'
import type { MaybeResolver } from './clientTestUtils'
export const stubNavigationMenu: NavigationMenu = {
__typename: 'NavigationMenu',
items: NAV_ITEMS.map((navItem, index) => {
return {
__typename: 'NavigationItem',
id: index.toString(),
type: navItem.type,
iconPath: navItem.iconPath,
name: navItem.name,
selected: index === 0,
}
}),
selected: NAV_ITEMS[0].type,
}
export const stubNavigationItem: MaybeResolver<NavigationItem> = stubNavigationMenu.items[0]
@@ -1,30 +0,0 @@
exports['NavigationMenu returns null when framework is set but bundler is null 1'] = {
"navigationMenu": {
"items": [
{
"id": "projectSetup",
"name": "Project Setup",
"selected": true,
"iconPath": "clarity/dashboard-line"
},
{
"id": "runs",
"name": "Runs",
"selected": false,
"iconPath": "clarity/bullet-list-line"
},
{
"id": "learn",
"name": "Learn",
"selected": false,
"iconPath": "clarity/terminal-line"
},
{
"id": "settings",
"name": "Settings",
"selected": false,
"iconPath": "clarity/settings-line"
}
]
}
}
-30
View File
@@ -445,9 +445,6 @@ type Mutation {
"""Log out of Cypress Cloud"""
logout: Boolean
"""Set the current navigation item"""
navigationMenuSetItem(type: NavItem!): Boolean
openExternal(url: String!): Boolean
"""show the launchpad windows"""
@@ -481,30 +478,6 @@ type Mutation {
wizardUpdate(input: WizardUpdateInput!): Boolean
}
enum NavItem {
learn
projectSetup
runs
settings
}
"""Container describing a single nav item"""
type NavigationItem implements Node {
iconPath: String!
"""Relay style Node ID field for the NavigationItem field"""
id: ID!
name: String!
selected: Boolean!
type: NavItem!
}
"""Container for state associated with the side navigation menu"""
type NavigationMenu {
items: [NavigationItem!]!
selected: NavItem!
}
"""Implements the Relay Node spec"""
interface Node {
"""Globally unique identifier representing a concrete GraphQL ObjectType"""
@@ -602,9 +575,6 @@ type Query {
"""The state of any info related to local development of the runner"""
dev: DevState!
"""Metadata about the nagivation menu"""
navigationMenu: NavigationMenu
"""All known projects for the app"""
projects: [ProjectLike!]!
@@ -1,4 +1,4 @@
import { BUNDLERS, CODE_LANGUAGES, FRONTEND_FRAMEWORKS, NAV_ITEMS, TESTING_TYPES, WIZARD_STEPS } from '@packages/types'
import { BUNDLERS, CODE_LANGUAGES, FRONTEND_FRAMEWORKS, TESTING_TYPES, WIZARD_STEPS } from '@packages/types'
import { enumType } from 'nexus'
export const SupportedBundlerEnum = enumType({
@@ -32,11 +32,6 @@ export const TestingTypeEnum = enumType({
members: TESTING_TYPES.map((t) => t.type),
})
export const NavItemEnum = enumType({
name: 'NavItem',
members: NAV_ITEMS.map((t) => t.type),
})
export const WizardStepEnum = enumType({
name: 'WizardStep',
members: WIZARD_STEPS.map((t) => t.type),
@@ -1,6 +1,6 @@
import { arg, booleanArg, enumType, idArg, mutationType, nonNull, stringArg } from 'nexus'
import { CodeGenTypeEnum } from '../enumTypes/gql-CodeGenTypeEnum'
import { CodeLanguageEnum, FrontendFrameworkEnum, NavItemEnum, SupportedBundlerEnum, TestingTypeEnum } from '../enumTypes/gql-WizardEnums'
import { CodeLanguageEnum, FrontendFrameworkEnum, SupportedBundlerEnum, TestingTypeEnum } from '../enumTypes/gql-WizardEnums'
import { WizardUpdateInput } from '../inputTypes/gql-WizardUpdateInput'
import { GeneratedSpec } from './gql-GeneratedSpec'
@@ -165,14 +165,6 @@ export const mutation = mutationType({
},
})
t.liveMutation('navigationMenuSetItem', {
description: 'Set the current navigation item',
args: { type: nonNull(NavItemEnum) },
resolve: async (_, args, ctx) => {
await ctx.actions.wizard.setSelectedNavItem(args.type)
},
})
t.liveMutation('login', {
description: 'Auth with Cypress Cloud',
resolve: async (_, args, ctx) => {
@@ -1,20 +0,0 @@
import { objectType } from 'nexus'
import { NavItemEnum } from '../enumTypes/gql-WizardEnums'
export const NavigationItem = objectType({
name: 'NavigationItem',
description: 'Container describing a single nav item',
node: 'type',
definition (t) {
t.nonNull.field('type', {
type: NavItemEnum,
})
t.nonNull.string('iconPath')
t.nonNull.string('name')
t.nonNull.boolean('selected', {
resolve: (source, args, ctx) => ctx.appData.navItem === source.type,
})
},
})
@@ -1,20 +0,0 @@
import { NAV_ITEMS } from '@packages/types'
import { objectType } from 'nexus'
import { NavItemEnum } from '../enumTypes/gql-WizardEnums'
import { NavigationItem } from './gql-NavigationItem'
export const NavigationMenu = objectType({
name: 'NavigationMenu',
description: 'Container for state associated with the side navigation menu',
definition (t) {
t.nonNull.list.nonNull.field('items', {
type: NavigationItem,
resolve: () => Array.from(NAV_ITEMS),
})
t.nonNull.field('selected', {
type: NavItemEnum,
resolve: (source, args, ctx) => ctx.appData.navItem,
})
},
})
@@ -4,7 +4,6 @@ import { ProjectLike } from '..'
import { App } from './gql-App'
import { CurrentProject } from './gql-CurrentProject'
import { DevState } from './gql-DevState'
import { NavigationMenu } from './gql-NavigationMenu'
import { Wizard } from './gql-Wizard'
export const Query = objectType({
@@ -21,11 +20,6 @@ export const Query = objectType({
resolve: (root, args, ctx) => ctx.appData,
})
t.field('navigationMenu', {
type: NavigationMenu,
description: 'Metadata about the nagivation menu',
})
t.nonNull.field('wizard', {
type: Wizard,
description: 'Metadata about the wizard, null if we arent showing the wizard',
@@ -41,7 +35,7 @@ export const Query = objectType({
t.field('currentProject', {
type: CurrentProject,
description: 'The currently opened project',
resolve: (root, args, ctx) => ctx.coreData.app.currentProject,
resolve: (root, args, ctx) => ctx.coreData.currentProject,
})
t.nonNull.list.nonNull.field('projects', {
@@ -11,8 +11,6 @@ export * from './gql-GeneratedSpec'
export * from './gql-GitInfo'
export * from './gql-GlobalProject'
export * from './gql-Mutation'
export * from './gql-NavigationItem'
export * from './gql-NavigationMenu'
export * from './gql-ProjectPreferences'
export * from './gql-Query'
export * from './gql-Spec'
@@ -1,33 +1,36 @@
import defaultMessages from '@packages/frontend-shared/src/locales/en-US.json'
describe('Launchpad: Open Mode', () => {
beforeEach(() => {
cy.setupE2E()
cy.visitLaunchpad()
// Forcing reload, need to sync with @brian-mann to debug behavior here
cy.reload({ log: false })
})
it('shows Add Project when no projects have been added', () => {
cy.get('h1').should('contain', defaultMessages.globalPage.empty.title)
})
it('shows projects when projects have been added', () => {
cy.get('h1').should('contain', defaultMessages.globalPage.empty.title)
})
it('shows the projects page when a project is not specified', () => {
cy.task('scaffoldProject', 'todos').then((projectPath) => {
cy.withCtx(async (ctx, o) => {
ctx.actions.project.addProject({ path: o.projectPath as string, open: false })
}, { projectPath })
describe('global mode', () => {
beforeEach(() => {
cy.setupE2E()
cy.visitLaunchpad()
})
cy.contains(defaultMessages.globalPage.recentProjectsHeader)
it('shows Add Project when no projects have been added', () => {
cy.get('h1').should('contain', defaultMessages.globalPage.empty.title)
})
it('shows projects when projects have been added', () => {
cy.get('h1').should('contain', defaultMessages.globalPage.empty.title)
})
it('shows the projects page when a project is not specified', () => {
cy.task('scaffoldProject', 'todos').then((projectPath) => {
cy.withCtx(async (ctx, o) => {
ctx.actions.project.addProject({ path: o.projectPath as string, open: false })
}, { projectPath })
})
cy.visitLaunchpad()
cy.contains(defaultMessages.globalPage.recentProjectsHeader)
})
})
it('goes directly to e2e tests when launched with --e2e', () => {
cy.setupE2E('todos')
cy.visitLaunchpad()
cy.withCtx(async (ctx) => {
// Though the data context is previously initialized,
@@ -45,7 +48,8 @@ describe('Launchpad: Open Mode', () => {
})
it('goes directly to component tests when launched with --component', () => {
cy.setupE2E('todos')
cy.setupE2E('launchpad')
cy.visitLaunchpad()
cy.withCtx(async (ctx) => {
// Though the data context is previously initialized,
@@ -59,11 +63,12 @@ describe('Launchpad: Open Mode', () => {
})
// Component testing is not configured for the todo project
cy.get('h1').should('contain', 'Cypress Configuration Error')
cy.get('h1').should('contain', 'Project Setup')
})
it('auto-selects the browser when launched with --browser', () => {
cy.setupE2E('launchpad')
cy.visitLaunchpad()
cy.withCtx(async (ctx) => {
ctx.launchArgs.testingType = 'e2e'
@@ -85,6 +90,7 @@ describe('Launchpad: Open Mode', () => {
describe('when there is a list of projects', () => {
it('goes to an active project if one is added', () => {
cy.setupE2E('todos')
cy.visitLaunchpad()
cy.withCtx(async (ctx, o) => {
ctx.emitter.toLaunchpad()
@@ -96,6 +102,9 @@ describe('Launchpad: Open Mode', () => {
describe('when a user interacts with the header', () => {
it('the Docs menu opens when clicked', () => {
cy.setupE2E('todos')
cy.visitLaunchpad()
cy.contains('Projects').should('be.visible')
cy.contains('button', 'Docs').click()
cy.contains(defaultMessages.topNav.docsMenu.gettingStartedTitle).should('be.visible')
@@ -6,7 +6,6 @@ describe('Plugin error handling', () => {
cy.visitLaunchpad()
cy.get('[data-cy-testingType=e2e]').click()
cy.wait(2000)
cy.get('body')
.should('contain.text', 'Cypress Configuration Error')
@@ -17,7 +16,6 @@ describe('Plugin error handling', () => {
})
cy.get('[data-testid=error-retry-button]').click()
cy.wait(2000)
cy.get('body')
.should('not.contain.text', 'Cypress Configuration Error')
+2 -1
View File
@@ -41,7 +41,8 @@ const query = useQuery({ query: OpenBrowserDocument })
gql`
mutation OpenBrowser_LaunchProject ($testingType: TestingTypeEnum!, $browserPath: String!) {
launchOpenProject
hideBrowserWindow
# Removing for now until we decide what the behavior should be
# hideBrowserWindow
setProjectPreferences(testingType: $testingType, browserPath: $browserPath) {
currentProject {
id
-23
View File
@@ -107,29 +107,6 @@ export const CODE_LANGUAGES = [
export type CodeLanguage = typeof CODE_LANGUAGES[number]
export const NAV_ITEMS = [
{
type: 'projectSetup',
name: 'Project Setup',
iconPath: 'clarity/dashboard-line',
},
{
type: 'runs',
name: 'Runs',
iconPath: 'clarity/bullet-list-line',
},
{
type: 'learn',
name: 'Learn',
iconPath: 'clarity/terminal-line',
},
{
type: 'settings',
name: 'Settings',
iconPath: 'clarity/settings-line',
},
] as const
export const WIZARD_STEPS = [
{
type: 'welcome',