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

breaking: remove support for svelte 4 and support svelte 5 #30700

Merged
merged 1 commit into from
Dec 10, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .circleci/workflows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1828,6 +1828,32 @@ jobs:
command: |
# we need to bootstrap the binary into our project directory and run the tests
source ./system-tests/scripts/bootstrap-docker-container.sh 'yarn cypress run'
# We can remove this job a once https://github.com/sveltejs/svelte-loader/issues/243 is resolved.
AtofStryker marked this conversation as resolved.
Show resolved Hide resolved
svelte-webpack-system-test:
parallelism: 1
working_directory: ~/cypress
docker:
- image: cypress/browsers-internal:node20.18.1-bullseye-chrome131-ff133
environment:
# needed to inform the bootstrap-docker-container.sh script to link the binary in the system-test project directory
REPO_DIR: /root/cypress
TEST_PROJECT_DIR: ./system-tests/projects/svelte-webpack-configured
USE_YARN_TO_INSTALL_CYPRESS_BINARY: true
steps:
- maybe_skip_binary_jobs
- attach_workspace:
at: ~/
- run:
name: Install monorepo dependencies
command: yarn install --ignore-scripts
- run:
name: install dependencies
command: cd ./system-tests/projects/svelte-webpack-configured && yarn
- run:
name: Bootstrap the Cypress binary and run binary system test
command: |
# we need to bootstrap the binary into our project directory and run the tests
source ./system-tests/scripts/bootstrap-docker-container.sh 'yarn cypress run --component --spec src/mount.cy.ts src/App.cy.ts'

system-tests-chrome:
<<: *defaults
Expand Down Expand Up @@ -2993,6 +3019,7 @@ linux-x64-workflow: &linux-x64-workflow
- test-npm-module-on-minimum-node-version
- binary-system-tests
- yarn-pnp-preprocessor-system-test
- svelte-webpack-system-test
- test-kitchensink
- unit-tests
- verify-release-readiness
Expand Down Expand Up @@ -3112,6 +3139,11 @@ linux-x64-workflow: &linux-x64-workflow
requires:
- get-published-artifacts
- system-tests-node-modules-install
- svelte-webpack-system-test:
context: publish-binary
requires:
- get-published-artifacts
- system-tests-node-modules-install

