Skip to content

Commit 7903bc5

Browse files
committed
Merge branch 'unified-desktop-gui' into tgriesser/unify/ui-data-push
* unified-desktop-gui: feat(app): persist current spec in data context, update runner workflow for demo (#18406)
2 parents 69449f2 + b07ccf8 commit 7903bc5

File tree

19 files changed

+281
-88
lines changed

19 files changed

+281
-88
lines changed

packages/app/index.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ declare global {
7373
*/
7474
AutIframe: any
7575
Reporter: any
76+
shortcuts: {
77+
stop: () => void
78+
}
7679
}
7780
}
7881
}

packages/app/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
"@urql/vue",
7777
"@vueuse/core",
7878
"lodash",
79+
"mobx",
80+
"nanoid",
7981
"vue",
8082
"vue-toast-notification"
8183
]

packages/app/src/App.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,10 @@
1010
<!-- </keep-alive> -->
1111
</router-view>
1212
</template>
13+
14+
<style>
15+
.reporter {
16+
position: relative;
17+
width: 100%;
18+
}
19+
</style>

packages/app/src/pages/Runner/[...all].vue

Lines changed: 24 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,34 @@
11
<template>
2-
<div>
3-
<h2>Runner Page</h2>
4-
5-
<div v-once>
6-
<div :id="RUNNER_ID" />
7-
<div :id="REPORTER_ID" />
8-
</div>
9-
</div>
2+
<Runner
3+
v-if="query.data.value?.app?.activeProject"
4+
:gql="query.data.value.app?.activeProject?.currentSpec"
5+
/>
106
</template>
117

