Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(graphql): ability to update/query for appData #19082

Merged
merged 18 commits into from
Nov 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 0 additions & 2 deletions packages/app/src/runner/SpecRunner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@

<script lang="ts" setup>
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { useI18n } from '@cy/i18n'
import { REPORTER_ID, RUNNER_ID, getRunnerElement, getReporterElement, empty } from '../runner/utils'
import { gql } from '@urql/core'
import InlineSpecList from '../specs/InlineSpecList.vue'
Expand Down Expand Up @@ -103,7 +102,6 @@ const eventManager = getEventManager()
const autStore = useAutStore()
const screenshotStore = useScreenshotStore()
const runnerUiStore = useRunnerUiStore()
const { t } = useI18n()

const runnerPane = ref<HTMLDivElement>()

Expand Down
4 changes: 2 additions & 2 deletions packages/app/src/settings/device/ExternalEditorSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ import { useMutation } from '@urql/vue'

gql`
mutation ExternalEditorSettings_SetPreferredEditorBinary ($value: String!) {
setPreferredEditorBinary (value: $value)
setPreferences (value: $value)
}`

const { t } = useI18n()

const setPreferredBinaryEditor = useMutation(ExternalEditorSettings_SetPreferredEditorBinaryDocument)

function handleChoseEditor (binary: string) {
setPreferredBinaryEditor.executeMutation({ value: binary })
setPreferredBinaryEditor.executeMutation({ value: JSON.stringify({ preferredEditorBinary: binary }) })
}

gql`
Expand Down
29 changes: 11 additions & 18 deletions packages/app/src/settings/device/TestingPreferences.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
class="mx-8px"
:value="props.gql.localSettings.preferences[pref.id] ?? false"
:name="pref.title"
@update="(value) => pref.mutation.executeMutation({ value })"
@update="(value) => updatePref(pref.id, value)"
/>
</h4>
<p class="text-size-14px leading-24px text-gray-600">
Expand All @@ -37,9 +37,7 @@ import { useI18n } from '@cy/i18n'
import Switch from '@packages/frontend-shared/src/components/Switch.vue'
import { gql, useMutation } from '@urql/vue'
import {
SetAutoScrollingEnabledDocument,
SetUseDarkSidebarDocument,
SetWatchForSpecChangeDocument,
SetTestingPreferencesDocument,
} from '@packages/data-context/src/gen/all-operations.gen'
import type { TestingPreferencesFragment } from '../../generated/graphql'

Expand All @@ -58,41 +56,36 @@ fragment TestingPreferences on Query {
`

gql`
mutation SetAutoScrollingEnabled($value: Boolean!) {
setAutoScrollingEnabled(value: $value)
mutation SetTestingPreferences($value: String!) {
setPreferences (value: $value)
}`

gql`
mutation SetUseDarkSidebar($value: Boolean!) {
setUseDarkSidebar(value: $value)
}`

gql`
mutation SetWatchForSpecChange($value: Boolean!) {
setWatchForSpecChange(value: $value)
}`
const setPreferences = useMutation(SetTestingPreferencesDocument)

const prefs = [
{
id: 'autoScrollingEnabled',
title: t('settingsPage.testingPreferences.autoScrollingEnabled.title'),
mutation: useMutation(SetAutoScrollingEnabledDocument),
description: t('settingsPage.testingPreferences.autoScrollingEnabled.description'),
},
{
id: 'useDarkSidebar',
title: t('settingsPage.testingPreferences.useDarkSidebar.title'),
mutation: useMutation(SetUseDarkSidebarDocument),
description: t('settingsPage.testingPreferences.useDarkSidebar.description'),
},
{
id: 'watchForSpecChange',
title: t('settingsPage.testingPreferences.watchForSpecChange.title'),
mutation: useMutation(SetWatchForSpecChangeDocument),
description: t('settingsPage.testingPreferences.watchForSpecChange.description'),
},
] as const

function updatePref (preferenceId: typeof prefs[number]['id'], value: boolean) {
setPreferences.executeMutation({
value: JSON.stringify({ [preferenceId]: value }),
})
}

const props = defineProps<{
gql: TestingPreferencesFragment
}>()
Expand Down
71 changes: 29 additions & 42 deletions packages/app/src/specs/CreateSpecPage.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import Button from '@cy/components/Button.vue'
import CreateSpecPage from './CreateSpecPage.vue'
import { ref, Ref } from 'vue'
import { defaultMessages } from '@cy/i18n'
import type { TestingTypeEnum } from '../generated/graphql-test'
import { CreateSpecPageFragmentDoc } from '../generated/graphql-test'