linux-x64-contributor-workflow: &linux-x64-contributor-workflow
jobs:
Expand Down
3 changes: 2 additions & 1 deletion cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ _Released 12/17/2024 (PENDING)_
- `Next.js` versions 10, 11, 12, and 13. Addresses [#29583](https://github.com/cypress-io/cypress/issues/29583).
- `Nuxt.js` version 2. Addresses [#30468](https://github.com/cypress-io/cypress/issues/30468).
- `React` versions 16 and 17. Addresses [#29607](https://github.com/cypress-io/cypress/issues/29607).
- `Svelte` version 3. Addresses [#30492](https://github.com/cypress-io/cypress/issues/30492).
- `Svelte` versions 3 and 4. Addresses [#30492](https://github.com/cypress-io/cypress/issues/30492) and [#30692](https://github.com/cypress-io/cypress/issues/30692).
- `Vue` version 2. Addresses [#30295](https://github.com/cypress-io/cypress/issues/30295).
- The `cypress/react18` test harness is no longer included in the Cypress binary. Instead, React 18 support is now shipped with `cypress/react`! Addresses [#29607](https://github.com/cypress-io/cypress/issues/29607).
- The `cypress/angular-signals` test harness is no longer included in the Cypress binary. Instead, signals support is now shipped with `cypress/angular`! This requires `rxjs` to be installed as a `peerDependency`. Addresses [#29606](https://github.com/cypress-io/cypress/issues/29606).
Expand All @@ -43,6 +43,7 @@ in this [GitHub issue](https://github.com/cypress-io/cypress/issues/30447). Addr
- `React` version 19. Cypress will allow detected use of the React 19 Release Candidate until React 19 is officially released. Addresses [#29470](https://github.com/cypress-io/cypress/issues/29470).
- `Angular` version 19. Addresses [#30175](https://github.com/cypress-io/cypress/issues/30175).
- `Vite` version 6. Addresses [#30591](https://github.com/cypress-io/cypress/issues/30591).
- `Svelte` version 5. Addresses [#29641](https://github.com/cypress-io/cypress/issues/29641).

**Bugfixes:**

Expand Down
4 changes: 2 additions & 2 deletions npm/svelte/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# @cypress/svelte

Mount Svelte components in the open source [Cypress.io](https://www.cypress.io/) test runner **v10.7.0+**
Mount Svelte components in the open source [Cypress.io](https://www.cypress.io/) test runner

> **Note:** This package is bundled with the `cypress` package and should not need to be installed separately. See the [Svelte Component Testing Docs](https://docs.cypress.io/guides/component-testing/svelte/overview) for mounting Svelte components. Installing and importing `mount` from `@cypress/svelte` should only be done for advanced use-cases.
> **Note:** This package is bundled with the `cypress` package and should not need to be installed separately. See the [Svelte Component Testing Docs](https://docs.cypress.io/guides/component-testing/svelte/overview) for mounting Svelte components. Installing and importing `mount` from `@cypress/svelte` should only be done for advanced use-cases or in the case you may require an older or non supported version of svelte.

## Development

Expand Down
4 changes: 2 additions & 2 deletions npm/svelte/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@
},
"devDependencies": {
"@cypress/mount-utils": "0.0.0-development",
"svelte": "^4.2.19",
"svelte": "^5.4.0",
"typescript": "~5.4.5"
},
"peerDependencies": {
"cypress": ">=10.6.0",
"svelte": ">=4.0.0"
"svelte": ">=5.0.0"
},
"files": [
"dist/**/*"
Expand Down
8 changes: 7 additions & 1 deletion npm/svelte/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { createEntries } from '@cypress/mount-utils/create-rollup-entry.mjs'

const config = {
external: [
Copy link
Contributor Author

Choose a reason for hiding this comment

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

we did not need svelte as an imported dependency before, but now we need the mount and unmount functions in svelte 5. Since we want to use whatever version of svelte the user has installed, we want to bundle this as an external dependency

'svelte',
],
}

// updated respectExternal to false due to this issue: https://github.com/Swatinem/rollup-plugin-dts/issues/162#issuecomment-1702374232
export default createEntries({ formats: ['es', 'cjs'], input: 'src/index.ts', dtsOptions: { respectExternal: false } })
export default createEntries({ formats: ['es', 'cjs'], input: 'src/index.ts', dtsOptions: { respectExternal: false }, config })
47 changes: 22 additions & 25 deletions npm/svelte/src/mount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,25 @@ import {
getContainerEl,
setupHooks,
} from '@cypress/mount-utils'
import type { ComponentConstructorOptions, ComponentProps, SvelteComponent } from 'svelte'
import { mount as svelteMount, unmount as svelteUnmount } from 'svelte'
import type { MountOptions, Component } from 'svelte'

const DEFAULT_COMP_NAME = 'unknown'

type SvelteConstructor<T> = new (...args: any[]) => T;
type SvelteComponentOptions<T extends SvelteComponent> = Omit<
ComponentConstructorOptions<ComponentProps<T>>,
'hydrate' | 'target' | '$$inline'
>;

export interface MountOptions<T extends SvelteComponent>
extends SvelteComponentOptions<T> {
log?: boolean
}

export interface MountReturn<T extends SvelteComponent> {
component: T
export interface MountReturn{
component: Record<string, any>
}

let componentInstance: SvelteComponent | undefined
let componentInstance: Record<string, any> | undefined

const cleanup = () => {
componentInstance?.$destroy()
if (componentInstance) {
svelteUnmount(componentInstance)
}
}

// Extract the component name from the object passed to mount
const getComponentDisplayName = <T extends SvelteComponent>(Component: SvelteConstructor<T>): string => {
const getComponentDisplayName = (Component: Component<Record<string, any>, Record<string, any>, any>): string => {
if (Component.name) {
const [, match] = /Proxy\<(\w+)\>/.exec(Component.name) || []

Expand All @@ -41,7 +33,7 @@ const getComponentDisplayName = <T extends SvelteComponent>(Component: SvelteCon
/**
* Mounts a Svelte component inside the Cypress browser
*
* @param {SvelteConstructor<T>} Component Svelte component being mounted
* @param {Record<string, any>} Component Svelte component being mounted
* @param {MountReturn<T extends SvelteComponent>} options options to customize the component being mounted
* @returns Cypress.Chainable<MountReturn>
*
Expand All @@ -56,19 +48,24 @@ const getComponentDisplayName = <T extends SvelteComponent>(Component: SvelteCon
*
* @see {@link https://on.cypress.io/mounting-svelte} for more details.
*/
export function mount<T extends SvelteComponent> (
Component: SvelteConstructor<T>,
options: MountOptions<T> = {},
): Cypress.Chainable<MountReturn<T>> {
export function mount (
Component: Component<Record<string, any>, Record<string, any>, any>,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The component signature for svelte completely changed in Svelte 5, where Svelte components are no longer generic classes . Instead, the typing represents something more simple now, which is just a generic type of Record<string, any>

options: Omit<MountOptions, 'target'> & {log?: boolean} = {},
): Cypress.Chainable<MountReturn> {
// In Svelte 5, the component name is no longer easily discoverable and logs as "wrapper"
// so we default the logging of it to false as it doesn't provide a lot of value
options.log = options.log || false
Copy link
Contributor Author

Choose a reason for hiding this comment

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

depending on how Svelte is bundled has an impact here, where the name of the component can only be determined to be wrapper. For instance, the name in open mode is wrapper, but in run mode it's the full component name. This like has to do with the development version of svelte being used in open mode but production being used in run.

Because of this, I have default the mount log off by default as when developing tests it doesn't provide a lot of value to just say mount<wrapper>


return cy.then(() => {
// Remove last mounted component if cy.mount is called more than once in a test
cleanup()

const target = getContainerEl()

const ComponentConstructor = ((Component as any).default || Component) as SvelteConstructor<T>
const ComponentConstructor = ((Component as any).default || Component) as Component<Record<string, any>, Record<string, any>, any>

componentInstance = new ComponentConstructor({
// @see https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes
componentInstance = svelteMount(ComponentConstructor, {
target,
...options,
})
Expand All @@ -85,7 +82,7 @@ export function mount<T extends SvelteComponent> (
})
}
})
.wrap({ component: componentInstance as T }, { log: false })
.wrap({ component: componentInstance as Record<string, any> }, { log: false })
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ describe('scaffolding component testing', {
cy.contains('button', 'Next step').click()
cy.findByRole('button', { name: 'Continue' }).click()
cy.get('[data-cy="launchpad-Configuration files"]').should('be.visible')
verifyConfigFile(`cypress.config.js`)
verifyConfigFile(`cypress.config.ts`)
})
})

Expand All @@ -160,7 +160,7 @@ describe('scaffolding component testing', {
cy.contains('button', 'Next step').click()
cy.findByRole('button', { name: 'Continue' }).click()
cy.get('[data-cy="launchpad-Configuration files"]').should('be.visible')
verifyConfigFile(`cypress.config.js`)
verifyConfigFile(`cypress.config.ts`)
})
})

Expand Down
20 changes: 10 additions & 10 deletions packages/scaffold-config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ We will also attempt to scaffold a configuration file for projects using React a

### Supported Frameworks and Libraries

| Name | Version | Dev Server | Version | Library | Component Adaptor | Example Project |
| ---------------- | ------- | ---------- | -------- | -------------- | -------------------------- | ------------------------------------------------------------------- |
| React | - | Vite | 4.x, 5.x | React 16, 17 | `@cypress/react@latest` | [Link](../../system-tests/projects/react-vite-ts-configured) |
| React | - | Webpack | 4.x, 5.x | React 16, 17 | `@cypress/vue@latest` | [Link](../../system-tests/projects/react18) |
| Vue | - | Vite | 4.x, 5.x | Vue 3 | `@cypress/react@latest` | [Link](../../system-tests/projects/vue3-vite-ts-configured) |
| Vue | - | Webpack | 4.x, 5.x | Vue 3 | `@cypress/vue@latest` | [Link](../../system-tests/projects/vue3-webpack-ts-configured) |
| Angular | - | Webpack | 5.x | Angular 17, 18 | `@cypress/angular@latest` | [Link](../../system-tests/projects/angular-cli-configured) |
| Svelte | - | Vite | 4.x, 5.x | Svelte 4 | `@cypress/svelte@latest` | [Link](../../system-tests/projects/svelte-vite-configured) |
| Svelte | - | Webpack | 4.x, 5.x | Svelte 4 | `@cypress/svelte@latest` | [Link](../../system-tests/projects/svelte-webpack-configured) |
| Next.js | 14.x | Webpack | 4.x, 5.x | React 18 | `@cypress/react@latest` | [Link](../../system-tests/projects/nextjs-configured) |
| Name | Version| Dev Server | Version | Library | Component Adaptor | Example Project |
| ---------------- | -------| ---------- | ------- | ------------------ | -------------------------- | ------------------------------------------------------------------- |
| React | - | Vite | 4, 5 | React 18, 19 | `@cypress/react@latest` | [Link](../../system-tests/projects/react-vite-ts-configured) |
Copy link
Contributor Author

Choose a reason for hiding this comment

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

figured this was a good time to make sure the list is up to date

| React | - | Webpack | 4, 5 | React 18, 19 | `@cypress/vue@latest` | [Link](../../system-tests/projects/react18) |
| Vue | - | Vite | 4, 5, 6 | Vue 3 | `@cypress/react@latest` | [Link](../../system-tests/projects/vue3-vite-ts-configured) |
| Vue | - | Webpack | 4, 5 | Vue 3 | `@cypress/vue@latest` | [Link](../../system-tests/projects/vue3-webpack-ts-configured) |
| Angular | - | Webpack | 5 | Angular 17, 18, 19 | `@cypress/angular@latest` | [Link](../../system-tests/projects/angular-cli-configured) |
| Svelte | - | Vite | 4, 5, 6 | Svelte 5 | `@cypress/svelte@latest` | [Link](../../system-tests/projects/svelte-vite-configured) |
| Svelte | - | Webpack | 4, 5 | Svelte 5 | `@cypress/svelte@latest` | [Link](../../system-tests/projects/svelte-webpack-configured) |
| Next.js | 14, 15 | Webpack | 4, 5 | React 18, 19 | `@cypress/react@latest` | [Link](../../system-tests/projects/nextjs-configured) |

### Adding More Projects

Expand Down
2 changes: 1 addition & 1 deletion packages/scaffold-config/src/dependencies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const WIZARD_DEPENDENCY_SVELTE: Cypress.CypressComponentDependency = {
package: 'svelte',
installer: 'svelte',
description: 'Cybernetically enhanced web apps',
minVersion: '^4.0.0',
minVersion: '^5.0.0',
} as const

export const WIZARD_DEPENDENCIES = [
Expand Down
6 changes: 3 additions & 3 deletions packages/scaffold-config/test/unit/detect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,12 @@ describe('detectFramework', () => {
})
})

;['4.0.0', '5.0.0'].forEach((v) => {
;['5.0.0', '6.0.0'].forEach((v) => {
it(`Svelte and Vite v${v}`, async () => {
const projectPath = await scaffoldMigrationProject('svelte-vite-unconfigured')

fakeDepsInNodeModules(projectPath, [
{ dependency: 'svelte', version: '4.0.0' },
{ dependency: 'svelte', version: '5.0.0' },
{ dependency: 'vite', version: v },
])

Expand All @@ -182,7 +182,7 @@ describe('detectFramework', () => {
const projectPath = await scaffoldMigrationProject('svelte-webpack-unconfigured')

fakeDepsInNodeModules(projectPath, [
{ dependency: 'svelte', version: '4.0.0' },
{ dependency: 'svelte', version: '5.0.0' },
{ dependency: 'webpack', version: '5.0.0' },
])

Expand Down

This file was deleted.

16 changes: 16 additions & 0 deletions system-tests/project-fixtures/svelte/cypress/support/component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { mount } from 'cypress/svelte'
import '../../src/app.css'

// Augment the Cypress namespace to include type definitions for
// your custom command.
// Alternatively, can be defined in cypress/support/component.d.ts
// with a <reference path="./component" /> at the top of your spec.
declare global {
namespace Cypress {
interface Chainable {
mount: typeof mount
}
}
}

Cypress.Commands.add('mount', mount)
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import App from './App.svelte'

it('should render with style', () => {
cy.mount(App)
cy.mount(App, {
// logging due to @packages/app/reporter-ct-mount-hover.cy.ts tests to test the mount log
log: true,
})

cy.contains('Hello World!')
// Verify global styles
cy.get('.very-red').should('have.css', 'color', 'rgb(255, 0, 0)')
Expand Down
20 changes: 0 additions & 20 deletions system-tests/project-fixtures/svelte/src/Counter.svelte

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<script>
let count = 0
<script lang="ts">
let count: number = $state(0)
Copy link
Contributor Author

@AtofStryker AtofStryker Dec 5, 2024

Choose a reason for hiding this comment

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

most of the changes to these components are to follow the svelte migration guide

biggest differences:

  • similar to React now, is that Svelte components need to explicitly declare state or props for a given property. This is why there is Counter.svelte which uses state and CounterProp.svelte which uses a prop to set the counter.
  • Events are NOT propagated up to components by default and event dispatchers are deprecated. The recommended pattern is now to pass a callback function in as a prop and call that when the event is fired (see Changes to Component Events)

There are a few others but these are the main changes. I also converted the projects to typescript as this is the new base case

const increment = () => {
count += 1
}
</script>

<button on:click={increment}>
<button onclick={increment}>
count is {count}
</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script lang="ts">
let { count } = $props()
count = count || 0
</script>

<button>
count is {count}
</button>
8 changes: 0 additions & 8 deletions system-tests/project-fixtures/svelte/src/main.js

This file was deleted.

9 changes: 9 additions & 0 deletions system-tests/project-fixtures/svelte/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { mount } from 'svelte'
import './app.css'
import App from './App.svelte'

const app = mount(App, {
target: document.getElementById('app')!,
})

export default app
Loading
Loading