128
<script lang="ts" setup>
13-
import { onMounted } from 'vue'
14-
import type { SpecFile } from '@packages/types/src'
15-
import { UnifiedRunnerAPI } from '../../runner'
16-
import { REPORTER_ID, RUNNER_ID } from '../../runner/utils'
17-
import { useRoute } from 'vue-router'
18-
19-
onMounted(() => {
20-
UnifiedRunnerAPI.initialize(executeSpec)
21-
})
22-
23-
const route = useRoute()
24-
25-
function executeSpec () {
26-
const absolute = route.hash.slice(1)
27-
28-
if (absolute) {
29-
// @ts-ignore
30-
execute({
31-
absolute,
32-
relative: `src/Basic.spec.tsx`,
33-
name: `Basic.spec.tsx`,
34-
})
9+
import { gql } from '@urql/core'
10+
import { useQuery } from '@urql/vue'
11+
import { Runner_AllDocument } from '../../generated/graphql'
12+
import Runner from '../../runs/Runner.vue'
13+
14+
gql`
15+
query Runner_All {
16+
app {
17+
activeProject {
18+
id
19+
currentSpec {
20+
...CurrentSpec_Runner
21+
}
22+
}
3523
}
3624
}
25+
`
3726
38-
const execute = (spec?: SpecFile) => {
39-
if (!spec) {
40-
return
41-
}
42-
43-
UnifiedRunnerAPI.executeSpec(spec)
44-
}
27+
// network-only - we do not want to execute a stale spec
28+
const query = useQuery({
29+
query: Runner_AllDocument,
30+
requestPolicy: 'network-only',
31+
})
4532
</script>
4633

4734
<route>

packages/app/src/pages/Specs.vue

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ const props = defineProps<{
3535

3636
<style>
3737
iframe {
38-
border: 5px solid black;
39-
margin: 10px;
40-
background: lightgray;
38+
width: 100%;
4139
}
4240
</style>

packages/app/src/runner/index.ts

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,9 @@
1616
*/
1717
import { store, Store } from '../store'
1818
import { injectBundle } from './injectBundle'
19-
import type { SpecFile } from '@packages/types/src/spec'
19+
import type { BaseSpec } from '@packages/types/src/spec'
2020
import { UnifiedReporterAPI } from './reporter'
21-
import { getRunnerElement } from './utils'
22-
23-
function empty (el: HTMLElement) {
24-
while (el.lastChild) {
25-
if (el && el.firstChild) {
26-
el.removeChild(el.firstChild)
27-
}
28-
}
29-
}
21+
import { getRunnerElement, empty } from './utils'
3022

3123
const randomString = `${Math.random()}`
3224

@@ -52,7 +44,7 @@ function setupRunner (done: () => void) {
5244
/**
5345
* Get the URL for the spec. This is the URL of the AUT IFrame.
5446
*/
55-
function getSpecUrl (namespace: string, spec: SpecFile, prefix = '') {
47+
function getSpecUrl (namespace: string, spec: BaseSpec, prefix = '') {
5648
return spec ? `${prefix}/${namespace}/iframes/${spec.absolute}` : ''
5749
}
5850

@@ -71,7 +63,7 @@ function teardownSpec (store: Store) {
7163
* Cypress on it.
7264
*
7365
*/
74-
function setupSpec (spec: SpecFile) {
66+
function setupSpec (spec: BaseSpec) {
7567
// @ts-ignore - TODO: figure out how to manage window.config.
7668
const config = window.config
7769

@@ -136,7 +128,7 @@ function initialize (ready: () => void) {
136128
* 5. Setup the spec. This involves a few things, see the `setupSpec` function's
137129
* description for more information.
138130
*/
139-
async function executeSpec (spec: SpecFile) {
131+
async function executeSpec (spec: BaseSpec) {
140132
store.setSpec(spec)
141133

142134
await UnifiedReporterAPI.resetReporter()

packages/app/src/runner/injectBundle.ts

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,34 @@
1-
function injectReporterStyle () {
2-
const style = document.createElement('style')
3-
4-
style.innerText = `
5-
.reporter {
6-
min-height: 0;
7-
width: 300px;
8-
left: 750px;
9-
position: absolute;
10-
}
11-
`
12-
13-
document.head.appendChild(style)
14-
}
1+
// function injectReporterStyle () {
2+
// const style = document.createElement('style')
3+
4+
// style.innerText = `
5+
// .reporter {
6+
// min-height: 0;
7+
// width: 300px;
8+
// left: 750px;
9+
// position: absolute;
10+
// }
11+
// `
12+
13+
// document.head.appendChild(style)
14+
// }
1515

1616
export async function injectBundle (ready: () => void) {
17+
const src = '/__cypress/runner/cypress_runner.js'
18+
19+
const alreadyInjected = document.querySelector(`script[src="${src}"]`)
20+
21+
if (alreadyInjected) {
22+
ready()
23+
24+
return
25+
}
26+
1727
const response = await window.fetch('/api')
1828
const data = await response.json()
1929
const script = document.createElement('script')
2030

21-
script.src = '/__cypress/runner/cypress_runner.js'
31+
script.src = src
2232
script.type = 'text/javascript'
2333

2434
const link = document.createElement('link')
@@ -29,7 +39,7 @@ export async function injectBundle (ready: () => void) {
2939
document.head.appendChild(script)
3040
document.head.appendChild(link)
3141

32-
injectReporterStyle()
42+
// injectReporterStyle()
3343

3444
script.onload = () => {
3545
// @ts-ignore - just stick config on window until we figure out how we are

packages/app/src/runner/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,11 @@ export function getRunnerElement () {
1919
export function getReporterElement () {
2020
return getElementById(REPORTER_ID)
2121
}
22+
23+
export function empty (el: HTMLElement) {
24+
while (el.lastChild) {
25+
if (el && el.firstChild) {
26+
el.removeChild(el.firstChild)
27+
}
28+
}
29+
}

packages/app/src/runs/Runner.vue

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<template>
2+
<div>
3+
<div v-once>
4+
<div class="flex">
5+
<div :id="RUNNER_ID" />
6+
<div :id="REPORTER_ID" />
7+
</div>
8+
</div>
9+
</div>
10+
</template>
11+
12+
<script lang="ts" setup>
13+
import { onBeforeUnmount, onMounted } from 'vue'
14+
import { UnifiedRunnerAPI } from '../runner'
15+
import { REPORTER_ID, RUNNER_ID, getRunnerElement, getReporterElement, empty } from '../runner/utils'
16+
import { gql } from '@urql/core'
17+
import type { CurrentSpec_RunnerFragment } from '../generated/graphql'
18+
19+
gql`
20+
fragment CurrentSpec_Runner on Spec {
21+
id
22+
relative
23+
absolute
24+
name
25+
}
26+
`
27+
28+
const props = defineProps<{
29+
gql: CurrentSpec_RunnerFragment | null
30+
}>()
31+
32+
onMounted(() => {
33+
UnifiedRunnerAPI.initialize(execute)
34+
})
35+
36+
onBeforeUnmount(() => {
37+
// For now we clean up the AUT and Reporter every time we leave the route.
38+
// In the long term, we really should use <keep-alive> and maintain the state
39+
// For now, this is much more simple.
40+
empty(getRunnerElement())
41+
window.UnifiedRunner.shortcuts.stop()
42+
empty(getReporterElement())
43+
})
44+
45+
const execute = () => {
46+
if (!props.gql) {
47+
return
48+
}
49+
50+
UnifiedRunnerAPI.executeSpec(props.gql)
51+
}
52+
</script>
53+
54+
<style scoped>
55+
#unified-runner {
56+
position: relative;
57+
flex-grow: 1;
58+
margin: 20px;
59+
box-shadow: 0px 0px 5px 0 black;
60+
padding: 10px;
61+
}
62+
63+
#unified-reporter {
64+
position: relative;
65+
width: 300px;
66+
height: 100vh;
67+
}
68+
</style>
69+
70+
<route>
71+
{
72+
name: "Runner"
73+
}
74+
</route>

packages/app/src/specs/SpecsList.vue

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,41 @@
99
<div>{{ t('specPage.componentSpecsHeader') }}</div>
1010
<div>{{ t('specPage.gitStatusHeader') }}</div>
1111
</div>
12-
<router-link
12+
<button
1313
v-for="spec in filteredSpecs"
14-
v-slot="{ navigate }"
1514
:key="spec.node.id"
16-
:to="path(spec)"
15+
class="text-left"
16+
@click.prevent="selectSpec(spec)"
1717
>
18-
<SpecsListRow
19-
:gql="spec"
20-
@click="navigate"
21-
@keypress.enter="navigate"
22-
/>
23-
</router-link>
18+
<SpecsListRow :gql="spec" />
19+
</button>
2420
</div>
2521
</div>
2622
</template>
2723

2824
<script setup lang="ts">
2925
import SpecsListHeader from './SpecsListHeader.vue'
3026
import SpecsListRow from './SpecsListRow.vue'
31-
import { gql } from '@urql/vue'
27+
import { gql, useMutation } from '@urql/vue'
3228
import { computed, ref } from 'vue'
33-
import type { Specs_SpecsListFragment, SpecNode_SpecsListFragment } from '../generated/graphql'
29+
import { Specs_SpecsListFragment, SpecNode_SpecsListFragment, SpecsList_SetCurrentSpecDocument } from '../generated/graphql'
3430
import { useI18n } from '@cy/i18n'
31+
import { useRouter } from 'vue-router'
3532
3633
const { t } = useI18n()
37-
const path = (spec: SpecNode_SpecsListFragment) => `/runner/#${spec.node.absolute}`
34+
35+
gql`
36+
mutation SpecsList_SetCurrentSpec($id: ID!) {
37+
setCurrentSpec(id: $id) {
38+
currentSpec {
39+
id
40+
relative
41+
absolute
42+
name
43+
}
44+
}
45+
}
46+
`
3847
3948
gql`
4049
fragment SpecNode_SpecsList on SpecEdge {
@@ -53,7 +62,7 @@ fragment Specs_SpecsList on App {
5362
activeProject {
5463
id
5564
projectRoot
56-
specs(first: 10) {
65+
specs(first: 25) {
5766
edges {
5867
...SpecNode_SpecsList
5968
}
@@ -62,6 +71,17 @@ fragment Specs_SpecsList on App {
6271
}
6372
`
6473
74+
const setSpecMutation = useMutation(SpecsList_SetCurrentSpecDocument)
75+
76+
const router = useRouter()
77+
78+
async function selectSpec (spec: SpecNode_SpecsListFragment) {
79+
const { id } = spec.node
80+
81+
await setSpecMutation.executeMutation({ id })
82+
router.push('runner')
83+
}
84+
6585
const props = defineProps<{
6686
gql: Specs_SpecsListFragment
6787
}>()

0 commit comments

Comments
 (0)