Skip to content

Commit

Permalink
chore: set up sharing of react via module federation in studio (#31129)
Browse files Browse the repository at this point in the history
* chore: set up sharing of react via module federation in studio

* PR comments
  • Loading branch information
ryanthemanuel authored Feb 24, 2025
1 parent a6e2efc commit 0177508
Show file tree
Hide file tree
Showing 16 changed files with 192 additions and 85 deletions.
2 changes: 2 additions & 0 deletions packages/app/cypress/e2e/cypress-in-cypress-component.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ describe('Cypress In Cypress CT', { viewportWidth: 1500, defaultCommandTimeout:

// Temporarily removed from CT since it doesn't work. Invert this assertion when completing https://github.com/cypress-io/cypress/issues/24549
cy.get('.hook-open-in-ide').should('not.exist')

cy.get('#unified-runner').should('have.attr', 'style', 'width: 500px; height: 500px; transform: scale(1); position: absolute; margin-left: 225px;')
})

it('navigation between specs and other parts of the app works', () => {
Expand Down
2 changes: 2 additions & 0 deletions packages/app/cypress/e2e/cypress-in-cypress-e2e.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ describe('Cypress In Cypress E2E', { viewportWidth: 1500, defaultCommandTimeout:
})

cy.get('.hook-open-in-ide').should('exist')

cy.get('#unified-runner').should('have.attr', 'style', 'width: 1000px; height: 660px; transform: scale(0.769697); position: absolute; margin-left: -25px;')
})

it('navigation between specs and other parts of the app works', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"@headlessui/vue": "1.4.0",
"@iconify-json/mdi": "1.1.63",
"@intlify/unplugin-vue-i18n": "4.0.0",
"@module-federation/vite": "^1.2.2",
"@module-federation/runtime": "^0.8.11",
"@packages/data-context": "0.0.0-development",
"@packages/frontend-shared": "0.0.0-development",
"@packages/graphql": "0.0.0-development",
Expand Down
21 changes: 20 additions & 1 deletion packages/app/src/runner/ResizablePanels.cy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const slotContents = {
panel1: () => <div class="h-full bg-emerald-100">panel1</div>,
panel2: () => <div class="h-full bg-purple-300">panel2</div>,
panel3: () => <div class="grow h-full bg-indigo-100">panel3</div>,
panel4: () => <div class="h-full bg-yellow-100">panel4</div>,
}

describe('<ResizablePanels />', { viewportWidth: 1500, defaultCommandTimeout: 4000 }, () => {
Expand Down Expand Up @@ -169,7 +170,7 @@ describe('<ResizablePanels />', { viewportWidth: 1500, defaultCommandTimeout: 40
assertWidth('panel3', 550)
})

it('Panel 3 resizes correctly when both panels are hidden', () => {
it('Panel 3 resizes correctly when all panels are hidden', () => {
cy.mount(() => (
<div class="h-screen">
<ResizablePanels
Expand All @@ -184,5 +185,23 @@ describe('<ResizablePanels />', { viewportWidth: 1500, defaultCommandTimeout: 40
cy.contains('panel2').should('not.be.visible')
assertWidth('panel3', 1500)
})

it('Panel 3 resizes correctly when panels 1 and 2 are hidden and panel 4 is shown', () => {
cy.mount(() => (
<div class="h-screen">
<ResizablePanels
maxTotalWidth={1500}
v-slots={slotContents}
showPanel1={false}
showPanel2={false}
showPanel4={true}
/>
</div>))

cy.contains('panel1').should('not.be.visible')
cy.contains('panel2').should('not.be.visible')
cy.contains('panel4').should('be.visible')
assertWidth('panel3', 1200)
})
})
})
34 changes: 31 additions & 3 deletions packages/app/src/runner/ResizablePanels.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@
:width="panel3width"
/>
</div>

<div
v-show="showPanel4"
data-cy="studio-panel"
class="h-full bg-gray-100 relative"
:style="{width: `${panel4Width}px`}"
>
<slot
name="panel4"
:width="panel4Width"
/>
</div>
</div>
</template>

Expand All @@ -72,6 +84,7 @@ import type { DraggablePanel } from './useRunnerStyle'
const props = withDefaults(defineProps<{
showPanel1?: boolean // specsList in runner
showPanel2?: boolean // reporter in runner
showPanel4?: boolean // studio in runner
initialPanel1Width?: number
initialPanel2Width?: number
minPanel1Width?: number
Expand All @@ -82,6 +95,7 @@ const props = withDefaults(defineProps<{
}>(), {
showPanel1: true,
showPanel2: true,
showPanel4: false,
initialPanel1Width: runnerConstants.defaultSpecListWidth,
initialPanel2Width: runnerConstants.defaultReporterWidth,
minPanel1Width: 200,
Expand Down Expand Up @@ -146,6 +160,14 @@ const maxPanel1Width = computed(() => {
return props.maxTotalWidth - unavailableWidth
})
const panel4Width = computed(() => {
if (!props.showPanel4) {
return 0
}
return runnerConstants.defaultStudioWidth
})
const panel1Width = computed(() => {
if (!props.showPanel1) {
return 0
Expand All @@ -155,13 +177,13 @@ const panel1Width = computed(() => {
})
const maxPanel2Width = computed(() => {
const unavailableWidth = panel1Width.value + props.minPanel3Width
const unavailableWidth = panel1Width.value + props.minPanel3Width + panel4Width.value
return props.maxTotalWidth - unavailableWidth
})
const panel3width = computed(() => {
const panel3SpaceAvailable = props.maxTotalWidth - panel1Width.value - panel2Width.value
const panel3SpaceAvailable = props.maxTotalWidth - panel1Width.value - panel2Width.value - panel4Width.value
// minimumWithMargin - if panel 3 would end up below the minimum allowed size
// due to window resizing, forcing the minimum width will create a horizontal scroll
Expand All @@ -176,7 +198,7 @@ function handleResizeEnd (panel: DraggablePanel) {
}
function isNewWidthAllowed (mouseClientX: number, panel: DraggablePanel) {
const isMaxWidthSmall = props.maxTotalWidth < (panel1Width.value + panel2Width.value + props.minPanel3Width)
const isMaxWidthSmall = props.maxTotalWidth < (panel1Width.value + panel2Width.value + props.minPanel3Width + panel4Width.value)
const fallbackWidth = 50
if (panel === 'panel1') {
Expand Down Expand Up @@ -206,6 +228,12 @@ watchEffect(() => {
} else if (props.showPanel1) {
emit('panelWidthUpdated', { panel: 'panel1', width: cachedPanel1Width.value })
}
if (!props.showPanel4) {
emit('panelWidthUpdated', { panel: 'panel4', width: 0 })
} else if (props.showPanel4) {
emit('panelWidthUpdated', { panel: 'panel4', width: panel4Width.value })
}
})
</script>
29 changes: 16 additions & 13 deletions packages/app/src/runner/SpecRunnerOpenMode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
:min-panel3-width="minWidths.aut"
:show-panel1="runnerUiStore.isSpecsListOpen && !screenshotStore.isScreenshotting"
:show-panel2="!screenshotStore.isScreenshotting && !hideCommandLog"
:show-panel4="shouldShowStudioPanel"
@resize-end="handleResizeEnd"
@panel-width-updated="handlePanelWidthUpdated"
>
Expand Down Expand Up @@ -96,12 +97,15 @@
/>
<ScreenshotHelperPixels />
</template>
<template #panel4>
<StudioPanel v-show="shouldShowStudioPanel" />
</template>
</ResizablePanels>
</AdjustRunnerStyleDuringScreenshot>
</template>

<script lang="ts" setup>
import { computed, onBeforeUnmount, onMounted, watchEffect } from 'vue'
import { computed, onBeforeUnmount, onMounted } from 'vue'
import { REPORTER_ID, RUNNER_ID } from './utils'
import InlineSpecList from '../specs/InlineSpecList.vue'
import { getAutIframeModel, getEventManager } from '.'
Expand Down Expand Up @@ -130,6 +134,7 @@ import { runnerConstants } from './runner-constants'
import StudioInstructionsModal from './studio/StudioInstructionsModal.vue'
import StudioSaveModal from './studio/StudioSaveModal.vue'
import { useStudioStore } from '../store/studio-store'
import StudioPanel from '../studio/StudioPanel.vue'
const {
preferredMinimumPanelWidth,
Expand All @@ -148,6 +153,7 @@ fragment SpecRunner_Preferences on Query {
autoScrollingEnabled
reporterWidth
specListWidth
studioWidth
}
}
}
Expand Down Expand Up @@ -220,6 +226,10 @@ const reporterWidthPreferences = computed(() => {
return props.gql.localSettings.preferences.reporterWidth ?? runnerUiStore.reporterWidth
})
const studioWidthPreferences = computed(() => {
return props.gql.localSettings.preferences.studioWidth ?? runnerUiStore.studioWidth
})
const isSpecsListOpenPreferences = computed(() => {
return props.gql.localSettings.preferences.isSpecsListOpen ?? false
})
Expand All @@ -228,6 +238,10 @@ const studioStatus = computed(() => {
return props.gql.studio?.status
})
const shouldShowStudioPanel = computed(() => {
return studioStatus.value === 'INITIALIZED' && studioStore.isActive
})
const hideCommandLog = runnerUiStore.hideCommandLog
// watch active spec, and re-run if it changes!
Expand All @@ -245,6 +259,7 @@ if (!hideCommandLog) {
preferences.update('isSpecsListOpen', isSpecsListOpenPreferences.value)
preferences.update('reporterWidth', reporterWidthPreferences.value)
preferences.update('specListWidth', specsListWidthPreferences.value)
preferences.update('studioWidth', studioWidthPreferences.value)
// 👆 we must update these preferences before calling useRunnerStyle, to make sure that values from GQL
// will be available during the initial calculation that useRunnerStyle does
}
Expand Down Expand Up @@ -300,18 +315,6 @@ function openFile () {
})
}
watchEffect(() => {
if (studioStatus.value === 'INITIALIZED') {
import('app-studio').then(({ mountTestGenerationPanel }) => {
// eslint-disable-next-line no-console
console.log('Studio loaded', mountTestGenerationPanel)
}).catch((err) => {
// eslint-disable-next-line no-console
console.error('Error loading Studio', err)
})
}
})
onMounted(() => {
const eventManager = getEventManager()
Expand Down
1 change: 1 addition & 0 deletions packages/app/src/runner/runner-constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export const runnerConstants = {
defaultSpecListWidth: 280,
defaultReporterWidth: 450,
defaultStudioWidth: 300,
preferredMinimumPanelWidth: 200,
absoluteAutMinimum: 100,
absoluteSpecListMinimum: 50,
Expand Down
12 changes: 9 additions & 3 deletions packages/app/src/runner/useRunnerStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useAutStore, useRunnerUiStore } from '../store'
import { useScreenshotStore } from '../store/screenshot-store'
import { runnerConstants } from './runner-constants'

export type ResizablePanelName = 'panel1' | 'panel2' | 'panel3'
export type ResizablePanelName = 'panel1' | 'panel2' | 'panel3' | 'panel4'

export type DraggablePanel = Exclude<ResizablePanelName, 'panel3'>

Expand All @@ -17,6 +17,7 @@ const autMargin = 16
// so that we only save to GQL when the resizing has ended
const reporterWidth = ref<number>(0)
const specListWidth = ref<number>(0)
const studioWidth = ref<number>(0)

export const useRunnerStyle = () => {
const { width: windowWidth, height: windowHeight } = useWindowSize()
Expand All @@ -26,10 +27,11 @@ export const useRunnerStyle = () => {
const screenshotStore = useScreenshotStore()
const autStore = useAutStore()

const { reporterWidth: initialReporterWidth, specListWidth: initialSpecsListWidth } = runnerUIStore
const { reporterWidth: initialReporterWidth, specListWidth: initialSpecsListWidth, studioWidth: initialStudioWidth } = runnerUIStore

reporterWidth.value = initialReporterWidth
specListWidth.value = initialSpecsListWidth
studioWidth.value = initialStudioWidth

const containerWidth = computed(() => {
const miscBorders = 4
Expand All @@ -47,7 +49,7 @@ export const useRunnerStyle = () => {
nonAutWidth += (autMargin * 2)
}

nonAutWidth += reporterWidth.value + specListWidth.value + miscBorders
nonAutWidth += reporterWidth.value + specListWidth.value + studioWidth.value + miscBorders
}

const containerWidth = windowWidth.value - nonAutWidth
Expand Down Expand Up @@ -117,6 +119,8 @@ export function useResizablePanels () {
const handleResizeEnd = async (panel: DraggablePanel) => {
if (panel === 'panel1') {
await preferences.update('specListWidth', specListWidth.value)
} else if (panel === 'panel4') {
await preferences.update('studioWidth', studioWidth.value)
} else {
await preferences.update('reporterWidth', reporterWidth.value)
}
Expand All @@ -125,6 +129,8 @@ export function useResizablePanels () {
const handlePanelWidthUpdated = ({ panel, width }: { panel: DraggablePanel, width: number }) => {
if (panel === 'panel1') {
specListWidth.value = width
} else if (panel === 'panel4') {
studioWidth.value = width
} else {
reporterWidth.value = width
}
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/store/runner-ui-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface RunnerUiState {
isSpecsListOpen: boolean
specListWidth: number
reporterWidth: number
studioWidth: number
automationStatus: AutomationStatus
randomString: string
hideCommandLog: boolean
Expand All @@ -40,6 +41,7 @@ export const useRunnerUiStore = defineStore({
isSpecsListOpen: false,
specListWidth: runnerConstants.defaultSpecListWidth,
reporterWidth: runnerConstants.defaultReporterWidth,
studioWidth: runnerConstants.defaultStudioWidth,
automationStatus: automation.CONNECTING,
randomString: `${Math.random()}`,
hideCommandLog: window.__CYPRESS_CONFIG__.hideCommandLog,
Expand Down
Loading

5 comments on commit 0177508

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 0177508 Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/14.0.4/linux-x64/develop-017750810e246ff1f16e8632cd4e0385a8c843d8/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 0177508 Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/14.0.4/linux-arm64/develop-017750810e246ff1f16e8632cd4e0385a8c843d8/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 0177508 Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the win32 x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/14.0.4/win32-x64/develop-017750810e246ff1f16e8632cd4e0385a8c843d8/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 0177508 Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin arm64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/14.0.4/darwin-arm64/develop-017750810e246ff1f16e8632cd4e0385a8c843d8/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 0177508 Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release build at https://on.cypress.io/advanced-installation#Install-pre-release-version

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/14.0.4/darwin-x64/develop-017750810e246ff1f16e8632cd4e0385a8c843d8/cypress.tgz

Please sign in to comment.