Skip to content

Commit 69d316e

Browse files
authored
feat(app): decouple event manager from driver (#18695)
* change event manager to be a class * update method * attach event manager to window for cypress-in-cypress * fix CT tests * do not use fake event manager anymore * remove cypress import from event manager * pass in cypress as arg * move regenerator runtime * move async runtime * include regenerator-runtime in runner unit tests * fix unit tests * inject studio * attach event manager to window for unified app * move event manager to app * move event manager entirely to app, delete runner-shared copy * improve tests * add missing arg * types * remove unused optimization
1 parent e3720df commit 69d316e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+619
-445
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { AutIframe } from '../../../src/runner/aut-iframe'
2+
import { EventManager } from '../../../src/runner/event-manager'
3+
import { logger } from '@packages/runner-shared/src/logger'
4+
import { blankContents } from '@packages/runner-shared/src/blank-contents'
5+
import _ from 'lodash'
6+
import { visitFailure } from '@packages/runner-shared/src/visit-failure'
7+
8+
class StudioRecorderMock {}
9+
10+
// Event manager with Cypress driver dependencies stubbed out
11+
// Useful for component testing
12+
export const createEventManager = () => {
13+
return new EventManager(
14+
null, // packages/driver, not needed for CT tests
15+
// @ts-ignore
16+
null, // MobX, also not needed in Vue CT tests,
17+
null, // selectorPlaygroundModel,
18+
StudioRecorderMock, // needs to be a valid class
19+
)
20+
}
21+
22+
// Stub AutIframe, useful for component testing
23+
export const createTestAutIframe = (eventManager = createEventManager()) => {
24+
return new AutIframe(
25+
'Test Project',
26+
eventManager,
27+
_,
28+
null, // CypressJQuery, shouldn't be using driver in component tests anyway
29+
logger,
30+
null, // dom - imports driver, which we don't want in CT, so just stub it out
31+
visitFailure,
32+
{
33+
recorder: eventManager.studioRecorder,
34+
selectorPlaygroundModel: eventManager.selectorPlaygroundModel,
35+
},
36+
blankContents,
37+
)
38+
}

packages/app/index.d.ts

-3
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,6 @@ declare global {
8080
_: any // lodash
8181
CypressJQuery: any
8282

83-
studioRecorder: any
84-
selectorPlaygroundModel: any
85-
8683
MobX: typeof MobX
8784

8885
/**

packages/app/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"graphql-tag": "^2.12.5",
4545
"javascript-time-ago": "2.3.8",
4646
"just-my-luck": "3.0.0",
47+
"lodash": "4.17.21",
4748
"pinia": "2.0.0-rc.14",
4849
"rimraf": "3.0.2",
4950
"rollup-plugin-polyfill-node": "^0.7.0",
@@ -78,8 +79,10 @@
7879
"@urql/exchange-execute",
7980
"@urql/vue",
8081
"@vueuse/core",
82+
"bluebird",
8183
"cypress-file-upload",
8284
"dedent",
85+
"events",
8386
"fake-uuid",
8487
"graphql",
8588
"graphql-relay",

packages/app/src/runner/SnapshotChangeState.vue

+6-1
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,20 @@
1313

1414
<script lang="ts" setup>
1515
import { computed } from 'vue'
16+
import type { AutIframe } from '../runner/aut-iframe'
1617
import { useSnapshotStore } from './snapshot-store'
1718
import SnapshotButtonGroup from './SnapshotButtonGroup.vue'
1819
1920
const snapshotStore = useSnapshotStore()
2021
2122
const changeState = (index: number) => {
22-
snapshotStore.changeState(index)
23+
snapshotStore.changeState(index, props.getAutIframe())
2324
}
2425
26+
const props = defineProps<{
27+
getAutIframe: () => AutIframe
28+
}>()
29+
2530
const snapshots = computed(() => {
2631
return (snapshotStore.snapshotProps?.snapshots || [])
2732
.map((x, index) => ({ ...x, index }))

packages/app/src/runner/SnapshotControls.spec.tsx

+42-8
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,36 @@
11
import SnapshotControls from './SnapshotControls.vue'
22
import { autSnapshot } from '../../cypress/support/fixtures'
33
import { useSnapshotStore } from './snapshot-store'
4+
import { createEventManager, createTestAutIframe } from '../../cypress/e2e/support/ctSupport'
45

5-
describe('SnapshotControls', () => {
6-
const mountSnapshotControls = () => {
7-
const eventManager = {} as typeof window.UnifiedRunner.eventManager
6+
// function createTestAutIframe () {
7+
// return new class {
8+
// removeHighlights () {}
9+
// }
10+
// }
811

9-
return cy.mount(() => <SnapshotControls eventManager={eventManager} />)
12+
describe('SnapshotControls', () => {
13+
const mountSnapshotControls = (
14+
eventManager = createEventManager(),
15+
autIframe = createTestAutIframe(),
16+
) => {
17+
return cy.mount(() => (
18+
<SnapshotControls
19+
eventManager={eventManager}
20+
getAutIframe={() => autIframe}
21+
/>
22+
))
1023
}
1124

12-
beforeEach(() => {
13-
return mountSnapshotControls()
14-
})
15-
1625
it('renders nothing when messageTitle is undefined', () => {
26+
mountSnapshotControls()
1727
cy.get('[data-cy="snapshot-highlight-controls"]').should('not.exist')
1828
cy.get('[data-cy="snapshot-message"]').should('not.exist')
1929
cy.get('[data-cy="snapshot-change-state"]').should('not.exist')
2030
})
2131

2232
it('renders snapshot title when one is pinned', () => {
33+
mountSnapshotControls()
2334
const snapshotStore = useSnapshotStore()
2435

2536
snapshotStore.pinSnapshot(autSnapshot)
@@ -28,6 +39,7 @@ describe('SnapshotControls', () => {
2839
})
2940

3041
it('renders snapshot pinned status', () => {
42+
mountSnapshotControls()
3143
const snapshotStore = useSnapshotStore()
3244

3345
snapshotStore.pinSnapshot(autSnapshot)
@@ -40,6 +52,7 @@ describe('SnapshotControls', () => {
4052
})
4153

4254
it('clears snapshot message', () => {
55+
mountSnapshotControls()
4356
const snapshotStore = useSnapshotStore()
4457

4558
snapshotStore.pinSnapshot(autSnapshot)
@@ -49,6 +62,7 @@ describe('SnapshotControls', () => {
4962
})
5063

5164
it('shows snapshot with custom message', () => {
65+
mountSnapshotControls()
5266
const message = 'This is a custom message'
5367
const snapshotStore = useSnapshotStore()
5468

@@ -57,6 +71,7 @@ describe('SnapshotControls', () => {
5771
})
5872

5973
it('does not show highlight controls if no element present on snapshot', () => {
74+
mountSnapshotControls()
6075
const snapshotStore = useSnapshotStore()
6176

6277
snapshotStore.pinSnapshot(autSnapshot)
@@ -65,19 +80,38 @@ describe('SnapshotControls', () => {
6580

6681
it('toggles highlight controls if snapshot has an element', () => {
6782
const snapshotStore = useSnapshotStore()
83+
const eventManager = createEventManager()
84+
const autIframe = createTestAutIframe()
85+
const removeHighlights = cy.stub(autIframe, 'removeHighlights')
6886

87+
// we don't have an iframe-model since this is a CT test, but we can
88+
// simulate it by registering the same unpin:snapshot event it does.
89+
eventManager.on('unpin:snapshot', () => snapshotStore.unpinSnapshot())
6990
snapshotStore.pinSnapshot({ ...autSnapshot, $el: 'some element' })
91+
92+
mountSnapshotControls(eventManager, autIframe)
7093
cy.get('[data-cy="snapshot-highlight-controls"]').should('exist')
94+
cy.get('[data-cy="toggle-snapshot-highlights"]').as('toggle')
95+
cy.get('@toggle').should('have.attr', 'title', 'Hide highlights')
96+
cy.get('@toggle').click().then(() => {
97+
expect(removeHighlights).to.have.been.calledOnce
98+
})
99+
100+
cy.get('@toggle').should('have.attr', 'title', 'Show highlights')
101+
cy.get('[data-cy="unpin-snapshot"]').click()
102+
cy.get('[data-cy="snapshot-highlight-controls"]').should('not.exist')
71103
})
72104

73105
it('shows running test error', () => {
106+
mountSnapshotControls()
74107
const snapshotStore = useSnapshotStore()
75108

76109
snapshotStore.setTestsRunningError()
77110
cy.get('[data-cy="snapshot-message"]').contains('Cannot show Snapshot while tests are running')
78111
})
79112

80113
it('shows snapshot missing error', () => {
114+
mountSnapshotControls()
81115
const snapshotStore = useSnapshotStore()
82116

83117
snapshotStore.setMissingSnapshotMessage()

packages/app/src/runner/SnapshotControls.vue

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
<SnapshotHighlightControls
1212
v-if="snapshotStore.isSnapshotPinned && snapshotStore.snapshotProps?.$el"
1313
:event-manager="props.eventManager"
14+
:get-aut-iframe="props.getAutIframe"
1415
/>
1516

1617
<SnapshotChangeState
1718
v-if="snapshotStore.isSnapshotPinned && shouldShowStateControls"
19+
:get-aut-iframe="props.getAutIframe"
1820
/>
1921
</div>
2022
</div>
@@ -26,9 +28,12 @@ import { useSnapshotStore } from './snapshot-store'
2628
import SnapshotMessage from './SnapshotMessage.vue'
2729
import SnapshotChangeState from './SnapshotChangeState.vue'
2830
import SnapshotHighlightControls from './SnapshotHighlightControls.vue'
31+
import type { EventManager } from '../runner/event-manager'
32+
import type { AutIframe } from '../runner/aut-iframe'
2933
3034
const props = defineProps<{
31-
eventManager: typeof window.UnifiedRunner.eventManager
35+
eventManager: EventManager
36+
getAutIframe: () => AutIframe
3237
}>()
3338
3439
const snapshotStore = useSnapshotStore()

packages/app/src/runner/SnapshotHighlightControls.vue

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<i className="fas fa-times" />
99
</button>
1010
<button
11+
data-cy="toggle-snapshot-highlights"
1112
:title="`${snapshotStore.snapshot?.showingHighlights ? 'Hide' : 'Show'} highlights`"
1213
@click="toggleHighlights"
1314
>
@@ -17,11 +18,14 @@
1718
</template>
1819

1920
<script lang="ts" setup>
21+
import type { AutIframe } from '../runner/aut-iframe'
22+
import type { EventManager } from '../runner/event-manager'
2023
import { useSnapshotStore } from './snapshot-store'
2124
import SnapshotButtonGroup from './SnapshotButtonGroup.vue'
2225
2326
const props = defineProps<{
24-
eventManager: typeof window.UnifiedRunner.eventManager
27+
eventManager: EventManager
28+
getAutIframe: () => AutIframe
2529
}>()
2630
2731
const snapshotStore = useSnapshotStore()
@@ -31,7 +35,7 @@ const unpin = () => {
3135
}
3236
3337
const toggleHighlights = () => {
34-
snapshotStore.toggleHighlights()
38+
snapshotStore.toggleHighlights(props.getAutIframe())
3539
}
3640
</script>
3741

packages/app/src/runner/SpecRunner.vue

+7-4
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@
3232
:style="viewportStyle"
3333
/>
3434
</div>
35-
<SnapshotControls :event-manager="eventManager" />
35+
<SnapshotControls
36+
:event-manager="eventManager"
37+
:get-aut-iframe="getAutIframeModel"
38+
/>
3639
</div>
3740
</div>
3841
</template>
@@ -43,8 +46,8 @@ import { REPORTER_ID, RUNNER_ID, getRunnerElement, getReporterElement, empty } f
4346
import { gql } from '@urql/core'
4447
import type { SpecRunnerFragment } from '../generated/graphql'
4548
import InlineSpecList from '../specs/InlineSpecList.vue'
49+
import { getAutIframeModel, getEventManager, UnifiedRunnerAPI } from '../runner'
4650
import { useAutStore } from '../store'
47-
import { UnifiedRunnerAPI } from '../runner'
4851
import type { BaseSpec } from '@packages/types'
4952
import SnapshotControls from './SnapshotControls.vue'
5053
import SpecRunnerHeader from './SpecRunnerHeader.vue'
@@ -56,7 +59,7 @@ fragment SpecRunner on App {
5659
}
5760
`
5861
59-
const eventManager = window.UnifiedRunner.eventManager
62+
const eventManager = getEventManager()
6063
6164
const autStore = useAutStore()
6265
@@ -91,7 +94,7 @@ watch(() => props.activeSpec, (spec) => {
9194
}, { immediate: true, flush: 'post' })
9295
9396
onMounted(() => {
94-
window.UnifiedRunner.eventManager.on('restart', () => {
97+
getEventManager().on('restart', () => {
9598
runSpec()
9699
})
97100
})

0 commit comments

Comments
 (0)