mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-26 00:50:41 -05:00
Merge branch '10.0-release' into 10.0-release-merge-develop-03-22
This commit is contained in:
@@ -29,7 +29,6 @@ mainBuildFilters: &mainBuildFilters
|
||||
only:
|
||||
- develop
|
||||
- 10.0-release
|
||||
- UNIFY-1294-specs-list-flake
|
||||
|
||||
# usually we don't build Mac app - it takes a long time
|
||||
# but sometimes we want to really confirm we are doing the right thing
|
||||
@@ -39,7 +38,6 @@ macWorkflowFilters: &mac-workflow-filters
|
||||
or:
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
- equal: [ '10.0-release', << pipeline.git.branch >> ]
|
||||
- equal: [ UNIFY-1294-specs-list-flake, << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: "-release$"
|
||||
value: << pipeline.git.branch >>
|
||||
@@ -49,7 +47,6 @@ windowsWorkflowFilters: &windows-workflow-filters
|
||||
or:
|
||||
- equal: [ develop, << pipeline.git.branch >> ]
|
||||
- equal: [ '10.0-release', << pipeline.git.branch >> ]
|
||||
- equal: [ UNIFY-1294-specs-list-flake, << pipeline.git.branch >> ]
|
||||
- matches:
|
||||
pattern: "-release$"
|
||||
value: << pipeline.git.branch >>
|
||||
|
||||
@@ -126,7 +126,7 @@ describe('App: Index', () => {
|
||||
|
||||
expectedScaffoldPaths.forEach((spec) => {
|
||||
// Validate that links for each generated spec are rendered
|
||||
cy.get(`a[href="#/specs/runner?file=${spec}"`).scrollIntoView().should('exist')
|
||||
cy.get(`a[href="${getRunnerHref(spec)}"`).scrollIntoView().should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -51,9 +51,10 @@ export function testUrqlClient (context: ClientTestContext,
|
||||
|
||||
if (firstMutation.kind === 'OperationDefinition') {
|
||||
const mutationName = firstMutation.name?.value
|
||||
const mutationResolver = mutationName && mutationResolvers.get(mutationName)
|
||||
|
||||
if (mutationName && mutationResolvers[mutationName]) {
|
||||
const val = mutationResolvers[mutationName]((conf: any) => (conf), result.operation.variables)
|
||||
if (mutationResolver) {
|
||||
const val = mutationResolver((conf: any) => (conf), result.operation.variables)
|
||||
|
||||
if (val) {
|
||||
result.data = val
|
||||
|
||||
@@ -150,7 +150,7 @@ export const registerMountFn = ({ plugins }: MountFnOptions = {}) => {
|
||||
const definition = document.definitions[0]
|
||||
|
||||
if (definition.kind === 'OperationDefinition' && definition.name) {
|
||||
mutationResolvers[definition.name.value] = resolver
|
||||
mutationResolvers.set(definition.name.value, resolver)
|
||||
} else {
|
||||
throw new Error('only use mutation documents in stubMutationResolver first argument')
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ describe('<Select />', () => {
|
||||
})
|
||||
|
||||
describe('#icons', () => {
|
||||
// TODO: Fix this
|
||||
// TODO: Enable with completion of UNIFY-1375
|
||||
it.skip('marks the selected item with a check by default', () => {
|
||||
mountSelect().then(openSelect)
|
||||
.then(selectFirstOption)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import CopyButton from './CopyButton.vue'
|
||||
import { Clipboard_CopyToClipboardDocument } from '../generated/graphql'
|
||||
|
||||
describe('<CopyButton />', { viewportHeight: 80, viewportWidth: 120 }, () => {
|
||||
it('copies text to clipboard', () => {
|
||||
@@ -7,13 +8,23 @@ describe('<CopyButton />', { viewportHeight: 80, viewportWidth: 120 }, () => {
|
||||
</>))
|
||||
.get('button')
|
||||
.should('contain.text', 'Copy')
|
||||
|
||||
.get('svg')
|
||||
.should('exist')
|
||||
|
||||
// TODO: UNIFY-999 Solve "write permission denied" error to test this in run mode
|
||||
// cy.findByRole('button', { name: 'Copy' }).realClick()
|
||||
// cy.findByRole('button', { name: 'Copied!' }).should('be.visible')
|
||||
const copyStub = cy.stub()
|
||||
|
||||
cy.stubMutationResolver(Clipboard_CopyToClipboardDocument, (defineResult, { text }) => {
|
||||
copyStub(text)
|
||||
|
||||
return defineResult({
|
||||
copyTextToClipboard: true,
|
||||
})
|
||||
})
|
||||
|
||||
cy.findByRole('button', { name: 'Copy' }).click()
|
||||
cy.findByRole('button', { name: 'Copied!' }).should('be.visible')
|
||||
|
||||
cy.wrap(copyStub).should('have.been.calledWith', 'Foobar')
|
||||
})
|
||||
|
||||
it('noIcon hides the icon', () => {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
declare global {
|
||||
namespace Cypress {
|
||||
interface Chainable {
|
||||
attachFileWithPath: (path: string) => Chainable<HTMLInputElement>
|
||||
attachFileWithPath: (path: string) => Chainable<JQuery<HTMLInputElement>>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function attachedFileWithPath (subject: HTMLInputElement, path: string) {
|
||||
export function attachFileWithPath (subject, path: string) {
|
||||
const attachedFile = new File([new Blob()], 'cypress.config.ts')
|
||||
|
||||
Object.defineProperty(attachedFile, 'path', { value: path })
|
||||
@@ -22,6 +22,5 @@ export function attachedFileWithPath (subject: HTMLInputElement, path: string) {
|
||||
Cypress.Commands.add(
|
||||
'attachFileWithPath',
|
||||
{ prevSubject: true },
|
||||
// TODO: Figure out why https://github.com/cypress-io/cypress/pull/19003 isn't fixing this?
|
||||
attachedFileWithPath as any,
|
||||
attachFileWithPath,
|
||||
)
|
||||
|
||||
@@ -906,7 +906,8 @@ describe('Full migration flow for each project', { retries: { openMode: 2, runMo
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: toLaunchpad emitter not working in Cypress in Cypress.
|
||||
// TODO: UNIFY-1350 toLaunchpad emitter not working in Cypress in Cypress,
|
||||
// re-evaluate after conversion to subscriptions
|
||||
describe.skip('component testing migration - defaults', () => {
|
||||
it('live update migration UI as user moves files', () => {
|
||||
cy.scaffoldProject('migration-component-testing-customized')
|
||||
|
||||
@@ -122,11 +122,7 @@ describe('Launchpad: Setup Project', () => {
|
||||
cy.get('@aboutTestingTypes').should('not.exist')
|
||||
})
|
||||
|
||||
// Cypress enter key down isn't trigger close callback. Working correctly when manually tested
|
||||
// or when using the cypress-real-evens plugin.
|
||||
// Could be related to this bug? https://github.com/cypress-io/cypress/issues/14864
|
||||
// FIXME: https://github.com/cypress-io/cypress/pull/19726
|
||||
it.skip('closes modal by pressing enter key when close button is focused', () => {
|
||||
it('closes modal by pressing enter key when close button is focused', () => {
|
||||
cy.contains('Review the differences').click()
|
||||
cy.get('#app').should('have.attr', 'aria-hidden', 'true')
|
||||
|
||||
@@ -136,10 +132,8 @@ describe('Launchpad: Setup Project', () => {
|
||||
.within(() => {
|
||||
cy.get('h2').contains('Key Differences').should('be.visible')
|
||||
|
||||
cy.tabUntil((el) => el.text().includes('Close'))
|
||||
|
||||
cy.findByRole('button', { name: 'Close' })
|
||||
.should('have.focus')
|
||||
.focus()
|
||||
.type('{enter}')
|
||||
})
|
||||
|
||||
|
||||
@@ -29,27 +29,40 @@ describe('FileRow', () => {
|
||||
content={content}
|
||||
filePath="cypress/integration/support.ts"
|
||||
description={description}
|
||||
fileExtension=".ts"
|
||||
/>
|
||||
<FileRow
|
||||
status="changes"
|
||||
content={content}
|
||||
filePath="cypress/integration/command.js"
|
||||
description={description}
|
||||
fileExtension=".js"
|
||||
/>
|
||||
<FileRow
|
||||
status="skipped"
|
||||
content={content}
|
||||
filePath="cypress.config.js"
|
||||
description={description}
|
||||
fileExtension=".js"
|
||||
/>
|
||||
<FileRow
|
||||
status="error"
|
||||
content={content}
|
||||
filePath="cypress/integration/index.js"
|
||||
description={description}
|
||||
fileExtension=".js"
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
|
||||
cy.get('pre.shiki').should('exist')
|
||||
|
||||
cy.contains('cypress/integration/support.ts')
|
||||
cy.contains('cypress/integration/command.js')
|
||||
cy.contains('cypress.config.js')
|
||||
cy.contains('cypress/integration/index.js')
|
||||
|
||||
cy.percySnapshot()
|
||||
})
|
||||
|
||||
it('opens on click', () => {
|
||||
@@ -60,12 +73,14 @@ describe('FileRow', () => {
|
||||
content={content}
|
||||
filePath="cypress/integration/support.js"
|
||||
description={description}
|
||||
fileExtension=".js"
|
||||
/>
|
||||
<FileRow
|
||||
status="changes"
|
||||
content={content}
|
||||
filePath="cypress/integration/command.js"
|
||||
description={description}
|
||||
fileExtension=".js"
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
@@ -75,7 +90,11 @@ describe('FileRow', () => {
|
||||
cy.contains(messages.changesRequiredBadge).should('not.exist') // Hide badge when row is expanded
|
||||
cy.contains(changesRequiredDescription).should('be.visible')
|
||||
cy.get('pre').should('have.length', 2)
|
||||
|
||||
cy.percySnapshot('row starts open')
|
||||
cy.contains('cypress/integration/command.js').click()
|
||||
|
||||
cy.percySnapshot('row collapses after click')
|
||||
})
|
||||
|
||||
it('responds nice to small screens', { viewportWidth: 500 }, () => {
|
||||
@@ -88,6 +107,7 @@ describe('FileRow', () => {
|
||||
content={content}
|
||||
filePath="cypress/integration/command.js"
|
||||
description={lorem}
|
||||
fileExtension=".js"
|
||||
/>
|
||||
</div>
|
||||
))
|
||||
@@ -97,5 +117,7 @@ describe('FileRow', () => {
|
||||
cy.contains(messages.changesRequiredBadge).should('not.exist')
|
||||
cy.contains(changesRequiredDescription).should('be.visible')
|
||||
cy.get('pre').should('exist')
|
||||
|
||||
cy.percySnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -96,12 +96,13 @@ const props = defineProps<{
|
||||
filePath: string
|
||||
content: string
|
||||
description?: string
|
||||
fileExtension: string
|
||||
}>()
|
||||
|
||||
// TODO: Remove this. Use FileParts when available
|
||||
const language = computed(() => {
|
||||
// get the extension of the current file path
|
||||
const extension = /\.(\w+)$/.exec(props.filePath)?.[1]
|
||||
// The fileExtension from FileParts is prepended with a period;
|
||||
// we must strip the period to validate against our supported languages.
|
||||
let extension = props.fileExtension.replace(/^\./, '')
|
||||
|
||||
if (extension && (langsSupported as readonly string[]).includes(extension)) {
|
||||
return extension as CyLangType
|
||||
|
||||
@@ -100,7 +100,8 @@ withDefaults(defineProps<{
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
// TODO: remove this when vue3-file-selector supports setting this attribute
|
||||
// vue3-file-selector does not support setting these attributes through props,
|
||||
// so we add them directly after mounting.
|
||||
const fileRef = projectUpload.value?.querySelector('input[type=file]')
|
||||
|
||||
fileRef?.setAttribute('webkitdirectory', 'webkitdirectory')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defaultMessages } from '@cy/i18n'
|
||||
import GlobalPage from './GlobalPage.vue'
|
||||
import type { GlobalPageFragment } from '../generated/graphql-test'
|
||||
import { GlobalPageFragmentDoc } from '../generated/graphql-test'
|
||||
import { GlobalPageFragmentDoc, GlobalPage_AddProjectDocument } from '../generated/graphql-test'
|
||||
|
||||
const searchLabel = defaultMessages.globalPage.searchPlaceholder
|
||||
const emptyMessages = defaultMessages.globalPage.empty
|
||||
@@ -19,8 +19,42 @@ describe('<GlobalPage />', { viewportHeight: 900, viewportWidth: 1200 }, () => {
|
||||
cy.findByText(emptyMessages.title).should('be.visible')
|
||||
cy.findByText(emptyMessages.helper).should('be.visible')
|
||||
|
||||
// TODO: This should open a native file picker
|
||||
const addProjectStub = cy.stub()
|
||||
|
||||
cy.stubMutationResolver(GlobalPage_AddProjectDocument, (defineResult) => {
|
||||
addProjectStub()
|
||||
|
||||
return defineResult({
|
||||
addProject: {
|
||||
'projects': [
|
||||
{
|
||||
'id': '1',
|
||||
'title': 'some-test-title',
|
||||
'projectRoot': '/usr/local/dev/projects/some-test-title',
|
||||
'__typename': 'GlobalProject',
|
||||
},
|
||||
{
|
||||
'id': 'R2xvYmFsUHJvamVjdDoyOmFub3RoZXItdGVzdC1wcm9qZWN0',
|
||||
'title': 'another-test-project',
|
||||
'projectRoot': '/usr/local/dev/projects/another-test-project',
|
||||
'__typename': 'GlobalProject',
|
||||
},
|
||||
],
|
||||
'localSettings': {
|
||||
'availableEditors': [],
|
||||
'preferences': {
|
||||
'preferredEditorBinary': null,
|
||||
'__typename': 'LocalSettingsPreferences',
|
||||
},
|
||||
'__typename': 'LocalSettings',
|
||||
},
|
||||
'__typename': 'Query',
|
||||
} })
|
||||
})
|
||||
|
||||
cy.findByText(emptyMessages.browseManually).click()
|
||||
|
||||
cy.wrap(addProjectStub).should('have.been.called')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -47,11 +81,14 @@ describe('<GlobalPage />', { viewportHeight: 900, viewportWidth: 1200 }, () => {
|
||||
})
|
||||
|
||||
it('can add a project when clicking the button', () => {
|
||||
cy.findByText('cypress-config-ts').should('not.exist')
|
||||
|
||||
cy.contains('button', defaultMessages.globalPage.addProjectButton).click()
|
||||
cy.get('input[type=file]')
|
||||
.attachFileWithPath('absolute/path/to/yet-another-test-project/cypress.config.ts')
|
||||
.trigger('change', { force: true })
|
||||
// .findByText('yet-another-test-project').should('be.visible')
|
||||
|
||||
cy.findByText('cypress-config-ts').should('be.visible')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -22,15 +22,6 @@ app.use(createI18n())
|
||||
|
||||
let launchpadClient: Client
|
||||
|
||||
// TODO: (tim) remove this when we refactor to remove the retry plugin logic
|
||||
export function getLaunchpadClient () {
|
||||
if (!launchpadClient) {
|
||||
throw new Error(`Cannot access launchpadClient before app has been init`)
|
||||
}
|
||||
|
||||
return launchpadClient
|
||||
}
|
||||
|
||||
// Make sure highlighter is initialized before
|
||||
// we show any code to avoid jank at rendering
|
||||
Promise.all([
|
||||
|
||||
@@ -138,11 +138,9 @@ const emits = defineEmits<{
|
||||
const step1Modal = ref(false)
|
||||
const step2Modal = ref(false)
|
||||
|
||||
// probably to be changed for a GQL field
|
||||
const selectOption = ref<PossibleOption>()
|
||||
|
||||
function applySkipResult (val: PossibleOption) {
|
||||
// TODO: add a GQL mutation here
|
||||
selectOption.value = val
|
||||
emits('selectOption', selectOption.value)
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ const toInstall = computed(() => {
|
||||
return props.gql.wizard.packagesToInstall?.map((p) => p.package)
|
||||
})
|
||||
|
||||
// TODO: convert this to a subscription
|
||||
// TODO: UNIFY-1350 convert this to a subscription
|
||||
const intervalQueryTrigger = useIntervalFn(async () => {
|
||||
const res = await queryInstalled.executeQuery({ requestPolicy: 'network-only' })
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
:content="file.file.contents"
|
||||
:status="file.status"
|
||||
:file-path="file.file.relative"
|
||||
:file-extension="file.file.fileExtension"
|
||||
:description="file.description || undefined"
|
||||
/>
|
||||
<hr class="my-4">
|
||||
@@ -64,6 +65,7 @@ fragment ScaffoldedFiles on Query {
|
||||
absolute
|
||||
relative
|
||||
contents
|
||||
fileExtension
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ const warnings = computed(() => {
|
||||
const dismiss = (key) => {
|
||||
// TODO, call a mutation here so that the server persists the result of the mutation.
|
||||
// However, we still intend to keep the "warnings" dismissal so that the client updates immediately before the server responds.
|
||||
// UNIFY-1368
|
||||
dismissed.value[key] = true
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user