const pageTitleSelector = '[data-testid=create-spec-page-title]'
const pageDescriptionSelector = '[data-testid=create-spec-page-description]'
Expand All @@ -14,14 +12,21 @@ const messages = defaultMessages.createSpec
describe('<CreateSpecPage />', () => {
describe('mounting in component type', () => {
beforeEach(() => {
cy.mount(() => (<div class="p-12"><CreateSpecPage gql={{
currentProject: {
id: 'id',
storybook: null,
codeGenGlob: '**.vue',
currentTestingType: 'component',
cy.mountFragment(CreateSpecPageFragmentDoc, {
onResult: (ctx) => {
ctx.currentProject = {
...ctx.currentProject,
id: 'id',
storybook: null,
configFileAbsolutePath: '/usr/bin/cypress.config.ts',
codeGenGlob: '**.vue',
currentTestingType: 'component',
}
},
render: (gql) => {
return <CreateSpecPage gql={gql} />
},
}} /></div>))
})
})

it('renders the "No Specs" footer', () => {
Expand All @@ -44,14 +49,21 @@ describe('<CreateSpecPage />', () => {

describe('mounting in e2e mode', () => {
beforeEach(() => {
cy.mount(() => (<div class="p-12"><CreateSpecPage gql={{
currentProject: {
id: 'id',
storybook: null,
codeGenGlob: '**.vue',
currentTestingType: 'e2e',
cy.mountFragment(CreateSpecPageFragmentDoc, {
onResult: (ctx) => {
ctx.currentProject = {
...ctx.currentProject,
configFileAbsolutePath: '/usr/bin/cypress.config.ts',
id: 'id',
storybook: null,
codeGenGlob: '**.vue',
currentTestingType: 'e2e',
}
},
render: (gql) => {
return <CreateSpecPage gql={gql} />
},
}} /></div>))
})
})

it('renders e2e mode', () => {
Expand All @@ -64,29 +76,4 @@ describe('<CreateSpecPage />', () => {
.get(pageDescriptionSelector).should('contain.text', messages.page.e2e.description)
})
})

it('playground', () => {
const testingType: Ref<TestingTypeEnum> = ref('component')

cy.mount(() => (
<div class="p-12 space-y-10 resize overflow-auto">
{ /* Testing Utils */ }
<Button variant="outline"
size="md"
// @ts-ignore
onClick={() => testingType.value = testingType.value === 'component' ? 'e2e' : 'component'}>
Toggle Testing Types
</Button>

{ /* Subject Under Test */ }
<CreateSpecPage gql={{
currentProject: {
id: 'id',
storybook: null,
codeGenGlob: '**.vue',
currentTestingType: testingType.value,
},
}} />
</div>))
})
})
59 changes: 57 additions & 2 deletions packages/app/src/specs/CreateSpecPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
:gql="props.gql"
@close="closeModal"
/>

<div
v-if="props.gql.currentProject?.currentTestingType"
class="overflow-scroll text-center max-w-600px mx-auto py-40px"
Expand All @@ -29,6 +30,13 @@
@select="choose"
/>

<ChooseExternalEditorModal
:open="runnerUiStore.showChooseExternalEditorModal"
:gql="props.gql"
@close="runnerUiStore.setShowChooseExternalEditorModal(false)"
@selected="openFile"
/>

<div class="text-center border-t-1 pt-32px mt-32px">
<p
data-testid="no-specs-message"
Expand All @@ -42,7 +50,7 @@
prefix-icon-class="icon-light-gray-50 icon-dark-gray-400"
:prefix-icon="SettingsIcon"
class="mx-auto duration-300 hocus:ring-gray-50 hocus:border-gray-200"
@click.prevent=""
@click.prevent="showCypressConfigInIDE"
>
{{ t('createSpec.viewSpecPatternButton') }}
</Button>
Expand All @@ -57,29 +65,76 @@ import Button from '@cy/components/Button.vue'
import { ref } from 'vue'
import CreateSpecModal from './CreateSpecModal.vue'
import CreateSpecCards from './CreateSpecCards.vue'
import { gql } from '@urql/vue'
import { gql, useMutation } from '@urql/vue'
import type { CreateSpecPageFragment } from '../generated/graphql'
import { CreateSpecPage_OpenFileInIdeDocument } from '@packages/data-context/src/gen/all-operations.gen'
import { useRunnerUiStore } from '../store/runner-ui-store'
import ChooseExternalEditorModal from '@packages/frontend-shared/src/gql-components/ChooseExternalEditorModal.vue'
const { t } = useI18n()

gql`
fragment CreateSpecPage on Query {
...CreateSpecCards
...CreateSpecModal
...ChooseExternalEditor

currentProject {
id
currentTestingType
configFileAbsolutePath
}
localSettings {
preferences {
preferredEditorBinary
}
}
}
`

gql`
mutation CreateSpecPage_OpenFileInIDE ($input: FileDetailsInput!) {
openFileInIDE (input: $input)
}
`

const props = defineProps<{
gql: CreateSpecPageFragment
}>()

const openFileInIDE = useMutation(CreateSpecPage_OpenFileInIdeDocument)

const showModal = ref(false)

const generator = ref()

const openInIde = (absolute: string) => {
openFileInIDE.executeMutation({
input: {
absolute,
line: 1,
column: 1,
},
})
}

const runnerUiStore = useRunnerUiStore()

const openFile = () => {
runnerUiStore.setShowChooseExternalEditorModal(false)

if (props.gql.currentProject?.configFileAbsolutePath) {
openInIde(props.gql.currentProject.configFileAbsolutePath)
}
}

const showCypressConfigInIDE = () => {
if (props.gql.localSettings.preferences.preferredEditorBinary && props.gql.currentProject?.configFileAbsolutePath) {
openInIde(props.gql.currentProject.configFileAbsolutePath)
} else {
runnerUiStore.setShowChooseExternalEditorModal(true)
}
}

const closeModal = () => {
showModal.value = false
generator.value = null
Expand Down
24 changes: 15 additions & 9 deletions packages/data-context/src/actions/LocalSettingsActions.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import type { DevicePreferences, Editor } from '@packages/types'
import { AllowedState, defaultPreferences, Editor } from '@packages/types'
import pDefer from 'p-defer'

import type { DataContext } from '..'

export interface LocalSettingsApiShape {
setPreferredOpener(editor: Editor): Promise<void>
getAvailableEditors(): Promise<Editor[]>

getPreferences (): Promise<DevicePreferences>
setDevicePreference<K extends keyof DevicePreferences> (key: K, value: DevicePreferences[K]): Promise<void>
getPreferences (): Promise<AllowedState>
setPreferences (object: AllowedState): Promise<void>
}

export class LocalSettingsActions {
constructor (private ctx: DataContext) {}

setDevicePreference<K extends keyof DevicePreferences> (key: K, value: DevicePreferences[K]) {
setPreferences (stringifiedJson: string) {
const toJson = JSON.parse(stringifiedJson) as AllowedState

// update local data
this.ctx.coreData.localSettings.preferences[key] = value
for (const [key, value] of Object.entries(toJson)) {
this.ctx.coreData.localSettings.preferences[key as keyof AllowedState] = value as any
}

// persist to appData
return this.ctx._apis.localSettingsApi.setDevicePreference(key, value)
return this.ctx._apis.localSettingsApi.setPreferences(toJson)
}

async refreshLocalSettings () {
Expand All @@ -35,8 +38,11 @@ export class LocalSettingsActions {
const availableEditors = await this.ctx._apis.localSettingsApi.getAvailableEditors()

this.ctx.coreData.localSettings.availableEditors = availableEditors
this.ctx.coreData.localSettings.preferences = await this.ctx._apis.localSettingsApi.getPreferences()
this.ctx.coreData.localSettings.preferences = {
...defaultPreferences,
...(await this.ctx._apis.localSettingsApi.getPreferences()),
}

dfd.resolve(availableEditors)
dfd.resolve()
}
}
6 changes: 3 additions & 3 deletions packages/data-context/src/data/coreDataShape.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BUNDLERS, FoundBrowser, FoundSpec, FullConfig, Preferences, DevicePreferences, devicePreferenceDefaults, Editor, Warning } from '@packages/types'
import { BUNDLERS, FoundBrowser, FoundSpec, FullConfig, Preferences, Editor, Warning, AllowedState } from '@packages/types'
import type { NexusGenEnums, TestingTypeEnum } from '@packages/graphql/src/gen/nxs.gen'
import type { BrowserWindow } from 'electron'
import type { ChildProcess } from 'child_process'
Expand All @@ -22,7 +22,7 @@ export interface DevStateShape {
export interface LocalSettingsDataShape {
refreshing: Promise<Editor[]> | null
availableEditors: Editor[]
preferences: DevicePreferences
preferences: AllowedState
}

export interface ConfigChildProcessShape {
Expand Down Expand Up @@ -117,7 +117,7 @@ export function makeCoreData (): CoreDataShape {
},
localSettings: {
availableEditors: [],
preferences: devicePreferenceDefaults,
preferences: {},
refreshing: null,
},
isAuthBrowserOpened: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,6 @@ const externalEditors = computed(() => {
return props.gql.localSettings.availableEditors?.map((x) => ({ ...x, icon: icons[x.id] })) || []
})

gql`
mutation SetPreferredEditorBinary ($value: String!) {
setPreferredEditorBinary (value: $value)
}`

gql`
fragment ChooseExternalEditor on Query {
localSettings {
Expand Down