diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 000000000000..e5b6d8d6a67a --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets) + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 000000000000..b56077a9220c --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", + "changelog": ["@svitejs/changesets-changelog-github-compact", { "repo": "sveltejs/svelte" }], + "commit": false, + "fixed": [], + "linked": [], + "access": "public", + "baseBranch": "main", + "bumpVersionsWithWorkspaceProtocolOnly": true, + "ignore": ["!(@sveltejs/*|svelte)"] +} diff --git a/.editorconfig b/.editorconfig index ed2a319d5843..2f52d9993f71 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,5 @@ trim_trailing_whitespace = true [test/**/expected.css] insert_final_newline = false -[{package.json,.travis.yml,.eslintrc.json}] +[package.json] indent_style = space -indent_size = 2 diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index a0ca1e55c847..000000000000 --- a/.eslintignore +++ /dev/null @@ -1,14 +0,0 @@ -**/_actual.js -**/expected.js -test/*/samples/*/output.js -node_modules - -# output files -animate/*.js -esing/*.js -internal/*.js -motion/*.js -store/*.js -transition/*.js -index.js -compiler.js diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 722b0e906749..000000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "root": true, - "rules": { - "indent": "off", - "no-unused-vars": "off", - "semi": [2, "always"], - "keyword-spacing": [2, { "before": true, "after": true }], - "space-before-blocks": [2, "always"], - "no-mixed-spaces-and-tabs": [2, "smart-tabs"], - "no-cond-assign": 0, - "object-shorthand": [2, "always"], - "no-const-assign": 2, - "no-class-assign": 2, - "no-this-before-super": 2, - "no-var": 2, - "no-unreachable": 2, - "valid-typeof": 2, - "quote-props": [2, "as-needed"], - "one-var": [2, "never"], - "prefer-arrow-callback": 2, - "prefer-const": [2, { "destructuring": "all" }], - "arrow-spacing": 2, - "no-inner-declarations": 0, - "require-atomic-updates": "off", - "@typescript-eslint/indent": ["error", "tab", { - "SwitchCase": 1, - "ignoredNodes": ["TemplateLiteral"] - }], - "@typescript-eslint/camelcase": "off", - "@typescript-eslint/no-use-before-define": "off", - "@typescript-eslint/array-type": ["error", "array-simple"], - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/explicit-member-accessibility": "off", - "@typescript-eslint/no-unused-vars": ["error", { - "argsIgnorePattern": "^_" - }], - "@typescript-eslint/no-object-literal-type-assertion": ["error", { - "allowAsParameter": true - }], - "@typescript-eslint/no-unused-vars": "off" - }, - "globals": { - "globalThis": false - }, - "env": { - "es6": true, - "browser": true, - "node": true, - "mocha": true - }, - "extends": [ - "eslint:recommended", - "plugin:import/errors", - "plugin:import/warnings", - "plugin:import/typescript", - "plugin:@typescript-eslint/recommended" - ], - "parserOptions": { - "ecmaVersion": 9, - "sourceType": "module" - }, - "settings": { - "import/core-modules": [ - "svelte", - "svelte/internal", - "svelte/store", - "svelte/easing", - "estree" - ] - }, - "overrides": [ - { - "files": ["*.js"], - "rules": { - "@typescript-eslint/no-var-requires": "off" - } - } - ] -} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000000..a299a4435ae8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +/site/** -linguist-detectable +/test/**/samples/** -linguist-detectable +/**/*.svelte linguist-detectable diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000000..d632634540e5 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: svelte diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index e7bd60d3f410..220af118345e 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,21 +1,28 @@ - +- _Repeatable steps to reproduce the issue_ + +## Thanks for being part of Svelte! diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000000..2e484e5ca26d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,50 @@ +name: "\U0001F41E Bug report" +description: Report an issue with Svelte +labels: ['triage: bug'] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: textarea + id: bug-description + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks! + placeholder: Bug description + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Reproduction + description: Please provide a link to a repo or REPL that can reproduce the problem you ran into. If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "need reproduction" label. If no reproduction is provided within a reasonable time-frame, the issue will be closed. + placeholder: Reproduction + validations: + required: true + - type: textarea + id: logs + attributes: + label: Logs + description: 'Please include browser console and server logs around the time this bug occurred. Optional if provided reproduction. Please try not to insert an image but copy paste the log text.' + render: shell + - type: textarea + id: system-info + attributes: + label: System Info + description: Output of `npx envinfo --system --npmPackages svelte,rollup,webpack --binaries --browsers` + render: shell + placeholder: System, Binaries, Browsers + validations: + required: true + - type: dropdown + id: severity + attributes: + label: Severity + description: Select the severity of this issue + options: + - annoyance + - blocking an upgrade + - blocking all usage of svelte + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000000..ee3e5a41b982 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Discord Chat + url: https://svelte.dev/chat + about: Ask questions and discuss with other Svelte users in real time. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000000..d79e8b2e21f3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,35 @@ +name: 'Feature Request' +description: Request a new Svelte feature +labels: [enhancement] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to request this feature! If your feature request is complex or substantial enough to warrant in-depth discussion, maintainers may close the issue and ask you to open an [RFC](https://github.com/sveltejs/rfcs). + - type: textarea + id: problem + attributes: + label: Describe the problem + description: Please provide a clear and concise description the problem this feature would solve. The more information you can provide here, the better. + placeholder: I'm always frustrated when... + validations: + required: true + - type: textarea + id: solution + attributes: + label: Describe the proposed solution + description: Please provide a clear and concise description of what you would like to happen. + placeholder: I would like to see... + validations: + required: true + - type: dropdown + id: importance + attributes: + label: Importance + description: How important is this feature to you? + options: + - nice to have + - would make my life easier + - i cannot use svelte without it + validations: + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d2882acf4ac2..aa5f9732b6d3 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,7 +1,11 @@ - +- [ ] It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs +- [ ] Prefix your PR title with `feat:`, `fix:`, `chore:`, or `docs:`. +- [ ] This message body should clearly illustrate what problems it solves. +- [ ] Ideally, include a test that fails without this PR but passes with it. +- [ ] If this PR changes code within `packages/svelte/src`, add a changeset (`npx changeset`). + +### Tests and linting + +- [ ] Run the tests with `pnpm test` and lint the project with `pnpm lint` diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000000..cf73a1f6cb02 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,79 @@ +name: CI +on: + push: + branches: [main] + pull_request: +permissions: + contents: read # to fetch code (actions/checkout) + +env: + # We only install Chromium manually + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' + +jobs: + Tests: + permissions: {} + runs-on: ${{ matrix.os }} + timeout-minutes: 15 + strategy: + matrix: + include: + - node-version: 18 + os: windows-latest + - node-version: 18 + os: macOS-latest + - node-version: 18 + os: ubuntu-latest + - node-version: 20 + os: ubuntu-latest + - node-version: 22 + os: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm playwright install chromium + - run: pnpm test + env: + CI: true + Lint: + permissions: {} + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + cache: pnpm + - name: install + run: pnpm install --frozen-lockfile + - name: type check + run: pnpm check + - name: lint + if: (${{ success() }} || ${{ failure() }}) # ensures this step runs even if previous steps fail (avoids multiple runs uncovering different issues at different steps) + run: pnpm lint + - name: build and check generated types + if: (${{ success() }} || ${{ failure() }}) # ensures this step runs even if previous steps fail + run: pnpm build && { [ "`git status --porcelain=v1`" == "" ] || (echo "Generated types have changed — please regenerate types locally with `cd packages/svelte && pnpm generate:types` and commit the changes after you have reviewed them"; git diff; exit 1); } + Benchmarks: + permissions: {} + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm bench + env: + CI: true diff --git a/.github/workflows/ecosystem-ci-trigger.yml b/.github/workflows/ecosystem-ci-trigger.yml new file mode 100644 index 000000000000..71df3242e8f1 --- /dev/null +++ b/.github/workflows/ecosystem-ci-trigger.yml @@ -0,0 +1,94 @@ +name: ecosystem-ci trigger + +on: + issue_comment: + types: [created] + +jobs: + trigger: + runs-on: ubuntu-latest + if: github.repository == 'sveltejs/svelte' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run') + steps: + - uses: GitHubSecurityLab/actions-permissions/monitor@v1 + - uses: actions/github-script@v6 + with: + script: | + const user = context.payload.sender.login + console.log(`Validate user: ${user}`) + + let hasTriagePermission = false + try { + const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: user, + }); + hasTriagePermission = data.user.permissions.triage + } catch (e) { + console.warn(e) + } + + if (hasTriagePermission) { + console.log('Allowed') + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: '+1', + }) + } else { + console.log('Not allowed') + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: '-1', + }) + throw new Error('not allowed') + } + - uses: actions/github-script@v6 + id: get-pr-data + with: + script: | + console.log(`Get PR info: ${context.repo.owner}/${context.repo.repo}#${context.issue.number}`) + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }) + return { + num: context.issue.number, + branchName: pr.head.ref, + repo: pr.head.repo.full_name + } + - id: generate-token + uses: tibdex/github-app-token@b62528385c34dbc9f38e5f4225ac829252d1ea92 #keep pinned for security reasons, currently 1.8.0 + with: + app_id: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_ID }} + private_key: ${{ secrets.ECOSYSTEM_CI_GITHUB_APP_PRIVATE_KEY }} + repository: '${{ github.repository_owner }}/svelte-ecosystem-ci' + - uses: actions/github-script@v6 + id: trigger + env: + COMMENT: ${{ github.event.comment.body }} + with: + github-token: ${{ steps.generate-token.outputs.token }} + result-encoding: string + script: | + const comment = process.env.COMMENT.trim() + const prData = ${{ steps.get-pr-data.outputs.result }} + + const suite = comment.split('\n')[0].replace(/^\/ecosystem-ci run/, '').trim() + + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: 'svelte-ecosystem-ci', + workflow_id: 'ecosystem-ci-from-pr.yml', + ref: 'main', + inputs: { + prNumber: '' + prData.num, + branchName: prData.branchName, + repo: prData.repo, + suite: suite === '' ? '-' : suite + } + }) diff --git a/.github/workflows/pkg.pr.new-comment.yml b/.github/workflows/pkg.pr.new-comment.yml new file mode 100644 index 000000000000..3f1fca5a0bea --- /dev/null +++ b/.github/workflows/pkg.pr.new-comment.yml @@ -0,0 +1,116 @@ +name: Update pkg.pr.new comment + +on: + workflow_run: + workflows: ['Publish Any Commit'] + types: + - completed + +permissions: + pull-requests: write + +jobs: + build: + name: 'Update comment' + runs-on: ubuntu-latest + steps: + - uses: GitHubSecurityLab/actions-permissions/monitor@v1 + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: output + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + + - run: ls -R . + - name: 'Post or update comment' + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const output = JSON.parse(fs.readFileSync('output.json', 'utf8')); + + const bot_comment_identifier = ``; + + const body = (number) => `${bot_comment_identifier} + + [Playground](https://svelte.dev/playground?version=pr-${number}) + + \`\`\` + ${output.packages.map((p) => `pnpm add https://pkg.pr.new/${p.name}@${number}`).join('\n')} + \`\`\` + `; + + async function find_bot_comment(issue_number) { + if (!issue_number) return null; + const comments = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue_number, + }); + return comments.data.find((comment) => + comment.body.includes(bot_comment_identifier) + ); + } + + async function create_or_update_comment(issue_number) { + if (!issue_number) { + console.log('No issue number provided. Cannot post or update comment.'); + return; + } + + const existing_comment = await find_bot_comment(issue_number); + if (existing_comment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing_comment.id, + body: body(issue_number), + }); + } else { + await github.rest.issues.createComment({ + issue_number: issue_number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body(issue_number), + }); + } + } + + async function log_publish_info() { + const svelte_package = output.packages.find(p => p.name === 'svelte'); + const svelte_sha = svelte_package.url.replace(/^.+@([^@]+)$/, '$1'); + console.log('\n' + '='.repeat(50)); + console.log('Publish Information'); + console.log('='.repeat(50)); + console.log('\nPublished Packages:'); + console.log(output.packages.map((p) => `${p.name} - pnpm add https://pkg.pr.new/${p.name}@${p.url.replace(/^.+@([^@]+)$/, '$1')}`).join('\n')); + if(svelte_sha){ + console.log('\nPlayground URL:'); + console.log(`\nhttps://svelte.dev/playground?version=commit-${svelte_sha}`) + } + console.log('\n' + '='.repeat(50)); + } + + if (output.event_name === 'pull_request') { + if (output.number) { + await create_or_update_comment(output.number); + } + } else if (output.event_name === 'push') { + const pull_requests = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + head: `${context.repo.owner}:${output.ref.replace('refs/heads/', '')}`, + }); + + if (pull_requests.data.length > 0) { + await create_or_update_comment(pull_requests.data[0].number); + } else { + console.log( + 'No open pull request found for this push. Logging publish information to console:' + ); + await log_publish_info(); + } + } diff --git a/.github/workflows/pkg.pr.new.yml b/.github/workflows/pkg.pr.new.yml new file mode 100644 index 000000000000..90d219faae6a --- /dev/null +++ b/.github/workflows/pkg.pr.new.yml @@ -0,0 +1,47 @@ +name: Publish Any Commit +on: [push, pull_request] + +jobs: + build: + permissions: {} + + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: install corepack + run: npm i -g corepack@0.31.0 + + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 18.x + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build + + - run: pnpx pkg-pr-new publish --comment=off --json output.json --compact --no-template './packages/svelte' + - name: Add metadata to output + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const output = JSON.parse(fs.readFileSync('output.json', 'utf8')); + output.number = context.issue.number; + output.event_name = context.eventName; + output.ref = context.ref; + fs.writeFileSync('output.json', JSON.stringify(output), 'utf8'); + - name: Upload output + uses: actions/upload-artifact@v4 + with: + name: output + path: ./output.json + + - run: ls -R . diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000000..6debe5662a88 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,48 @@ +name: Release + +on: + push: + branches: + - main + +permissions: {} +jobs: + release: + # prevents this action from running on forks + if: github.repository == 'sveltejs/svelte' + permissions: + contents: write # to create release (changesets/action) + id-token: write # OpenID Connect token needed for provenance + pull-requests: write # to create pull request (changesets/action) + name: Release + runs-on: ubuntu-latest + steps: + - uses: GitHubSecurityLab/actions-permissions/monitor@v1 + - name: Checkout Repo + uses: actions/checkout@v4 + with: + # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits + fetch-depth: 0 + - uses: pnpm/action-setup@v4 + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 18.x + cache: pnpm + + - name: Install + run: pnpm install --frozen-lockfile + + - name: Build + run: pnpm build && { [ "`git status --porcelain=v1`" == "" ] || (echo "Generated types have changed — please regenerate types locally with `cd packages/svelte && pnpm generate:types` and commit the changes after you have reviewed them"; git diff; exit 1); } + + - name: Create Release Pull Request or Publish to npm + id: changesets + uses: changesets/action@v1 + with: + version: pnpm changeset:version + publish: pnpm changeset:publish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_CONFIG_PROVENANCE: true + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 590bd1d88e01..d50343766485 100644 --- a/.gitignore +++ b/.gitignore @@ -1,35 +1,26 @@ +# Dependency directories +node_modules/ + +# IDE related .idea + +# Test coverage +coverage +*.lcov + +# Optional eslint cache +.eslintcache + +# dotenv environment variables file +.env +.env.test + +# build output +.vercel + +# OS-specific .DS_Store -.nyc_output -node_modules -*.map -/src/compiler/compile/internal_exports.ts -/compiler.d.ts -/compiler.*js -/index.*js -/internal -/store -/easing -/motion -/transition -/animate -/scratch/ -/coverage/ -/coverage.lcov/ -/test/sourcemaps/samples/*/output.js -/test/sourcemaps/samples/*/output.js.map -/test/sourcemaps/samples/*/output.css -/test/sourcemaps/samples/*/output.css.map -/yarn-error.log -_actual*.* -/types - -/site/cypress/screenshots/ -/site/__sapper__/ -/site/.env -/site/.sessions -/site/static/svelte-app.json -/site/static/contributors.jpg -/site/static/workers -/site/scripts/svelte-app -/site/src/routes/_contributors.js + +tmp + +benchmarking/compare/.results diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000000..33484750d05a --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +playwright_skip_browser_download=1 \ No newline at end of file diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000000..d5c124353c37 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,47 @@ +documentation/docs/ + +packages/**/dist/*.js +packages/**/build/*.js +packages/**/npm/**/* +packages/**/config/*.js + +# packages/svelte +packages/svelte/messages/**/*.md +packages/svelte/src/compiler/errors.js +packages/svelte/src/compiler/warnings.js +packages/svelte/src/internal/client/errors.js +packages/svelte/src/internal/client/warnings.js +packages/svelte/src/internal/shared/errors.js +packages/svelte/src/internal/shared/warnings.js +packages/svelte/src/internal/server/errors.js +packages/svelte/tests/migrate/samples/*/output.svelte +packages/svelte/tests/**/*.svelte +packages/svelte/tests/**/_expected* +packages/svelte/tests/**/_actual* +packages/svelte/tests/**/expected* +packages/svelte/tests/**/_output +packages/svelte/tests/**/shards/*.test.js +packages/svelte/tests/hydration/samples/*/_expected.html +packages/svelte/tests/hydration/samples/*/_override.html +packages/svelte/types +packages/svelte/compiler/index.js +playgrounds/sandbox/input/**.svelte +playgrounds/sandbox/output + +# sites/svelte.dev +sites/svelte.dev/static/svelte-app.json +sites/svelte.dev/scripts/svelte-app/ +sites/svelte.dev/src/routes/_components/Supporters/contributors.jpg +sites/svelte.dev/src/routes/_components/Supporters/contributors.js +sites/svelte.dev/src/routes/_components/Supporters/donors.jpg +sites/svelte.dev/src/routes/_components/Supporters/donors.js +sites/svelte.dev/src/lib/generated + +**/node_modules +**/.svelte-kit +**/.vercel +.github/CODEOWNERS +.prettierignore +.changeset +pnpm-lock.yaml +pnpm-workspace.yaml diff --git a/.prettierrc b/.prettierrc index 81451039faf5..c4fd5d9f2f73 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,28 @@ -useTabs: true -singleQuote: true -trailingComma: es5 +{ + "useTabs": true, + "singleQuote": true, + "trailingComma": "none", + "printWidth": 100, + "plugins": ["prettier-plugin-svelte"], + "overrides": [ + { + "files": ["*.svelte"], + "options": { + "bracketSameLine": false + } + }, + { + "files": ["README.md", "packages/*/README.md", "**/package.json"], + "options": { + "useTabs": false, + "tabWidth": 2 + } + }, + { + "files": ["sites/svelte-5-preview/src/routes/docs/content/**/*.md"], + "options": { + "printWidth": 60 + } + } + ] +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a4603a26e2cc..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: node_js -node_js: - - "8" - - "10" - - "12" -env: - global: - - BUILD_TIMEOUT=20000 - -addons: - apt: - packages: - - xvfb - -install: - - export DISPLAY=':99.0' - - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & - - npm ci || npm install - -after_success: npm run codecov diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000000..142965ada292 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Run sandbox", + "program": "${workspaceFolder}/playgrounds/sandbox/run.js", + "env": { + "NODE_OPTIONS": "--stack-trace-limit=10000" + } + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000000..21a2a11c84e3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "search.exclude": { + "sites/svelte-5-preview/static/*": true + }, + "typescript.tsdk": "node_modules/typescript/lib" +} diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 340ef8c17633..000000000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,1568 +0,0 @@ -# Svelte changelog - -## 3.6.4 - -* Run `onMount` functions in correct order, and before initial `afterUpdate` functions ([#2281](https://github.com/sveltejs/svelte/issues/2281)) -* Fix code transformation for shorthand methods ([#2906](https://github.com/sveltejs/svelte/issues/2906)) -* Fix assignments in inline functions ([#3038](https://github.com/sveltejs/svelte/issues/3038)) - -## 3.6.3 - -* Fix await block mounting inside removed if block ([#1496](https://github.com/sveltejs/svelte/issues/1496)) -* Update when element references are removed ([#2034](https://github.com/sveltejs/svelte/issues/2034)) -* Don't attempt to serialize non-string values in server-rendered bindings ([#2135](https://github.com/sveltejs/svelte/issues/2135)) -* Recognise dependencies in function expressions ([#2693](https://github.com/sveltejs/svelte/issues/2693)) -* Scope pseudo-class selectors without class/type ([#1705](https://github.com/sveltejs/svelte/issues/1705)) -* Allow nested at-rules ([#3135](https://github.com/sveltejs/svelte/issues/3135)) -* Allow attributes to contain `=` characters ([#3149](https://github.com/sveltejs/svelte/pull/3149)) - -## 3.6.2 - -* Fix placement of each-else block ([#2917](https://github.com/sveltejs/svelte/issues/2917)) -* Make context accessible to `bind:this` ([#2806](https://github.com/sveltejs/svelte/issues/2806)) -* Pass hoisted values to slots ([#2586](https://github.com/sveltejs/svelte/issues/2586)) - -## 3.6.1 - -* Fix escaping of `@` in dev mode debug filename ([#3114](https://github.com/sveltejs/svelte/pull/3114)) - -## 3.6.0 - -* Add `innerHTML` and `textContent` bindings for `contenteditable` elements ([#2996](https://github.com/sveltejs/svelte/pull/2996)) -* Fix destructuring assignments where targets are member expressions ([#3092](https://github.com/sveltejs/svelte/issues/3092)) -* Deconflict with used globals ([#2963](https://github.com/sveltejs/svelte/pull/2963)) -* Always run `onDestroy` functions, not just for detaching components ([#3058](https://github.com/sveltejs/svelte/issues/3058)) -* Fix scope analysis around catch clauses ([#3064](https://github.com/sveltejs/svelte/issues/3064)) -* Add error constructors to known globals ([#3064](https://github.com/sveltejs/svelte/issues/3064)) -* Always bail out of hoisting on encountering local state in function definition ([#3044](https://github.com/sveltejs/svelte/issues/3044)) -* Fix incorrect merging of top-level text nodes ([#3027](https://github.com/sveltejs/svelte/issues/3027)) -* Handle removal of components in each blocks without props ([#3035](https://github.com/sveltejs/svelte/issues/3035)) -* Only call subscriber once when resubscribing to a store ([#3022](https://github.com/sveltejs/svelte/issues/3022)) -* Check for existence of dynamic component before introing ([#3054](https://github.com/sveltejs/svelte/issues/3054)) -* Sanitize names of bubbled event handlers ([#2923](https://github.com/sveltejs/svelte/issues/2923)) - - -## 3.5.4 - -* Preserve whitespace at the boundaries of `{#each}` blocks ([#713](https://github.com/sveltejs/svelte/issues/713)) -* Fix dynamic `bind:this` on components ([#2333](https://github.com/sveltejs/svelte/issues/2333)) -* Fix binding to values in a component when it uses `$$props` ([#2725](https://github.com/sveltejs/svelte/issues/2725)) -* Fix parsing ambiguous HTML entities ([#3071](https://github.com/sveltejs/svelte/pull/3071)) - -## 3.5.3 - -* Don't double-destroy keyed each blocks with outros ([#3055](https://github.com/sveltejs/svelte/issues/3055)) - -## 3.5.2 - -* Prevent duplicated outros causing errors ([#3001](https://github.com/sveltejs/svelte/issues/3001)) -* Fix automatic name generation ([#2843](https://github.com/sveltejs/svelte/issues/2843)) -* Fix .d.ts stubs ([#3009](https://github.com/sveltejs/svelte/pull/3009)) -* Don't strip non-breaking spaces ([#3014](https://github.com/sveltejs/svelte/issues/3014)) -* Fix `requestAnimationFrame` context ([#2933](https://github.com/sveltejs/svelte/issues/2933)) -* Allow space before attribute value ([#3026](https://github.com/sveltejs/svelte/issues/3026)) -* Remove null/undefined attributes ([#1434](https://github.com/sveltejs/svelte/issues/1434)) -* Fix whitespace in static markup ([#3030](https://github.com/sveltejs/svelte/pull/3030)) - -## 3.5.1 - -* Accommodate webpack idiosyncracies - -## 3.5.0 - -* Update package folder structure ([#2887](https://github.com/sveltejs/svelte/pull/2887)) -* Support `once` modifier on component events ([#2654](https://github.com/sveltejs/svelte/issues/2654)) -* Allow empty `` tags ([#2980](https://github.com/sveltejs/svelte/issues/2980)) -* Render textarea binding values inside element ([#2975](https://github.com/sveltejs/svelte/pull/2975)) -* Fix delayed animation glitch ([#2871](https://github.com/sveltejs/svelte/issues/2871)) -* Solve diamond dependencies problem with stores ([#2660](https://github.com/sveltejs/svelte/issues/2660)) -* Fix missing outros inside each blocks ([#2689](https://github.com/sveltejs/svelte/issues/2689)) -* Support animations without transitions ([#2908](https://github.com/sveltejs/svelte/issues/2908)) -* Add missing transition events ([#2912](https://github.com/sveltejs/svelte/pull/2912)) - - -## 3.4.4 - -* Publish type declaration files ([#2874](https://github.com/sveltejs/svelte/issues/2874)) -* Don't trigger updates for unreferenced values ([#2865](https://github.com/sveltejs/svelte/pull/2865)) -* Omit readonly bindings from SSR output ([#2339](https://github.com/sveltejs/svelte/issues/2339)) -* Prevent outdated animation CSS ([#2871](https://github.com/sveltejs/svelte/issues/2871)) -* Repair dynamic `{@html ...}` in head ([#2880](https://github.com/sveltejs/svelte/pull/2880)) -* Don't create unknown prop warnings for internal props, or if component has `$$props` ([#2881](https://github.com/sveltejs/svelte/pull/2881)) - - -## 3.4.3 - -* Add type declaration files for everything ([#2842](https://github.com/sveltejs/svelte/pull/2842)) -* Prevent `svelte/store` being bundled ([#2786](https://github.com/sveltejs/svelte/issues/2786)) -* Warn on unknown props in dev mode ([#2840](https://github.com/sveltejs/svelte/pull/2840)) -* Treat `requestAnimationFrame` as a no-op on the server ([#2856](https://github.com/sveltejs/svelte/pull/2856)) -* Add `raw` property to AST's `Text` nodes ([#2714](https://github.com/sveltejs/svelte/issues/2714)) -* Add `<details bind:open>` ([#2854](https://github.com/sveltejs/svelte/issues/2854)) - -## 3.4.2 - -* Use empty string for empty data attributes ([#2804](https://github.com/sveltejs/svelte/pull/2804)) -* Support `customElement: true` with no `<svelte:options>` ([#2821](https://github.com/sveltejs/svelte/issues/2821)) -* Add docstrings to `svelte/store` ([#2795](https://github.com/sveltejs/svelte/pull/2795)) - -## 3.4.1 - -* Handle non-falsy non-function return values from derivers ([#2780](https://github.com/sveltejs/svelte/issues/2780)) -* Allow `spring` to work server-side ([#2773](https://github.com/sveltejs/svelte/issues/2773)) - -## 3.4.0 - -* Allow custom element to be defined without a `tag` ([#2417](https://github.com/sveltejs/svelte/issues/2417)) -* Fix parsing of quote marks inside attribute values ([#2715](https://github.com/sveltejs/svelte/pull/2754)) -* Convert `svelte/store` to TypeScript ([#2733](https://github.com/sveltejs/svelte/pull/2733)) -* Allow `debug` tags to include hoisted values ([#2764](https://github.com/sveltejs/svelte/issues/2764)) -* Parse error if attribute name is missing `=` ([#1513](https://github.com/sveltejs/svelte/pull/2770)) -* Allow reactive declarations to depend on mutated `const` values ([#2728](https://github.com/sveltejs/svelte/issues/2728)) - -## 3.3.0 - -* Allow multiple event listeners on a single node ([#2688](https://github.com/sveltejs/svelte/issues/2688)) -* Allow derivers to return a cleanup function ([#2553](https://github.com/sveltejs/svelte/issues/2553)) -* Support namespaced components (`<Foo.Bar/>`) ([#2743](https://github.com/sveltejs/svelte/pull/2743)) - -## 3.2.2 - -* Add `window` and `document` to expected globals ([#2722](https://github.com/sveltejs/svelte/pull/2722)) -* Prevent hoisting of functions that depend on reactive state ([#2703](https://github.com/sveltejs/svelte/pull/2703)) -* Generate correct code when slot has no changes ([#2697](https://github.com/sveltejs/svelte/issues/2697)) -* Prevent `Object.prototype`-related bugs ([#2696](https://github.com/sveltejs/svelte/pull/2696)) - -## 3.2.1 - -* Use same comparison logic for `derived` as for other stores ([#2644](https://github.com/sveltejs/svelte/issues/2644)) -* Invalidate dependencies of reactive declarations ([#2444](https://github.com/sveltejs/svelte/issues/2444)) -* Fix instrumentation of auto-subscription self-assignments ([#2681](https://github.com/sveltejs/svelte/issues/2681)) -* Warn on non-top-level or module-context statements labeled with `$:` ([#2176](https://github.com/sveltejs/svelte/issues/2176)) - -## 3.2.0 - -* Improve `spring` animations, and add `hard`/`soft` options ([#2627](https://github.com/sveltejs/svelte/pull/2627)) -* Expose `parse` and `walk` functions ([#2661](https://github.com/sveltejs/svelte/issues/2661), [#2534](https://github.com/sveltejs/svelte/pull/2534)) -* Support array/object rest in `each` block destructuring patterns ([#2647](https://github.com/sveltejs/svelte/issues/2647), [#2658](https://github.com/sveltejs/svelte/pull/2658)) -* Use `setAttribute` to change `form` property on form elements ([#1742](https://github.com/sveltejs/svelte/issues/1742)) -* Fix a11y warning when `<figcaption>` is non-direct descendant of `<figure>` ([#2582](https://github.com/sveltejs/svelte/issues/2582)) -* Squelch erroneous 'empty block' warnings ([#1716](https://github.com/sveltejs/svelte/issues/1716)) -* Fix IE9/10 error with `insertBefore` ([#2573](https://github.com/sveltejs/svelte/issues/2573)) -* Prevent `$$scope` from being spread onto an element ([#2520](https://github.com/sveltejs/svelte/issues/2520)) -* Resubscribe to stores that are assigned to in `<script>` ([#2435](https://github.com/sveltejs/svelte/issues/2435)) -* Allow reactive declarations to depend on `const` variables ([#2285](https://github.com/sveltejs/svelte/issues/2285)) -* Trigger store changes on UpdateExpression ([#2625](https://github.com/sveltejs/svelte/issues/2625)) -* Squelch missing prop warning if variable is initialised ([#2635](https://github.com/sveltejs/svelte/issues/2635)) -* Add `alert`, `confirm` and `prompt` to known globals ([#2648](https://github.com/sveltejs/svelte/issues/2648)) - - -## 3.1.0 - -* Allow store subscribe functions to return an object with an `unsubscribe` method, providing native RxJS support ([#2549](https://github.com/sveltejs/svelte/issues/2549)) - -## 3.0.1 - -* Prevent text input cursor jumping in Safari ([#2506](https://github.com/sveltejs/svelte/issues/2506)) -* Allow assignments to member expressions ([#2510](https://github.com/sveltejs/svelte/issues/2510)) -* Prevent mutually dependent functions causing an infinite during hoisting ([#2542](https://github.com/sveltejs/svelte/issues/2542)) -* Reuse scheduler promise instead of creating new one each time ([#2555](https://github.com/sveltejs/svelte/pull/2555)) -* Various site/docs fixes - -## 3.0.0 - -* Everything - -## 2.15.4 - -* IE `classList` fix ([#1868](https://github.com/sveltejs/svelte/pull/1868)) - -## 2.15.3 - -* Don't mutate AST - -## 2.15.2 - -* Expose `stats.props` ([#1837](https://github.com/sveltejs/svelte/issues/1837)) - -## 2.15.1 - -* Don't throw missing store error when store is declared in component ([#1828](https://github.com/sveltejs/svelte/issues/1828)) - -## 2.15.0 - -* Event modifiers ([#1088](https://github.com/sveltejs/svelte/issues/1088)) -* Wheel and touch events are passive by default ([#1088](https://github.com/sveltejs/svelte/issues/1088)) -* Add `<svelte:document>` tag ([#1484](https://github.com/sveltejs/svelte/issues/1484)) -* Include binding values in server-rendered HTML ([#1205](https://github.com/sveltejs/svelte/issues/1205)) -* Remove attributes when value is undefined/null ([#1434](https://github.com/sveltejs/svelte/issues/1434)) -* Initialise window scroll from component data ([#938](https://github.com/sveltejs/svelte/issues/938)) -* Remove references to unused properties in generated code ([#1187](https://github.com/sveltejs/svelte/issues/1187)) -* Add TypeScript definitions for store ([#1207](https://github.com/sveltejs/svelte/issues/1207)) -* Better error for missing store ([#1807](https://github.com/sveltejs/svelte/issues/1807)) - -## 2.14.3 - -* Account for directive dependencies ([#1793](https://github.com/sveltejs/svelte/issues/1793)) -* Detach each block iterations in each blocks with no update method ([#1795](https://github.com/sveltejs/svelte/issues/1795)) - -## 2.14.2 - -* Fix issue with nested `{#if}` blocks ([#1780](https://github.com/sveltejs/svelte/issues/1780)) - -## 2.14.1 - -* Fix block insertion order regression ([#1778](https://github.com/sveltejs/svelte/issues/1778)) -* Fix blocks inside `<svelte:head>` ([#1774](https://github.com/sveltejs/svelte/issues/1774)) -* Better attribute parsing ([#1772](https://github.com/sveltejs/svelte/issues/1772)) -* Fix parse errors inside directives ([#1788](https://github.com/sveltejs/svelte/issues/1788)) - - -## 2.14.0 - -* Refactor internals ([#1678](https://github.com/sveltejs/svelte/issues/1678)) -* Deprecate `onerror` option ([#1745](https://github.com/sveltejs/svelte/issues/1745)) -* Handle edge cases where `destroy` is called before `mount` ([#1653](https://github.com/sveltejs/svelte/pull/1653)) -* Make `scroll` binding more efficient ([#1579](https://github.com/sveltejs/svelte/pull/1770)) -* Make 'readonly property' store error more informative ([#1761](https://github.com/sveltejs/svelte/pull/1761)) - -## 2.13.5 - -* Fix missing dependencies in shorthand class directives ([#1739](https://github.com/sveltejs/svelte/issues/1739)) - -## 2.13.4 - -* Support dynamic `import()` in template expressions - -## 2.13.3 - -* Fix bug with keyed each blocks and nested components ([#1706](https://github.com/sveltejs/svelte/issues/1706)) - -## 2.13.2 - -* Coalesce simultaneous store/component updates ([#1520](https://github.com/sveltejs/svelte/issues/1520)) -* Fix nested transitions preventing each block item removal ([#1617](https://github.com/sveltejs/svelte/issues/1617)) -* Add `class` directive shorthand and encapsulate styles ([#1695](https://github.com/sveltejs/svelte/pull/1695)) -* Prevent erroneous updates of bound inputs ([#1699](https://github.com/sveltejs/svelte/issues/1699)) - -## 2.13.1 - -* Coerce second argument to `toggleClass` ([#1685](https://github.com/sveltejs/svelte/issues/1685)) - -## 2.13.0 - -* Add `class` directive ([#890](https://github.com/sveltejs/svelte/issues/890)) -* Remove sourcemaps from npm package ([#1690](https://github.com/sveltejs/svelte/pull/1690)) - -## 2.12.1 - -* Allow actions to take any expression ([#1676](https://github.com/sveltejs/svelte/issues/1676)) -* Run transitions in component context ([#1675](https://github.com/sveltejs/svelte/issues/1675)) -* Correctly set select value on mount ([#1666](https://github.com/sveltejs/svelte/issues/1666)) -* Support `{@debug}` in SSR ([#1659](https://github.com/sveltejs/svelte/issues/1659)) -* Don't treat ` ` as empty whitespace ([#1658](https://github.com/sveltejs/svelte/issues/1658)) -* Fix outros for if blocks with no else ([#1688](https://github.com/sveltejs/svelte/pull/1688)) -* Set `style.cssText` in spread attributes ([#1684](https://github.com/sveltejs/svelte/pull/1684)) - - -## 2.12.0 - -* Initialise actions on mount rather than hydrate ([#1653](https://github.com/sveltejs/svelte/pull/1653)) -* Allow non-existent components to be destroyed ([#1677](https://github.com/sveltejs/svelte/pull/1677)) -* Pass AMD ID from CLI correctly ([#1672](https://github.com/sveltejs/svelte/pull/1672)) -* Minor AST tweaks ([#1673](https://github.com/sveltejs/svelte/pull/1673), [#1674](https://github.com/sveltejs/svelte/pull/1674)) -* Reduce code duplication in component initialisation ([#1670](https://github.com/sveltejs/svelte/pull/1670)) - - -## 2.11.0 - -* Add `--shared` CLI option ([#1649](https://github.com/sveltejs/svelte/pull/1649)) -* Run first `onstate` *before* fragment is rendered ([#1522](https://github.com/sveltejs/svelte/issues/1522)) -* Exclude current computed prop from state object ([#1544](https://github.com/sveltejs/svelte/issues/1544)) - - -## 2.10.1 - -* Add sourcemaps to `{@debug}` tags ([#1647](https://github.com/sveltejs/svelte/pull/1647)) - -## 2.10.0 - -* Add a `{@debug}` tag, for inspecting values in templates in dev mode ([#1635](https://github.com/sveltejs/svelte/issues/1635)) -* Fix dimension bindings in iOS ([#1642](https://github.com/sveltejs/svelte/pull/1642)) - -## 2.9.11 - -* Pass props to custom elements rather than setting attributes, where appropriate ([#875](https://github.com/sveltejs/svelte/issues/875)) -* Handle whitespace in lists consistently between SSR and DOM renderers ([#1637](https://github.com/sveltejs/svelte/pull/1637)) -* Improve error for invalid `ref` names ([#1613](https://github.com/sveltejs/svelte/issues/1613)) - -## 2.9.10 - -* Handle `null` consistently in tags ([#1598](https://github.com/sveltejs/svelte/issues/1598)) -* Support object rest in computed properties ([#1540](https://github.com/sveltejs/svelte/issues/1540)) -* Always update dynamic components when expression changes ([#1621](https://github.com/sveltejs/svelte/issues/1621)) -* Encapsulate local styles inside global styles ([#1618](https://github.com/sveltejs/svelte/issues/1618)) - -## 2.9.9 - -* Fix attribute name regex ([#1623](https://github.com/sveltejs/svelte/pull/1623)) - -## 2.9.8 - -* Sanitize spread attributes in SSR — fixes vulnerability CVE-2018-6341 ([#1623](https://github.com/sveltejs/svelte/pull/1623)) - -## 2.9.7 - -* Allow `<input type=file bind:files>` ([#1608](https://github.com/sveltejs/svelte/issues/1608)) -* Ensure child window exists before removing listener in `addResizeHandler` ([#1600](https://github.com/sveltejs/svelte/issues/1600)) -* Handle transitions in `else` block ([#1589](https://github.com/sveltejs/svelte/issues/1589)) - -## 2.9.6 - -* Provide more useful error if SSR component attempts to render non-SSR component ([#1605](https://github.com/sveltejs/svelte/issues/1605)) - -## 2.9.5 - -* Null out refs to dynamic components ([#1596](https://github.com/sveltejs/svelte/issues/1596)) - -## 2.9.4 - -* Make identifier optional for `then` and `catch` blocks ([#1507](https://github.com/sveltejs/svelte/issues/1507)) -* Group outros correctly ([#1575](https://github.com/sveltejs/svelte/issues/1575)) - -## 2.9.3 - -* Fix bug when an each block contains transitions but its else branch does not ([#1559](https://github.com/sveltejs/svelte/issues/1559)) -* If an event handler throws an exception, don't block all future calls to that handler ([#1573](https://github.com/sveltejs/svelte/issues/1573)) - -## 2.9.2 - -* Fix conflict when using multiple if-else blocks, some of which use outros and some of which do not ([#1580](https://github.com/sveltejs/svelte/issues/1580)) -* Fix some cases where `.innerHTML` was being used to create child elements when it shouldn't ([#1581](https://github.com/sveltejs/svelte/issues/1581)) - -## 2.9.1 - -* Use `template.content` instead of `template` where appropriate ([#1571](https://github.com/sveltejs/svelte/issues/1571)) - -## 2.9.0 - -* Play outro transitions on `<svelte:component>` if `nestedTransitions` is true ([#1568](https://github.com/sveltejs/svelte/issues/1568)) -* Allow illegal identifiers to be component prop names, for e.g. spreading `data-foo` props ([#887](https://github.com/sveltejs/svelte/issues/887)) -* Abort transition when node is detached ([#1561](https://github.com/sveltejs/svelte/issues/1561)) -* Only include `transitionManager` when necessary ([#1514](https://github.com/sveltejs/svelte/issues/1514)) - -## 2.8.1 - -* Fix prefixed animation name replacement ([#1556](https://github.com/sveltejs/svelte/pull/1556)) - -## 2.8.0 - -* Correctly set store on nested components (to parent store, not root store) ([#1538](https://github.com/sveltejs/svelte/issues/1538)) - -## 2.7.2 - -* Prevent unnecessary remounts ([#1527](https://github.com/sveltejs/svelte/issues/1527)) -* Allow `refs.*` as callee ([#1526](https://github.com/sveltejs/svelte/pull/1526)) -* Handle empty lists when outroing ([#1532](https://github.com/sveltejs/svelte/issues/1532)) - -## 2.7.1 - -* Fix spread props with multiple dependencies ([#1515](https://github.com/sveltejs/svelte/issues/1515)) - -## 2.7.0 - -* Add `__svelte_meta` object to elements in dev mode, containing source info ([#1499](https://github.com/sveltejs/svelte/issues/1499)) -* Fix `bind:online` in dev mode ([#1502](https://github.com/sveltejs/svelte/issues/1502)) -* Update v1 warnings/errors ([#1508](https://github.com/sveltejs/svelte/pull/1508)) -* Transform prefixed keyframes ([#1504](https://github.com/sveltejs/svelte/issues/1504)) - -## 2.6.6 - -* Fix nested transition bug ([#1497](https://github.com/sveltejs/svelte/issues/1497)) - -## 2.6.5 - -* Handle cases where only some `if` block branches have outros ([#1492](https://github.com/sveltejs/svelte/issues/1492)) - -## 2.6.4 - -* Web worker support ([#1487](https://github.com/sveltejs/svelte/issues/1487)) -* Update dynamic component bindings when component changes ([#1489](https://github.com/sveltejs/svelte/issues/1489)) - -## 2.6.3 - -* Nested transitions respect `skipIntroByDefault` ([#1460](https://github.com/sveltejs/svelte/issues/1460)) -* Always create outro for top-level block ([#1470](https://github.com/sveltejs/svelte/issues/1470)) - -## 2.6.2 - -* Fix spread+bindings on dynamic components ([#1433](https://github.com/sveltejs/svelte/issues/1433)) -* Abort in-progress animations, if a new one starts ([#1458](https://github.com/sveltejs/svelte/issues/1458)) -* Allow animations to be parameterised ([#1462](https://github.com/sveltejs/svelte/issues/1462)) - -## 2.6.1 - -* Absolutely position outroing animated nodes ([#1457](https://github.com/sveltejs/svelte/pull/1457)) - -## 2.6.0 - -* Add `animate` directive ([#1454](https://github.com/sveltejs/svelte/pull/1454)) -* Add `skipIntroByDefault` compiler option and `intro: true` init option ([#1448](https://github.com/sveltejs/svelte/pull/1448)) -* Add `nestedTransitions` compiler option ([#1451](https://github.com/sveltejs/svelte/pull/1451)) -* Component outros, if `nestedTransitions` is true ([#1211](https://github.com/sveltejs/svelte/issues/1211)) -* Allow transition functions to return a function, for inter-transition coordination ([#1453](https://github.com/sveltejs/svelte/pull/1453)) -* Pass `1 - t` as second argument to transition functions ([#1452](https://github.com/sveltejs/svelte/pull/1452)) - -## 2.5.1 - -* Add new ARIA attributes ([#1436](https://github.com/sveltejs/svelte/pull/1436)) -* Add `Promise` to whitelisted globals ([#1441](https://github.com/sveltejs/svelte/issues/1441)) -* Allow spaces around reserved keyword attributes ([#1445](https://github.com/sveltejs/svelte/issues/1445)) - -## 2.5.0 - -* Support transitions in `await` blocks ([#956](https://github.com/sveltejs/svelte/issues/956)) -* Abort outros if block is recreated ([#1425](https://github.com/sveltejs/svelte/issues/1425)) -* Wait until transitions have completed before removing styles ([#648](https://github.com/sveltejs/svelte/issues/648)) -* Support event shorthand on dynamic components ([#1427](https://github.com/sveltejs/svelte/pull/1427)) -* Various codegen improvements ([#1419](https://github.com/sveltejs/svelte/pull/1419), [#1421](https://github.com/sveltejs/svelte/pull/1421), [#1422](https://github.com/sveltejs/svelte/pull/1422), [#1424](https://github.com/sveltejs/svelte/pull/1424)) -* Correctly handle `await` blocks with no dynamic content ([#1417](https://github.com/sveltejs/svelte/issues/1417)) -* Allow spread props on elements with static attribute tests ([#1429](https://github.com/sveltejs/svelte/pull/1429)) - - -## 2.4.4 - -* Declare missing variable in Store ([#1415](https://github.com/sveltejs/svelte/issues/1415)) -* ALways declare spread levels ([#1413](https://github.com/sveltejs/svelte/issues/1413)) - -## 2.4.3 - -* `ref` directives prevent HTMLified content ([#1407](https://github.com/sveltejs/svelte/issues/1407)) -* Store computed properties update components immediately upon declaration ([#1327](https://github.com/sveltejs/svelte/issues/1327)) - -## 2.4.2 - -* Evaluate `each` key in child scope ([#1397](https://github.com/sveltejs/svelte/issues/1397)) -* Prevent false negatives and positives when detecting cyclical computed store properties ([#1399](https://github.com/sveltejs/svelte/issues/1399)) -* Only update dynamic component props ([#1394](https://github.com/sveltejs/svelte/issues/1394)) - -## 2.4.1 - -* Fix DOM event context ([#1390](https://github.com/sveltejs/svelte/issues/1390)) - -## 2.4.0 - -* Integrate CLI ([#1360](https://github.com/sveltejs/svelte/issues/1360)) -* Allow arbitrary destructuring for each block items, with binding ([#1385](https://github.com/sveltejs/svelte/pull/1385)) -* Each block keys can use arbitrary expressions ([#703](https://github.com/sveltejs/svelte/issues/703)) -* `bind:offsetWidth`, `bind:offsetHeight`, `bind:clientWidth` and `bind:clientHeight` ([#984](https://github.com/sveltejs/svelte/issues/984)) -* Leaner generated code for `each` blocks ([#1287](https://github.com/sveltejs/svelte/issues/1287)) - - -## 2.3.0 - -* Allow computed properties to have entire state object as dependency ([#1303](https://github.com/sveltejs/svelte/issues/1303)) -* Fix `stats` when `options.generate` is `false` ([#1368](https://github.com/sveltejs/svelte/issues/1368)) -* Assign custom methods to custom elements ([#1369](https://github.com/sveltejs/svelte/issues/1369)) -* Fix `this` value in custom event handlers ([#1297](https://github.com/sveltejs/svelte/issues/1297)) -* Re-evaluate `each` values lazily ([#1286](https://github.com/sveltejs/svelte/issues/1286)) -* Preserve outer context in `await` blocks ([#1251](https://github.com/sveltejs/svelte/issues/1251)) - -## 2.2.0 - -* Internal refactoring ([#1367](https://github.com/sveltejs/svelte/pull/1367)) - -## 2.1.1 - -* Report initial `changed` based on state, not expected props ([#1356](https://github.com/sveltejs/svelte/issues/1356)) -* Set state to empty object, not null, on destroy ([#1354](https://github.com/sveltejs/svelte/issues/1354)) -* Prevent stale state in component event handlers ([#1353](https://github.com/sveltejs/svelte/issues/1353)) - -## 2.1.0 - -* Allow shorthand imports ([#1038](https://github.com/sveltejs/svelte/issues/1038)) -* Update spread props inside each blocks ([#1337](https://github.com/sveltejs/svelte/issues/1337)) - -## 2.0.0 - -*See [the blog post](https://svelte.dev/blog/version-2) for information on how to upgrade your apps* - -* New template syntax ([#1318](https://github.com/sveltejs/svelte/issues/1318)) -* Emit ES2015 code, not ES5 ([#1348](https://github.com/sveltejs/svelte/pull/1348)) -* Add `onstate` and `onupdate` hooks, remove `component.observe` method ([#1197](https://github.com/sveltejs/svelte/issues/1197)) -* Use destructuring syntax for computed properties ([#1069](https://github.com/sveltejs/svelte/issues/1069) -* Change signature of `svelte.compile` ([#1298](https://github.com/sveltejs/svelte/pull/1298)) -* Remove `validate` and `Stylesheet` from public API ([#1348](https://github.com/sveltejs/svelte/pull/1348)) -* Don't typecast numeric attributes ([#657](https://github.com/sveltejs/svelte/issues/657)) -* Always compile with `Store` support, and cascading disabled ([#1348](https://github.com/sveltejs/svelte/pull/1348)) -* Remove unused `hash` property from AST ([#1348](https://github.com/sveltejs/svelte/pull/1348)) -* Rename `loc` property to `start` in warnings and errors ([#1348](https://github.com/sveltejs/svelte/pull/1348)) - -## 1.64.1 - -* Fix computed properties in SSR renderer ([#1349](https://github.com/sveltejs/svelte/issues/1349)) - -## 1.64.0 - -* Deprecate passing a string argument to `component.get` ([#1347](https://github.com/sveltejs/svelte/pull/1347)) - -## 1.63.1 - -* Allow `observe` method to be overwritten - -## 1.63.0 - -* Add `onstate` and `onupdate` lifecycle hooks and deprecate `component.observe` ([#1197](https://github.com/sveltejs/svelte/issues/1197)) -* Add `on` and `fire` to `Store`, deprecate `onchange` and `observe` ([#1344](https://github.com/sveltejs/svelte/pull/1344)) -* Require computed properties to have destructured argument in v2 mode ([#1069](https://github.com/sveltejs/svelte/issues/1069)) - -## 1.62.0 - -* Add a `code` field to errors and warnings ([#474](https://github.com/sveltejs/svelte/issues/474)) -* When using v2 syntax, do not use interpolation in non-root `<style>` tags ([#1339](https://github.com/sveltejs/svelte/issues/1339)) - -## 1.61.0 - -* Support v2 syntax with `parser: 'v2'` option ([#1318](https://github.com/sveltejs/svelte/issues/1318)) - -## 1.60.3 - -* Fix validation of `multiple` attributes on bound `<select>` elements ([#1331](https://github.com/sveltejs/svelte/issues/1331)) - -## 1.60.2 - -* Fix order of insertions for keyed each blocks with siblings ([#1306](https://github.com/sveltejs/svelte/issues/1306)) -* Bail out of CSS DCE if element has spread attribute ([#1300](https://github.com/sveltejs/svelte/issues/1300)) -* Allow `console` etc in component events ([#1278](https://github.com/sveltejs/svelte/issues/1278)) -* Deconflict against inherited contexts ([#1275](https://github.com/sveltejs/svelte/issues/1275)) -* Make CSS DCE case insensitive ([#1269](https://github.com/sveltejs/svelte/issues/1269)) -* Error on dynamic `multiple` attribute for bound select ([#1270](https://github.com/sveltejs/svelte/issues/1270)) -* Allow custom events on `<:Window>` ([#1268](https://github.com/sveltejs/svelte/issues/1268)) - -## 1.60.1 - -* Fix spread updates on dynamic components ([#1307](https://github.com/sveltejs/svelte/issues/1307)) - -## 1.60.0 - -* Spread properties ([#195](https://github.com/sveltejs/svelte/issues/195)) -* `svelte.compile` returns an object with `{ js, css, ast }` properties, where `js` and `css` are `{ code, map }` objects ([#1298](https://github.com/sveltejs/svelte/pull/1298)) -* Fixed broken compile errors when using Rollup ([#1296](https://github.com/sveltejs/svelte/pull/1296)) - -## 1.59.0 - -* Deprecate `teardown` in custom event handlers ([#531](https://github.com/sveltejs/svelte/issues/531)) -* Allow static content in keyed `each` block ([#1291](https://github.com/sveltejs/svelte/issues/1291)) -* Allow empty content in keyed `each` block ([#1295](https://github.com/sveltejs/svelte/issues/1295)) -* Only delete applicable transitions ([#1290](https://github.com/sveltejs/svelte/issues/1290)) - -## 1.58.5 - -* Allow backtick string literals for `svg`, `tag`, and `props` properties ([#1284](https://github.com/sveltejs/svelte/issues/1284)) -* Fix removal of transition styles under Firefox ([#1288](https://github.com/sveltejs/svelte/pull/1288)) - -## 1.58.4 - -* Fix initial state regression ([#1283](https://github.com/sveltejs/svelte/pull/1283)) - -## 1.58.3 - -* Actions run in the context of the component ([#1279](https://github.com/sveltejs/svelte/pull/1279)) -* Set refs when mounting dynamic components ([#1280](https://github.com/sveltejs/svelte/pull/1280)) - -## 1.58.2 - -* (1.58.1 failed to publish) - -## 1.58.1 - -* Actions ([#1247](https://github.com/sveltejs/svelte/pull/1247)) -* Support `preserveComments` option in SSR mode ([#1265](https://github.com/sveltejs/svelte/issues/1265)) -* Fix performance regression ([#1274](https://github.com/sveltejs/svelte/pull/1274)) - -## 1.58.0 - -* Fast row swapping ([#588](https://github.com/sveltejs/svelte/issues/588)) -* Better error messages for invalid directives ([#1242](https://github.com/sveltejs/svelte/pull/1242)) -* Fix local context variable bugs ([#1240](https://github.com/sveltejs/svelte/pull/1243), [#1254](https://github.com/sveltejs/svelte/pull/1254)) -* Skip missing property warnings for computed/global properties in dev mode ([#1246](https://github.com/sveltejs/svelte/pull/1246)) -* Add end position to warnings ([#1250](https://github.com/sveltejs/svelte/pull/1250)) - -## 1.57.4 - -* Deconflict context names ([#1229](https://github.com/sveltejs/svelte/issues/1229)) -* Use `setAttribute` to set input types ([#1209](https://github.com/sveltejs/svelte/issues/1209)) -* Scale transition duration correctly ([#1221](https://github.com/sveltejs/svelte/issues/1221)) - -## 1.57.3 - -* Fix scoped CSS on static child elements ([#1223](https://github.com/sveltejs/svelte/issues/1223)) - -## 1.57.2 - -* Fix scoped CSS on SVG elements ([#1224](https://github.com/sveltejs/svelte/issues/1224)) - -## 1.57.1 - -* Add each_value to contextProps ([#1206](https://github.com/sveltejs/svelte/issues/1206)) - -## 1.57.0 - -* Use classes (not attributes) for style encapsulation, and base36-encode hashes ([#1118](https://github.com/sveltejs/svelte/issues/1118)) - -## 1.56.4 - -* Allow `component` and `state` to be context names ([#1213](https://github.com/sveltejs/svelte/issues/1213)) -* Don't remove `@supports` rules when `cascade: false` ([#1215](https://github.com/sveltejs/svelte/issues/1215)) - -## 1.56.3 - -* Top-level transitions work inside nested components ([#1188](https://github.com/sveltejs/svelte/issues/1188)) -* Always use internal `_mount` method ([#1201](https://github.com/sveltejs/svelte/issues/1201)) - -## 1.56.2 - -* Null out `key` for children of keyed each blocks ([#1202](https://github.com/sveltejs/svelte/issues/1202)) - -## 1.56.1 - -* Fix if-in-each bug ([#1195](https://github.com/sveltejs/svelte/issues/1195)) -* Cross-browser `scrollX`/`scrollY` support ([#1175](https://github.com/sveltejs/svelte/issues/1175)) - -## 1.56.0 - -* Internal refactor ([#1122](https://github.com/sveltejs/svelte/issues/1122)) -* Use correct context for component events ([#1184](https://github.com/sveltejs/svelte/issues/1184)) -* Allow observing `$foo` in dev mode ([#1181](https://github.com/sveltejs/svelte/issues/1181)) -* Handle dynamic data in default slot ([#1144](https://github.com/sveltejs/svelte/issues/1144)) - -## 1.55.1 - -* Fix cancellation of store `onchange` handlers ([#1177](https://github.com/sveltejs/svelte/issues/1177)) -* Write `["default"]` instead of `.default` in legacy mode ([#1166](https://github.com/sveltejs/svelte/issues/1166)) -* Upgrade Acorn ([#1182](https://github.com/sveltejs/svelte/pull/1182)) -* Don't warn about capitalisation if `options.name` begins with non-alphabetical character ([#1179](https://github.com/sveltejs/svelte/pull/1179)) - -## 1.55.0 - -* Add `immutable` compiler option for Svelte and runtime option for `Store` ([#1146](https://github.com/sveltejs/svelte/issues/1146)) -* Fix component store bindings ([#1100](https://github.com/sveltejs/svelte/issues/1100)) -* Fire `oncreate` when custom element is attached ([#1117](https://github.com/sveltejs/svelte/issues/1117)) -* Downgrade empty blocks to a warning ([#1156](https://github.com/sveltejs/svelte/pull/1156)) -* Error on unclosed comment ([#1156](https://github.com/sveltejs/svelte/pull/1156)) - -## 1.54.2 - -* Prevent `await` blocks using stale state ([#1131](https://github.com/sveltejs/svelte/issues/1131)) -* Prevent erroneous missing data warnings for custom elements ([#1065](https://github.com/sveltejs/svelte/issues/1065)) -* Remove empty selectors in prod mode ([#1138](https://github.com/sveltejs/svelte/issues/1138)) -* Escape attribute values in SSR mode ([#1155](https://github.com/sveltejs/svelte/pull/1155)) -* Remove `<noscript>` elements in DOM mode ([#1108](https://github.com/sveltejs/svelte/issues/1108)) -* Allow hydration of non-root `<script>`/`<style>` tags ([#1163](https://github.com/sveltejs/svelte/pull/1163)) -* Allow interpolation in non-root `<style>` tags ([#1163](https://github.com/sveltejs/svelte/pull/1163)) - -## 1.54.1 - -* Hoist destructured references ([#1139](https://github.com/sveltejs/svelte/issues/1139)) -* Add `bind:volume` for media elements ([#1143](https://github.com/sveltejs/svelte/issues/1143)) - -## 1.54.0 - -* Run `oncreate` hooks depth-first, top-to-bottom ([#1135](https://github.com/sveltejs/svelte/issues/1135)) -* Render boolean attributes correctly in SSR mode ([#1109](https://github.com/sveltejs/svelte/issues/1109)) -* Add `feed` aria role to expected roles when doing a11y checks ([#1124](https://github.com/sveltejs/svelte/pull/1124)) -* More complete fix for case sensitive attributes ([#1062](https://github.com/sveltejs/svelte/issues/1062)) -* Handle CLRF line endings in await block comments ([#1132](https://github.com/sveltejs/svelte/issues/1132)) - -## 1.53.0 - -* Base scoping selectors on `<style>` contents alone ([#1091](https://github.com/sveltejs/svelte/issues/1091)) - -## 1.52.0 - -* Deconflict referenced globals ([#1079](https://github.com/sveltejs/svelte/issues/1079)) -* Validate contents of `await` blocks ([#1061](https://github.com/sveltejs/svelte/issues/1061)) -* Fire `oncreate` for components in `await` blocks ([#1061](https://github.com/sveltejs/svelte/issues/1061)) -* Automatically fix attribute casing ([#1062](https://github.com/sveltejs/svelte/issues/1062)) -* Fix escaping in `<script>` and `<style>` ([#1082](https://github.com/sveltejs/svelte/issues/1082)) -* Error if invalid characters are used in computed properties, and allow any valid identifier in props ([#1083](https://github.com/sveltejs/svelte/issues/1083)) -* Don't run a11y tests on components ([#1110](https://github.com/sveltejs/svelte/issues/1110)) -* Respect `store` option in SSR mode ([#1107](https://github.com/sveltejs/svelte/issues/1107)) - -## 1.51.1 - -* Only escape <, > and & characters ([#1082](https://github.com/sveltejs/svelte/issues/1082)) - -## 1.51.0 - -* Lock `scroll` bindings ([#1071](https://github.com/sveltejs/svelte/issues/1071)) -* Escape HTML entities when compiling to static HTML ([#1066](https://github.com/sveltejs/svelte/issues/1066)) -* Apply a11y warnings to SVG `<a>` attributes with `xlink:href` ([#1008](https://github.com/sveltejs/svelte/issues/1008)) - -## 1.50.1 - -* Prevent main fragment being created twice in custom elements ([#1064](https://github.com/sveltejs/svelte/pull/1064)) - -## 1.50.0 - -* Detect unused/misplaced components ([#1039](https://github.com/sveltejs/svelte/issues/1039)) -* Warn on unused event definitions/transitions ([#1051](https://github.com/sveltejs/svelte/issues/1051)) -* Remove whitespace inside `<:Head>` ([#1026](https://github.com/sveltejs/svelte/issues/1026)) -* Optimise `<title>` ([#1027](https://github.com/sveltejs/svelte/issues/1027)) -* Add `bind: false` option to disable two-way binding ([#54](https://github.com/sveltejs/svelte/issues/54)) - -## 1.49.3 - -* Return `html` from SSR compiler `render().toString()` methods ([#1044](https://github.com/sveltejs/svelte/issues/1044)) -* Correctly reinitialise dynamic components ([#1040](https://github.com/sveltejs/svelte/issues/1040)) -* Allow `<option>` outside `<select>` ([#1022](https://github.com/sveltejs/svelte/issues/1022)) -* Fix data references in await-block event handlers ([#1032](https://github.com/sveltejs/svelte/issues/1032)) - -## 1.49.2 - -* Add `store.umd.js` ([#967](https://github.com/sveltejs/svelte/issues/967)) -* Warn on use of `this` inside computed properties ([#1033](https://github.com/sveltejs/svelte/pull/1033)) - -## 1.49.1 - -* Pass `store` to children in SSR mode ([#1029](https://github.com/sveltejs/svelte/pull/1029)) - -## 1.49.0 - -* Support `store` as a component property ([#1028](https://github.com/sveltejs/svelte/pull/1028)) - -## 1.48.0 - -* Added `<:Head>` component for injecting contents into document head ([#1013](https://github.com/sveltejs/svelte/issues/1013))) -* SSR `render(...)` method now returns a `{ html, css: { code, map }, head }` object ([#1013](https://github.com/sveltejs/svelte/issues/1013)) -* SSR `renderCss(...)` method is deprecated ([#1013](https://github.com/sveltejs/svelte/issues/1013)) -* Add a `preload` function to components ([#1015](https://github.com/sveltejs/svelte/issues/1015)) -* Expose `this.root` on nested components ([#1023](https://github.com/sveltejs/svelte/pull/1023)) - -## 1.47.2 - -* Deconflict computed properties against arguments to `_recompute` ([#1012](https://github.com/sveltejs/svelte/issues/1012)) -* Allow `await` blocks in slots ([#1018](https://github.com/sveltejs/svelte/issues/1018)) -* Allow components without slots to have whitespace as only child ([#1007](https://github.com/sveltejs/svelte/issues/1007)) -* Correctly set `toString` on `CompileError` ([#1016](https://github.com/sveltejs/svelte/pull/1016)) - -## 1.47.1 - -* Sanitize filenames in SSR mode ([#1005](https://github.com/sveltejs/svelte/issues/1005)) - -## 1.47.0 - -* Support dynamic `import(...)` inside `<script>` tags ([#1003](https://github.com/sveltejs/svelte/issues/1003)) - -## 1.46.1 - -* `await...then` shorthand ([#957](https://github.com/sveltejs/svelte/issues/957)) -* Allow dynamic components inside elements ([#993](https://github.com/sveltejs/svelte/issues/993)) -* Don't use `dataset` on SVG nodes ([#982](https://github.com/sveltejs/svelte/issues/982)) -* Fix erroneous `<figcaption>` a11y warning ([#991](https://github.com/sveltejs/svelte/issues/991)) -* Handle empty classes when pruning unused selectors ([#978](https://github.com/sveltejs/svelte/issues/978)) -* Better trimming of SSR'd output ([#976](https://github.com/sveltejs/svelte/issues/976)) -* Don't add `event` to `expectedProperties` ([#972](https://github.com/sveltejs/svelte/issues/972)) -* Emit error on bad `set` arguments in dev mode ([#990](https://github.com/sveltejs/svelte/issues/990)) - -## 1.46.0 - -* Pass `filename` through to preprocessors ([#983](https://github.com/sveltejs/svelte/issues/983)) - -## 1.45.0 - -* Dynamic components ([#971](https://github.com/sveltejs/svelte/pull/971)) - -## 1.44.2 - -* Fix `await` blocks with siblings ([#974](https://github.com/sveltejs/svelte/issues/974)) -* Fix `await` blocks inside `if` blocks ([#975](https://github.com/sveltejs/svelte/issues/975)) - -## 1.44.1 - -* Fix bidirectional transitions that reference state ([#962](https://github.com/sveltejs/svelte/issues/962)) - -## 1.44.0 - -* Add `svelte.preprocess` ([#181](https://github.com/sveltejs/svelte/issues/181), [#876](https://github.com/sveltejs/svelte/issues/876)) -* Add `{{#await ...}}` blocks ([#654](https://github.com/sveltejs/svelte/issues/654)) - -## 1.43.1 - -* Fix parameterised transitions ([#962](https://github.com/sveltejs/svelte/issues/962)) -* Prevent boolean attributes breaking estree-walker expectations ([#961](https://github.com/sveltejs/svelte/issues/961)) -* Throw error on cyclical store computations ([#964](https://github.com/sveltejs/svelte/pull/964)) - -## 1.43.0 - -* Export `Store` class to manage global state ([#930](https://github.com/sveltejs/svelte/issues/930)) -* Recognise `aria-current` ([#953](https://github.com/sveltejs/svelte/pull/953)) -* Support SSR register options including `extensions` ([#939](https://github.com/sveltejs/svelte/issues/939)) -* Friendlier error for illegal contexts ([#934](https://github.com/sveltejs/svelte/issues/934)) -* Remove whitespace around `<:Window>` components ([#943](https://github.com/sveltejs/svelte/issues/943)) - -## 1.42.1 - -* Correctly append items inside a slotted `each` block ([#932](https://github.com/sveltejs/svelte/pull/932)) -* Fix `<:Window bind:online/>` ([#936](https://github.com/sveltejs/svelte/issues/936)) -* Attach globals to state upon initialisation ([#908](https://github.com/sveltejs/svelte/issues/908)) - -## 1.42.0 - -* Implement `indeterminate` binding for checkbox inputs ([#910](https://github.com/sveltejs/svelte/issues/910)) -* Use `<option>` children as `value` attribute if none exists ([#928](https://github.com/sveltejs/svelte/issues/928)) -* Allow quoted property names in default export and sub-properties ([#914](https://github.com/sveltejs/svelte/issues/914)) -* Various improvements to generated code for bindings - -## 1.41.4 - -* Handle self-destructive bindings ([#917](https://github.com/sveltejs/svelte/issues/917)) -* Prevent `innerHTML` with `<option>` elements ([#915](https://github.com/sveltejs/svelte/issues/915)) -* Use `dataset` unless `legacy` is true ([#858](https://github.com/sveltejs/svelte/issues/858)) -* Add `prepare` script to facilitate installing from git ([#923](https://github.com/sveltejs/svelte/pull/923)) - -## 1.41.3 - -* Prevent argument name clashes ([#911](https://github.com/sveltejs/svelte/issues/911)) -* Fix UMD factory arguments ([#918](https://github.com/sveltejs/svelte/pull/918)) -* Don't attempt to set computed values ([#893](https://github.com/sveltejs/svelte/issues/893)) -* Fix TypeScript build error ([#919](https://github.com/sveltejs/svelte/issues/919)) - -## 1.41.2 - -* Handle attribute selectors with no value ([#905](https://github.com/sveltejs/svelte/issues/905)) -* Retain `async` keyword when extracting functions ([#904](https://github.com/sveltejs/svelte/issues/904)) -* Shallow clone `data` on initialisation ([#891](https://github.com/sveltejs/svelte/pull/891)) - -## 1.41.1 - -* Fix updates of destructured each blocks ([#897](https://github.com/sveltejs/svelte/pull/897)) -* Don't warn on `options.*` event handler callee ([#900](https://github.com/sveltejs/svelte/pull/900)) - -## 1.41.0 - -* `onwarn` and `onerror` receive default handlers as second arguments ([#883](https://github.com/sveltejs/svelte/pull/883)) -* Recognise `muted` as boolean property on `<audio>` elements ([#886](https://github.com/sveltejs/svelte/pull/886)) -* Array destructuring for `each` block contexts ([#889](https://github.com/sveltejs/svelte/pull/889)) - -## 1.40.2 - -* Ignore `@apply` and similar in CSS ([#871](https://github.com/sveltejs/svelte/issues/871)) -* Properly escape CSS in custom elements ([#872](https://github.com/sveltejs/svelte/issues/872)) - -## 1.40.1 - -* Always use explicit closing tags with `innerHTML` ([#866](https://github.com/sveltejs/svelte/issues/866)) -* Escape text in `textContent` and `innerHTML` expressions ([#868](https://github.com/sveltejs/svelte/issues/868)) - -## 1.40.0 - -* Short fragment method names ([#863](https://github.com/sveltejs/svelte/pull/863)) -* Extract declarations out of default export ([#756](https://github.com/sveltejs/svelte/issues/756)) - -## 1.39.4 - -* Extract shared init logic ([#855](https://github.com/sveltejs/svelte/pull/855)) -* Allow `console.*` calls in event handlers ([#782](https://github.com/sveltejs/svelte/issues/782)) -* Marker comments in output ([#823](https://github.com/sveltejs/svelte/issues/823)) -* Use `textContent` and `innerHTML` where appropriate ([#23](https://github.com/sveltejs/svelte/issues/23)) -* Various improvements to generated code - -## 1.39.3 - -* Allow `slot='...'` inside custom elements ([#827](https://github.com/sveltejs/svelte/issues/827)) -* Disallow `slot='...'` inside if/each blocks ([#849](https://github.com/sveltejs/svelte/issues/849)) -* Use correct parent node for slotted if blocks ([#850](https://github.com/sveltejs/svelte/issues/850)) - -## 1.39.2 - -* Escape CSS in shadow DOM ([#840](https://github.com/sveltejs/svelte/issues/840)) -* Fix missing anchor bug inside SVG elements ([#843](https://github.com/sveltejs/svelte/issues/843)) - -## 1.39.1 - -* Always use anchors for slotted content ([#822](https://github.com/sveltejs/svelte/issues/822)) -* Prevent ES6 in helpers ([#838](https://github.com/sveltejs/svelte/issues/838)) -* Correctly determine whether to use `timeRangesToArray` ([#837](https://github.com/sveltejs/svelte/pull/837)) - -## 1.39.0 - -* Always attach fragment to shadow root ([#821](https://github.com/sveltejs/svelte/issues/821)) -* Add `buffered`, `seekable`, `played` bindings to media elements ([#819](https://github.com/sveltejs/svelte/pull/819)) -* Quote `class` properties in legacy mode ([#830](https://github.com/sveltejs/svelte/issues/830)) -* Warn on missing `lang` attribute on `<html>` ([#828](https://github.com/sveltejs/svelte/pull/828)) - -## 1.38.0 - -* Compile-time a11y warnings ([#815](https://github.com/sveltejs/svelte/pull/815)) -* Remove redundant input blowback guards ([#645](https://github.com/sveltejs/svelte/issues/645)) -* Use component name in debugging messages ([#781](https://github.com/sveltejs/svelte/issues/781)) - -## 1.37.0 - -* Experimental support for compiling to custom elements ([#797](https://github.com/sveltejs/svelte/issues/797)) - -## 1.36.0 - -* Optimize `style` attributes where possible ([#455](https://github.com/sveltejs/svelte/issues/455)) - -## 1.35.0 - -* `set` and `get` continue to work until `destroy` is complete ([#788](https://github.com/sveltejs/svelte/issues/788)) -* Observers of unchanged bound values don't fire incorrectly ([#804](https://github.com/sveltejs/svelte/issues/804)) -* Nested components with slotted content render correctly in SSR mode ([#801](https://github.com/sveltejs/svelte/issues/801)) -* More efficient rendering of raw and slotted content ([#637](https://github.com/sveltejs/svelte/issues/637)) -* Handle unquoted attributes in attribute selectors ([#798](https://github.com/sveltejs/svelte/issues/798)) - -## 1.34.0 - -* Support nested `<slot>` elements ([#790](https://github.com/sveltejs/svelte/issues/790)) -* Attach `options` to instance ([#550](https://github.com/sveltejs/svelte/issues/550), [#777](https://github.com/sveltejs/svelte/issues/777)) -* Error if transitions are applied to component ([#791](https://github.com/sveltejs/svelte/issues/791)) -* Handle CSS variables in `<style>` tag ([#757](https://github.com/sveltejs/svelte/issues/757)) - -## 1.33.0 - -* Replace `{{yield}}` with `<slot>` — adds fallback content named slots, and `options.slots` ([#763](https://github.com/sveltejs/svelte/issues/763)) - -## 1.32.0 - -* Allow `anchor` initialisation option, alongside `target` ([#784](https://github.com/sveltejs/svelte/issues/784)) -* Remove leading CSS selectors safely ([#783](https://github.com/sveltejs/svelte/issues/783)) - -## 1.31.0 - -* Add `legacy` compile option, which adds IE9 compatibility ([#773](https://github.com/sveltejs/svelte/issues/773)) - -## 1.30.0 - -* Update all component bindings simultaneously ([#760](https://github.com/sveltejs/svelte/issues/760)) -* Fix `@keyframes` atrules with `from` and `to` selectors ([#774](https://github.com/sveltejs/svelte/issues/774)) - -## 1.29.3 - -* Only recompute tag and attribute values if they could have changed ([#768](https://github.com/sveltejs/svelte/issues/768)) -* Fix CSS scoping with multiple levels of descendant selectors ([#767](https://github.com/sveltejs/svelte/issues/767)) - -## 1.29.2 - -* Preserve space before non-parenthesized media query expression ([#759](https://github.com/sveltejs/svelte/issues/759)) -* Call `create()` on new iterations of static each blocks ([#762](https://github.com/sveltejs/svelte/issues/762)) -* Use `change` events as well as `input` events to bind range inputs ([#740](https://github.com/sveltejs/svelte/issues/740)) - -## 1.29.1 - -* Replace `set` and `destroy` with `noop` when component is destroyed ([#744](https://github.com/sveltejs/svelte/issues/744)) - -## 1.29.0 - -* Add static `setup` method ([#578](https://github.com/sveltejs/svelte/issues/578)) -* Hoist if block selectors ([#751](https://github.com/sveltejs/svelte/pull/751)) -* More sigil escaping fixes ([#750](https://github.com/sveltejs/svelte/pull/750)) - -## 1.28.1 - -* Fix unescaping of special words in SSR mode ([#741](https://github.com/sveltejs/svelte/issues/741)) - -## 1.28.0 - -* Support `ref:foo` as a CSS selector ([#693](https://github.com/sveltejs/svelte/issues/693)) -* Prevent magic-string bugs by only minifying CSS combinators if `cascade: false` ([#743](https://github.com/sveltejs/svelte/issues/743)) -* Don't throw an error if component is destroyed twice ([#643](https://github.com/sveltejs/svelte/issues/643)) - -## 1.27.0 - -* Minify CSS and remove unused styles ([#697](https://github.com/sveltejs/svelte/issues/697)) -* Optimize ternary expressions when excluding unused CSS ([#696](https://github.com/sveltejs/svelte/issues/696)) -* Clear refs after `ondestroy` callbacks fire ([#706](https://github.com/sveltejs/svelte/issues/706)) -* Prevent certain forms of component binding blowback ([#721](https://github.com/sveltejs/svelte/issues/721)) -* Use helper to encapsulate styles ([#375](https://github.com/sveltejs/svelte/issues/375)) -* Event propagation shorthand — `on:foo` equals `on:foo='fire("foo", event)` ([#638](https://github.com/sveltejs/svelte/issues/638)) -* Allow `refs.*` in event handlers, and validate them ([#686](https://github.com/sveltejs/svelte/issues/686)) - -## 1.26.2 - -* Unescape `#` characters ([#722](https://github.com/sveltejs/svelte/issues/722)) - -## 1.26.1 - -* Fix select binding regression ([#724](https://github.com/sveltejs/svelte/issues/724)) - -## 1.26.0 - -* Enforce correct order of operations when initialising ([#708](https://github.com/sveltejs/svelte/issues/708) and [#714](https://github.com/sveltejs/svelte/issues/714)) -* Ensure data is up-to-date when re-rendering yield block ([#711](https://github.com/sveltejs/svelte/issues/711)) -* Fix unescaping of strings, preserve at-rules in CSS ([#712](https://github.com/sveltejs/svelte/issues/712)) -* Preserve whitespace at end of each blocks ([#713](https://github.com/sveltejs/svelte/issues/713)) - -## 1.25.1 - -* Better CSS sourcemaps ([#716](https://github.com/sveltejs/svelte/pull/716)) - -## 1.25.0 - -* Fix hoisted event handlers ([#699](https://github.com/sveltejs/svelte/issues/699)) -* Fire `intro.start` and `outro.start` events ([#702](https://github.com/sveltejs/svelte/issues/702)) -* Preserve order of components in keyed each blocks ([#700](https://github.com/sveltejs/svelte/issues/700)) -* Add `cssMap` property to compiler output ([#698](https://github.com/sveltejs/svelte/pull/698/)) - -## 1.24.0 - -* Deconflict names with imports in SSR compiler ([#655](https://github.com/sveltejs/svelte/issues/655)) -* Improved transition performance ([#670](https://github.com/sveltejs/svelte/pull/670)) -* Run transitions on initial render ([#651](https://github.com/sveltejs/svelte/issues/651)) -* Add dev mode warning if `hydrate` is true but `hydratable` was false ([#664](https://github.com/sveltejs/svelte/issues/664)) -* Manipulate sourcemap to make missing loop values obvious ([#683](https://github.com/sveltejs/svelte/pull/683)) -* Only add CSS scoping attributes where necessary ([#679](https://github.com/sveltejs/svelte/issues/679)) -* Warn on unused CSS selectors ([#678](https://github.com/sveltejs/svelte/issues/678)) -* Fix `<select>` binding in loop ([#685](https://github.com/sveltejs/svelte/issues/685)) -* Prevent bindings from calling `oncreate` functions prematurely ([#694](https://github.com/sveltejs/svelte/pull/694)) -* Simpler codegen ([#673](https://github.com/sveltejs/svelte/pull/673)) - -## 1.23.4 - -* Don't recreate if blocks incorrectly ([#669](https://github.com/sveltejs/svelte/pull/669)) - -## 1.23.3 - -* Pass parameters to `get_block` ([#667](https://github.com/sveltejs/svelte/issues/667)) - -## 1.23.2 - -* Fix if blocks being recreated on update ([#665](https://github.com/sveltejs/svelte/issues/665)) - -## 1.23.1 - -* Fix each-else blocks that are empty on initial render ([#662](https://github.com/sveltejs/svelte/issues/662)) - -## 1.23.0 - -* Hydration ([#649](https://github.com/sveltejs/svelte/pull/649)) -* Correctly transform CSS selectors with pseudo-elements ([#658](https://github.com/sveltejs/svelte/issues/658)) - -## 1.22.5 - -* Fix nested component unmounting bug ([#643](https://github.com/sveltejs/svelte/issues/643)) - -## 1.22.4 - -* Include `ast` in `svelte.compile` return value ([#632](https://github.com/sveltejs/svelte/issues/632)) -* Set initial value of `<select>` binding, if unspecified ([#639](https://github.com/sveltejs/svelte/issues/639)) -* Mark indirect dependencies of `<select>` bindings (i.e. the dependencies of their `<option>` values) ([#639](https://github.com/sveltejs/svelte/issues/639)) - -## 1.22.3 - -* Fix nested component unmounting bug ([#625](https://github.com/sveltejs/svelte/issues/625)) -* Allow components to have computed member expression bindings ([#624](https://github.com/sveltejs/svelte/issues/624)) -* Handle empty `<style>` tags ([#634](https://github.com/sveltejs/svelte/issues/634)) -* Warn on missing component ([#623](https://github.com/sveltejs/svelte/issues/623)) -* Allow dynamic `type` attribute for unbound inputs ([#620](https://github.com/sveltejs/svelte/issues/620)) -* Rename `addEventListener` and `removeEventListener` directives ([#621](https://github.com/sveltejs/svelte/issues/621)) - -## 1.22.2 - -* Escape template strings correctly in SSR output ([#616](https://github.com/sveltejs/svelte/issues/616)) -* Prevent magic-string deprecation warning ([#617](https://github.com/sveltejs/svelte/pull/617)) - -## 1.22.1 - -* Sanitise event handler names ([#612](https://github.com/sveltejs/svelte/issues/612)) - -## 1.22.0 - -* Symmetry between `mount` and `unmount`. This is potentially a breaking change if your components import other components that were precompiled with an earlier version of Svelte ([#592](https://github.com/sveltejs/svelte/issues/592)) -* Add `cascade` option, which prevents styles affecting child components if `false`, unless selectors are wrapped in `:global(...)` and keyframe declaration IDs are prefixed with `-global-`. This will become the default behaviour in v2 ([#583](https://github.com/sveltejs/svelte/issues/583)) -* Support binding to computed member expressions ([#602](https://github.com/sveltejs/svelte/issues/602)) -* Coerce empty string in `number`/`range` inputs to `undefined`, not `0` ([#584](https://github.com/sveltejs/svelte/issues/584)) -* Fix insert location of DOM elements in each/if/nested component edge cases ([#610](https://github.com/sveltejs/svelte/issues/610)) - -## 1.21.0 - -* Always use `helpers` if referenced, not just for call expressions ([#575](https://github.com/sveltejs/svelte/issues/575)) -* Fix parsing of `<textarea>` children ([#599](https://github.com/sveltejs/svelte/pull/599)) -* Treat `<textarea>` value attributes and children as equivalent, and fail validation if both are present ([#599](https://github.com/sveltejs/svelte/pull/599)) -* Fix `<textarea>` SSR ([#599](https://github.com/sveltejs/svelte/pull/599)) -* Apply CSS transition styles immediately if transition has delay ([#574](https://github.com/sveltejs/svelte/issues/574)) -* Ensure `transitionManager` is treeshakeable ([#593](https://github.com/sveltejs/svelte/issues/593)) -* Fix for environments where `node.style.animation` is undefined ([#587](https://github.com/sveltejs/svelte/issues/587)) -* Fix order of operations when dealing with `<select>` elements ([#590](https://github.com/sveltejs/svelte/issues/590)) -* Downgrade 'invalid callee' to a warning ([#579](https://github.com/sveltejs/svelte/issues/579)) -* Convert to TypeScript ([#573](https://github.com/sveltejs/svelte/pull/573)) - -## 1.20.2 - -* Fix destruction of compound if-blocks with outros ([#572](https://github.com/sveltejs/svelte/pull/572)) - -## 1.20.1 - -* Fix insertion order of `if` blocks and their anchors ([#569](https://github.com/sveltejs/svelte/issues/569)) - -## 1.20.0 - -* Faster, better updates of keyed each blocks ([#373](https://github.com/sveltejs/svelte/issues/373), [#543](https://github.com/sveltejs/svelte/issues/543)) -* Use element IDs to robustly track dynamically injected `<style>` tags ([#554](https://github.com/sveltejs/svelte/issues/554)) -* Abort outros before corresponding intros ([#546](https://github.com/sveltejs/svelte/issues/546)) -* Generate less code for `if` blocks with `else` blocks ([#540](https://github.com/sveltejs/svelte/issues/540)) -* Ensure `{{yield}}` block content is injected into the right place ([#561](https://github.com/sveltejs/svelte/issues/561)) -* Simpler, more readable codegen code ([#559](https://github.com/sveltejs/svelte/pull/559)) -* Validate transition directives ([#564](https://github.com/sveltejs/svelte/issues/564)) -* Apply delays to bidirectional transitions ([#562](https://github.com/sveltejs/svelte/issues/562)) -* Handle all valid HTML entities ([#565](https://github.com/sveltejs/svelte/pull/565)) -* Fix outros on compound `if` blocks ([#565](https://github.com/sveltejs/svelte/pull/565)) -* Validation for `<:Window>` tags ([#565](https://github.com/sveltejs/svelte/pull/565)) -* Increased test coverage ([#565](https://github.com/sveltejs/svelte/pull/565)) - -## 1.19.1 - -* Export `generateKeyframes`, so that CSS transitions work - -## 1.19.0 - -* Experimental support for transitions ([#7](https://github.com/sveltejs/svelte/issues/7)) -* Use `querySelector(':checked')` instead of `selectedOptions` ([#539](https://github.com/sveltejs/svelte/issues/539)) -* Stringify helpers before bundling them, to avoid renaming errors ([#538](https://github.com/sveltejs/svelte/issues/538)) - -## 1.18.2 - -* Parenthesize if-block conditions ([#532](https://github.com/sveltejs/svelte/issues/532)) -* Fix parsing of parenthesized expressions ([#534](https://github.com/sveltejs/svelte/issues/534)) -* Fix error on `bind:checked` that doesn't belong to a checkbox input ([#529](https://github.com/sveltejs/svelte/pull/529)) - -## 1.18.1 - -* Allow `destroy()` in event handlers ([#523](https://github.com/sveltejs/svelte/issues/523)) -* Fix bug with `{{yield}}` blocks following elements ([#524](https://github.com/sveltejs/svelte/issues/524)) - -## 1.18.0 - -* Visit `<select>` attributes after children, to ensure options are in the right state ([#521](https://github.com/sveltejs/svelte/pull/521)) -* Use sibling elements as anchors rather than creating comment nodes wherever possible ([#3](https://github.com/sveltejs/svelte/issues/3)) - -## 1.17.2 - -* Replace bad characters when creating variable names based on element names ([#516](https://github.com/sveltejs/svelte/issues/516)) - -## 1.17.1 - -* Fixes for static each-else and yield blocks ([#509](https://github.com/sveltejs/svelte/issues/509)), ([#514](https://github.com/sveltejs/svelte/issues/514)) -* Code generation tweaks ([#504](https://github.com/sveltejs/svelte/issues/504)), ([#507](https://github.com/sveltejs/svelte/issues/507)) - -## 1.17.0 - -* Add `currentTime`, `duration` and `paused` bindings for media elements ([#406](https://github.com/sveltejs/svelte/issues/406)) -* Don't treat helpers as dependencies ([#492](https://github.com/sveltejs/svelte/issues/492)) -* Allow `<:Window>` event handlers to access component state ([#497](https://github.com/sveltejs/svelte/pull/497)) -* Allow two-way binding to properties named 'component' ([#495](https://github.com/sveltejs/svelte/issues/495)) -* Group checkbox bindings correctly, to avoid erroneously unchecking siblings ([#498](https://github.com/sveltejs/svelte/issues/498)) -* Validate two-way bindings ([#494](https://github.com/sveltejs/svelte/pull/494)) -* Allow dynamic each-block to have static else-block ([#501](https://github.com/sveltejs/svelte/pull/501)) -* Initialise `<select>` value correctly ([#502](https://github.com/sveltejs/svelte/pull/502)) - -## 1.16.0 - -* Better code generation ([#489](https://github.com/sveltejs/svelte/pull/489)), ([#490](https://github.com/sveltejs/svelte/pull/490)), ([#491](https://github.com/sveltejs/svelte/pull/491)) -* Prevent binding blowback on initial render ([#488](https://github.com/sveltejs/svelte/pull/488)) - -## 1.15.1 - -* Clone data before merging it with state ([#479](https://github.com/sveltejs/svelte/issues/479)) -* Apply binding event handlers before user event handlers ([#486](https://github.com/sveltejs/svelte/issues/486)) - -## 1.15.0 - -* Dev mode — downgrade 'missing data' to a warning, and ignore whitelisted globals ([#475](https://github.com/sveltejs/svelte/issues/475)) -* Fix `<select>` value binding when options are updated late ([#476](https://github.com/sveltejs/svelte/issues/476)) -* Throw at compile time if event handler references invalid callee ([#473](https://github.com/sveltejs/svelte/pull/473)) -* Check for helper function purity ([#473](https://github.com/sveltejs/svelte/pull/473)) -* Validate `namespace` option ([#473](https://github.com/sveltejs/svelte/pull/473)) - -## 1.14.1 - -* Replace bad characters when creating variable names based on attributes ([#470](https://github.com/sveltejs/svelte/issues/470)) - -## 1.14.0 - -* Better guard against naming conflicts ([#465](https://github.com/sveltejs/svelte/issues/465)) -* Better error if getters and setters are used with `methods` ([#425](https://github.com/sveltejs/svelte/issues/425)) -* Don't create whitespace nodes inside elements that can't use them ([#189](https://github.com/sveltejs/svelte/issues/189)) -* Collapse consecutive `if` statements with the same condition ([#450](https://github.com/sveltejs/svelte/issues/450)) -* Window `scroll` bindings are bidirectional ([#404](https://github.com/sveltejs/svelte/issues/404)) -* Add `bind:online` to window ([#404](https://github.com/sveltejs/svelte/issues/404)) -* In dev mode, throw if read-only properties are set ([#404](https://github.com/sveltejs/svelte/issues/404)) -* Prevent conflicts with component name ([#464](https://github.com/sveltejs/svelte/pull/464)) -* Ensure event handler names are deconflicted ([#466](https://github.com/sveltejs/svelte/issues/466)) - -## 1.13.7 - -* Fix observers — `defer: true` now triggers callback after DOM is updated ([#441](https://github.com/sveltejs/svelte/issues/441)) -* Handle empty `computed` property ([#452](https://github.com/sveltejs/svelte/issues/452)) -* Correctly bind one-way `<select>` value attributes with objects ([#423](https://github.com/sveltejs/svelte/issues/423)) -* Hoist event handlers inside each blocks, where possible ([#456](https://github.com/sveltejs/svelte/pull/456)) -* Don't bind event handler callbacks ([#433](https://github.com/sveltejs/svelte/issues/433)) -* Internal refactoring and neater code generation ([#453](https://github.com/sveltejs/svelte/pull/453)) - -## 1.13.6 - -* Use `assign` helper instead of `Object.assign` for better performance and legacy compatibility ([#431](https://github.com/sveltejs/svelte/issues/431)) -* Improved code generation ([#419](https://github.com/sveltejs/svelte/issues/419)), ([#440](https://github.com/sveltejs/svelte/issues/440)), ([#442](https://github.com/sveltejs/svelte/issues/442)) - -## 1.13.5 - -* Read `range` and `number` input values as numbers ([#436](https://github.com/sveltejs/svelte/issues/436)) -* Better error for `bind:value='{{foo}}'` ([#437](https://github.com/sveltejs/svelte/issues/437)) - -## 1.13.4 - -* Prevent unclosed `<script>` tag causing infinite loop ([#435](https://github.com/sveltejs/svelte/pull/435)) - -## 1.13.3 - -* Correctly handle `{{true}}`, `{{false}}` and `{{null}}` ([#424](https://github.com/sveltejs/svelte/issues/424)) -* Update `<select>` value attributes correctly ([#423](https://github.com/sveltejs/svelte/issues/423)) -* Bind custom event handler callbacks ([#428](https://github.com/sveltejs/svelte/issues/428)) -* Disallow `import root` ([#430](https://github.com/sveltejs/svelte/pull/430)) -* Prevent component bindings mutating the wrong object ([#432](https://github.com/sveltejs/svelte/pull/432)) - -## 1.13.2 - -* Fix deep component bindings ([#420](https://github.com/sveltejs/svelte/issues/420)) -* Include `css` property in compiler output ([#409](https://github.com/sveltejs/svelte/issues/409)) -* Treat functions as mutable objects when recomputing ([#413](https://github.com/sveltejs/svelte/issues/413) -* Include magic-string in bundle ([#410](https://github.com/sveltejs/svelte/issues/410)) -* Disable unneeded Bublé transformations for slimmer output ([#411](https://github.com/sveltejs/svelte/pull/411)) - -## 1.13.1 - -* Prevent infinite loops with pathological component bindings ([#398](https://github.com/sveltejs/svelte/issues/398)) -* More robust deconflicting ([#401](https://github.com/sveltejs/svelte/pull/401)) - -## 1.13.0 - -* Add `<:Window>` meta tag with event listeners, and a handful of bindings ([#371](https://github.com/sveltejs/svelte/issues/371)) -* Don't uncheck radios incorrectly ([#399](https://github.com/sveltejs/svelte/issues/399)) - -## 1.12.1 - -* Deconflict non-helper functions (`addCss` etc) ([#388](https://github.com/sveltejs/svelte/issues/388)) -* Allow reserved words in tags, e.g. `{{class}}` ([#383](https://github.com/sveltejs/svelte/issues/383)) - -## 1.12.0 - -* Shorthand attributes — `<Widget :foo/>` is equivalent to `<Widget foo='{{foo}}'/>` ([#384](https://github.com/sveltejs/svelte/pull/384)) -* Support `bind:group` for radio and checkbox inputs ([#311](https://github.com/sveltejs/svelte/issues/311), [#312](https://github.com/sveltejs/svelte/issues/312)) -* Better sourcemap support for two-way bindings - -## 1.11.4 - -* Dev mode warning for bad `component.observe` arguments ([#369](https://github.com/sveltejs/svelte/issues/369)) -* Translate `component.on('teardown', ...)` to `component.on('destroy', ...)` and add dev warning ([#365](https://github.com/sveltejs/svelte/issues/365)) -* Use shared prototype to save bytes ([#378](https://github.com/sveltejs/svelte/pull/378)) - -## 1.11.3 - -* Undo CSS behaviour change in 1.11.2 ([#372](https://github.com/sveltejs/svelte/issues/372)) -* Pin version of css-tree ([#370](https://github.com/sveltejs/svelte/pull/370)) - -## 1.11.2 - -* Add component CSS to each document a component is rendered to ([#331](https://github.com/sveltejs/svelte/issues/331)) - -## 1.11.1 - -* Fix two-way binding for components inside `each` blocks ([#356](https://github.com/sveltejs/svelte/issues/356)) - -## 1.11.0 - -* Add `format: 'eval'` and `svelte.create`, to create components directly from source code ([#345](https://github.com/sveltejs/svelte/issues/345)) -* Node 4 compatibility ([#109](https://github.com/sveltejs/svelte/issues/109)) - -## 1.10.3 - -* Prevent `'</script>'` string occurence breaking pages ([#349](https://github.com/sveltejs/svelte/pull/349)) -* Allow reference to whitelisted globals without properties ([#333](https://github.com/sveltejs/svelte/pull/333)) -* Don't remove ` ` incorrectly ([#348](https://github.com/sveltejs/svelte/issues/348)) -* `let` -> `var` in `addCss` block ([#351](https://github.com/sveltejs/svelte/pull/351)) - -## 1.10.2 - -* Accept any case for doctype declarations ([#336](https://github.com/sveltejs/svelte/issues/336)) -* Allow non-top-level `<script>` and `<style>` tags to pass through without processing ([#335](https://github.com/sveltejs/svelte/issues/335)) - -## 1.10.1 - -* typecheck argument in _set when in dev mode ([#342](https://github.com/sveltejs/svelte/issues/342)) -* Prevent duplicate helpers in non-shared mode ([#337](https://github.com/sveltejs/svelte/issues/337)) - -## 1.10.0 - -* Component self-references with `<:Self/>` ([#51](https://github.com/sveltejs/svelte/issues/51)) -* Two-way binding with `<select multiple>` ([#313](https://github.com/sveltejs/svelte/issues/313)) - -## 1.9.1 - -* Better error for malformed event handlers ([#220](https://github.com/sveltejs/svelte/issues/220)) -* Allow function expressions in tags ([#269](https://github.com/sveltejs/svelte/issues/269)) - -## 1.9.0 - -* Add development warnings ([#13](https://github.com/sveltejs/svelte/issues/13)), ([#320](https://github.com/sveltejs/svelte/pull/320)), ([#177](https://github.com/sveltejs/svelte/issues/177)), ([#249](https://github.com/sveltejs/svelte/issues/249)) -* Better error if parser encounters an unmatched closing tag ([#321](https://github.com/sveltejs/svelte/issues/321)) - -## 1.8.1 - -* Allow implicitly closed elements ([#318](https://github.com/sveltejs/svelte/pull/318)) -* More informative error messages for unclosed elements/blocks ([#258](https://github.com/sveltejs/svelte/issues/258)) -* Deprecate `onrender` and `onteardown` in favour of `oncreate` and `ondestroy` ([#40](https://github.com/sveltejs/svelte/issues/40)) - -## 1.8.0 - -* Prevent duplicate imports ([#308](https://github.com/sveltejs/svelte/issues/308)) -* Use `input` events (not `change`) for all input elements other than `checkbox` and `radio`, and textareas ([#309](https://github.com/sveltejs/svelte/pull/309)) -* Encapsulate keyframe declarations ([#245](https://github.com/sveltejs/svelte/issues/245)) - -## 1.7.1 - -* Deconflict imports and shared helpers ([#222](https://github.com/sveltejs/svelte/issues/222)) -* Deconflict each-block contexts and reserved words ([#222](https://github.com/sveltejs/svelte/issues/222)) -* Allow shorthand properties in expressions ([#296](https://github.com/sveltejs/svelte/issues/296)) - -## 1.7.0 - -* Include CSS AST in `svelte.parse` output ([#302](https://github.com/sveltejs/svelte/pull/302)) -* Better handling of CSS parse errors ([#302](https://github.com/sveltejs/svelte/pull/302)) -* Initialise `<select>` elements with two-way binding correctly ([#301](https://github.com/sveltejs/svelte/issues/301)) -* Allow local context in component event handlers inside `each` blocks ([#290](https://github.com/sveltejs/svelte/issues/290)) -* Fix two-way binding for components inside `each` blocks ([#290](https://github.com/sveltejs/svelte/issues/290)) - -## 1.6.11 - -* Initialise dynamic `<option>` value correctly ([#291](https://github.com/sveltejs/svelte/issues/291)) - -## 1.6.10 - -* Ensure `sources` and `sourcesContent` are populated in sourcemaps, even if none of the original code is used ([#295](https://github.com/sveltejs/svelte/pull/295)) -* Add `outputFilename` option to populate `file` and `sources` sourcemap properties correctly ([#295](https://github.com/sveltejs/svelte/pull/295)) - -## 1.6.9 - -* Don't trigger bindings for torn-down components ([#277](https://github.com/sveltejs/svelte/issues/277)) -* SSR: Handle two-way bindings ([#275](https://github.com/sveltejs/svelte/issues/275)) -* Improve performance by checking data has changed before updates ([#279](https://github.com/sveltejs/svelte/pull/279)) -* Parse CSS with css-tree to prevent transformation errors with unconventional styles ([#288](https://github.com/sveltejs/svelte/issues/288)) - -## 1.6.8 - -* Always trigger `onrender`, including when change initiator is a nested component ([#263](https://github.com/sveltejs/svelte/issues/263)) -* Handle default function parameters in computations ([#274](https://github.com/sveltejs/svelte/issues/274)) - -## 1.6.7 - -* SSR: Fix apostrophes ([#267](https://github.com/sveltejs/svelte/issues/267)) -* Add `xmlns` attributes to SVGs ([#262](https://github.com/sveltejs/svelte/pull/262)) - -## 1.6.6 - -* Omit text from comment anchors ([#247](https://github.com/sveltejs/svelte/issues/247)) -* Handle `xlink` attributes ([#264](https://github.com/sveltejs/svelte/issues/264)) - -## 1.6.5 - -* Handle `<!doctype>` declarations ([#255](https://github.com/sveltejs/svelte/pull/255)) - -## 1.6.4 - -* Fix updates of yields inside each blocks ([20e1b05](https://github.com/sveltejs/svelte/commit/20e1b05c45dc9fcddfe2e7c5c9fc3109f0d45fa9)) -* SSR: Handle attributes with values that begin with a number ([#248](https://github.com/sveltejs/svelte/issues/248)) -* Handle multiline comments in CSS ([#252](https://github.com/sveltejs/svelte/issues/252)) - -## 1.6.3 - -* Fix `{{yield}}` bugs for components inside `if` and `each` blocks ([#230](https://github.com/sveltejs/svelte/issues/230), [#231](https://github.com/sveltejs/svelte/issues/231)) -* Set attributes on `<svg>` elements correctly ([#233](https://github.com/sveltejs/svelte/issues/233)) -* Add `svelte.VERSION` property to compiler - -## 1.6.2 - -* Use helpers for `addEventListener`, `removeEventListener`, `setAttribute` ([#227](https://github.com/sveltejs/svelte/pull/227)) -* Escape `sharedPath` ([#229](https://github.com/sveltejs/svelte/pull/229)) -* Handle attributes with values that begin with a number ([#234](https://github.com/sveltejs/svelte/issues/234)) -* Update dependencies - -## 1.6.1 - -* SSR: Handle component directives at arbitrary positions ([#221](https://github.com/sveltejs/svelte/issues/221)) -* Provide useful feedback on invalid void closing tag ([#224](https://github.com/sveltejs/svelte/issues/224)) - -## 1.6.0 - -* Replace `standalone: false` with `shared: true`, or `shared: 'custom/path/to/shared.js'` ([#218](https://github.com/sveltejs/svelte/issues/218)) -* Include `shared.js` in package - -## 1.5.0 - -* Implement `standalone: false` ([#9](https://github.com/sveltejs/svelte/issues/9)) -* SSR: Handle component directives ([216](https://github.com/sveltejs/svelte/issues/216)) - -## 1.4.0 - -* Keyed `each` blocks ([#81](https://github.com/sveltejs/svelte/issues/81)) - -## 1.3.1 - -* Remove file extensions from AMD dependencies ([#144](https://github.com/sveltejs/svelte/issues/144)) -* Throw if `options.name` is illegal ([#102](https://github.com/sveltejs/svelte/issues/102)) - -## 1.3.0 - -* SSR compiler: Support `format` option ([#196](https://github.com/sveltejs/svelte/issues/196)) -* SSR compiler: Don't self-close 'normal' elements ([#200](https://github.com/sveltejs/svelte/issues/200)) -* Remove leading spaces from scoped CSS ([#140](https://github.com/sveltejs/svelte/issues/140)) -* Internal refactoring - -## 1.2.5 - -* Allow whitelisted globals in templates ([#185](https://github.com/sveltejs/svelte/issues/185)) -* Intercept parse errors with `options.onerror` - -## 1.2.4 - -* SSR compiler: Implement `{{{triples}}}` ([#197](https://github.com/sveltejs/svelte/issues/197)) -* SSR compiler: Escape HTML in tags ([#197](https://github.com/sveltejs/svelte/issues/197)) - -## 1.2.3 - -* Add support for `namespace` declaration for SVG (etc) components ([#147](https://github.com/sveltejs/svelte/issues/147)) -* Throw error if methods or lifecycle hooks are arrow functions that use `this` or `arguments` ([#179](https://github.com/sveltejs/svelte/issues/179)) -* Use `setAttribute()` for `list` attributes, to preserve link to `<datalist>` ([#178](https://github.com/sveltejs/svelte/issues/178)) -* Throw error if default export is not an object literal ([#190](https://github.com/sveltejs/svelte/pull/190)) -* Internal refactoring - -## 1.2.2 - -* Omit directives in server-side rendering ([#163](https://github.com/sveltejs/svelte/issues/167)) -* Handle comments in SSR ([#165](https://github.com/sveltejs/svelte/issues/165)) -* Support calling methods of `event`/`this` in event handlers ([#162](https://github.com/sveltejs/svelte/issues/162)) -* Remove `mount` from public API ([#150](https://github.com/sveltejs/svelte/issues/150)) - -## 1.2.1 - -* Server-side rendering is available as a compiler option (`generate: 'ssr'`) ([#159](https://github.com/sveltejs/svelte/pull/159)) -* Allow call expressions where function is not in `helpers` ([#163](https://github.com/sveltejs/svelte/issues/163)) - -## 1.2.0 - -* Server-side rendering of HTML ([#148](https://github.com/sveltejs/svelte/pull/148)) and CSS ([#154](https://github.com/sveltejs/svelte/pull/154)) - -## 1.1.3 - -* Handle `xmlns` attributes correctly ([#142](https://github.com/sveltejs/svelte/issues/142)) -* Error on duplicate `<style>`/`<script>` tags rather than failing silently ([#142](https://github.com/sveltejs/svelte/issues/142)) -* Don't create whitespace text nodes inside SVG elements ([#142](https://github.com/sveltejs/svelte/issues/142)) -* Require void elements to be lowercase, to eliminate confusion with components ([#137](https://github.com/sveltejs/svelte/issues/137)) - -## 1.1.2 - -* Deconflict variable names ([#88](https://github.com/sveltejs/svelte/issues/88), [#126](https://github.com/sveltejs/svelte/issues/126)) - -## 1.1.1 - -* Support multiple SVG elements in a component ([#130](https://github.com/sveltejs/svelte/issues/130)) - -## 1.1.0 - -* Separate fragment creation from `mount` ([#91](https://github.com/sveltejs/svelte/pull/91)) -* Trigger `onrender` hook at correct time for nested components ([#103](https://github.com/sveltejs/svelte/pull/103)) -* Fix keypath dynamic attributes in components ([#46](https://github.com/sveltejs/svelte/issues/46)) -* Implement `{{yield}}` ([#112](https://github.com/sveltejs/svelte/pull/112)) -* Optimise teardown ([#99](https://github.com/sveltejs/svelte/issues/99)) -* Require computed properties to have at least one dependency ([#115](https://github.com/sveltejs/svelte/pull/115)) -* Support `{{#each ...}}...{{else}}...{{/each}}` ([#90](https://github.com/sveltejs/svelte/issues/90)) -* Triple mustaches ([#35](https://github.com/sveltejs/svelte/issues/35)) - -## 1.0.7 - -* Correctly escape HTML entities ([#85](https://github.com/sveltejs/svelte/issues/85)) - -## 1.0.6 - -* Generate useful sourcemaps ([#60](https://github.com/sveltejs/svelte/issues/60)) - -## 1.0.5 - -* Ensure compiler only generates ES5 code ([#75](https://github.com/sveltejs/svelte/issues/75)) -* `get()` without arguments returns entire state object ([#73](https://github.com/sveltejs/svelte/issues/73)) - -## 1.0.4 - -* Handle empty attributes in elements and components ([#63](https://github.com/sveltejs/svelte/issues/63)) -* Detach top-level text nodes inside departing each blocks ([#62](https://github.com/sveltejs/svelte/issues/62)) - -## 1.0.3 - -* Better generated code for `if` blocks, especially with `else`/`elseif` chains ([#28](https://github.com/sveltejs/svelte/pull/28)) -* Trim unnecessary whitespace from `else`/`elseif` blocks ([#49](https://github.com/sveltejs/svelte/pull/49)) -* Handle trailing comments in script tags ([#64](https://github.com/sveltejs/svelte/issues/64)) - -## 1.0.2 - -Set `style.cssText` rather than `style` ([#44](https://github.com/sveltejs/svelte/issues/44)) - -## 1.0.1 - -* Preserve SVG namespace inside each blocks -* Always use `setAttribute` with SVG elements - -## 1.0.0 - -* Generate AMD, CJS, IIFE and UMD builds -* Correctly insert text nodes before anchors ([#31](https://github.com/sveltejs/svelte/pull/31)) - -## 0.3.0 - -* Fix bug where departing element would unset `ref` incorrectly ([#24](https://github.com/sveltejs/svelte/issues/24)) -* Basic template validation ([#6](https://github.com/sveltejs/svelte/issues/6)) -* Fire `onrender` hooks once component is in DOM ([#18](https://github.com/sveltejs/svelte/issues/18)) -* Only detach nodes when necessary to do so ([#26](https://github.com/sveltejs/svelte/issues/26)) - -## 0.2.2 - -* On second thoughts, don't transpile build. Was only really for Uglify's benefit, which is daft - -## 0.2.1 - -* Transpile build - -## 0.2.0 - -* Only generate UMD build, for now -* Include dependencies in the build, treat as `devDependencies` -* Faster initial render -* Parent data overrides child defaults -* Remove top-level text nodes on teardown -* Handle `readUntil` errors in parser -* Basic `<select>` binding -* Handle missing data -* Prevent infinite set/observe loops -* Add `bind:foo` shorthand -* `else` and `elseif` blocks -* Hoist imports - -## 0.1.1 - -* Support unquoted attributes -* Handle entities in attributes -* Inline nested components -* `fire` and `on` methods - -## 0.1.0 - -* Breaking change – Svelte compiler now generates constructor functions rather than factories ([#2](https://github.com/sveltejs/svelte/issues/2)) -* SVG support - -## 0.0.2 - -* First release capable of building TodoMVC - -## 0.0.1 - -* Just squatting on the package name diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000000..65d86fe76ab7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +This repository is governed by the Svelte Code of Conduct. + +https://github.com/sveltejs/community/blob/main/CODE_OF_CONDUCT.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000000..0e2628f84f77 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,171 @@ +# Contributing to Svelte + +Svelte is a new way to build web applications. It's a compiler that takes your declarative components and converts them into efficient JavaScript that surgically updates the DOM. + +The [Open Source Guides](https://opensource.guide/) website has a collection of resources for individuals, communities, and companies. These resources help people who want to learn how to run and contribute to open source projects. Contributors and people new to open source alike will find the following guides especially useful: + +- [How to Contribute to Open Source](https://opensource.guide/how-to-contribute/) +- [Building Welcoming Communities](https://opensource.guide/building-community/) + +## Get involved + +There are many ways to contribute to Svelte, and many of them do not involve writing any code. Here's a few ideas to get started: + +- Simply start using Svelte. Go through the [Getting Started](https://svelte.dev/docs#getting-started) guide. Does everything work as expected? If not, we're always looking for improvements. Let us know by [opening an issue](#reporting-new-issues). +- Look through the [open issues](https://github.com/sveltejs/svelte/issues). A good starting point would be issues tagged [good first issue](https://github.com/sveltejs/svelte/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). Provide workarounds, ask for clarification, or suggest labels. Help [triage issues](#triaging-issues-and-pull-requests). +- If you find an issue you would like to fix, [open a pull request](#pull-requests). +- Read through our [tutorials](https://svelte.dev/tutorial). If you find anything that is confusing or can be improved, you can make edits by clicking "Edit this page" at the bottom left of the tutorial page. +- Take a look at the [features requested](https://github.com/sveltejs/svelte/labels/feature%20request) by others in the community and consider opening a pull request if you see something you want to work on. + +Contributions are very welcome. If you think you need help planning your contribution, please ping us on Discord at [svelte.dev/chat](https://svelte.dev/chat) and let us know you are looking for a bit of help. + +### Triaging issues and pull requests + +One great way you can contribute to the project without writing any code is to help triage issues and pull requests as they come in. + +- Ask for more information if you believe the issue does not provide all the details required to solve it. +- Flag issues that are stale or that should be closed. +- Ask for test plans and review code. + +## Our process + +### RFCs + +If you'd like to propose an implementation for a large new feature or change then please [create an RFC](https://github.com/sveltejs/rfcs) to discuss it up front. + +### Roadmap + +When deciding where to contribute, you may wish to take a look at [our roadmap](https://svelte.dev/roadmap). The Svelte team generally works on a single major effort at a time. This has a couple benefits for us as maintainers. First, it allows us to focus and make noticeable progress in an area being proactive rather than reactive. Secondly, it allows us to handle related issues and PRs together. By batching issues and PRs together we’re able to ensure implementations and fixes holistically address the set of problems and use cases encountered by our users. + +### Maintainer meetings + +The maintainers meet on the final Saturday of each month. While these meetings are not open publicly, we will report back by leaving a comment on each issue discussed. We will generally discuss items aligning with our roadmap, but major PRs needing discussion amongst the maintainers can be added to the agenda for the monthly maintainer’s meeting. However, we typically are only able to get to a couple of items that are not aligned with our current priority. + +### Prioritization + +We do our best to review PRs and RFCs as they are sent, but it is difficult to keep up. We welcome help in reviewing PRs, RFCs, and issues. If an item aligns with the current priority on our [roadmap](https://svelte.dev/roadmap), it is more likely to be reviewed quickly. PRs to the most important and active ones repositories get reviewed more quickly while PRs to smaller inactive repos may sit for a bit before we periodically come by and review the pending PRs in a batch. + +## Bugs + +We use [GitHub issues](https://github.com/sveltejs/svelte/issues) for our public bugs. If you would like to report a problem, take a look around and see if someone already opened an issue about it. If you are certain this is a new unreported bug, you can submit a [bug report](#reporting-new-issues). + +If you have questions about using Svelte, contact us on Discord at [svelte.dev/chat](https://svelte.dev/chat), and we will do our best to answer your questions. + +If you see anything you'd like to be implemented, create a [feature request issue](https://github.com/sveltejs/svelte/issues/new?template=feature_request.yml). + +### Reporting new issues + +When [opening a new issue](https://github.com/sveltejs/svelte/issues/new/choose), always make sure to fill out the issue template. **This step is very important!** Not doing so may result in your issue not being managed in a timely fashion. Don't take this personally if this happens, and feel free to open a new issue once you've gathered all the information required by the template. + +- **One issue, one bug:** Please report a single bug per issue. +- **Provide reproduction steps:** List all the steps necessary to reproduce the issue. The person reading your bug report should be able to follow these steps to reproduce your issue with minimal effort. If possible, use the [REPL](https://svelte.dev/repl) to create your reproduction. + +## Pull requests + +### Proposing a change + +If you would like to request a new feature or enhancement but are not yet thinking about opening a pull request, you can also file an issue with [feature template](https://github.com/sveltejs/svelte/issues/new?template=feature_request.yml). + +If you're only fixing a bug, it's fine to submit a pull request right away, but we still recommend that you file an issue detailing what you're fixing. This is helpful in case we don't accept that specific fix but want to keep track of the issue. + +Small pull requests are much easier to review and more likely to get merged. + +### Installation + +Ensure you have [pnpm](https://pnpm.io/installation) installed. After cloning the repository, run `pnpm install`. + +### Developing + +To build the UMD version of `svelte/compiler` (this is only necessary for CommonJS consumers, or in-browser use), run `pnpm build` inside `packages/svelte`. To rebuild whenever source files change, run `pnpm dev`. + +### Creating a branch + +Fork [the repository](https://github.com/sveltejs/svelte) and create your branch from `main`. If you've never sent a GitHub pull request before, you can learn how from [this free video series](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github). + +### Testing + +A good test plan has the exact commands you ran and their output, provides screenshots or videos if the pull request changes UI. + +- If you've changed APIs, update the documentation. + +#### Writing tests + +All tests are located in `/test` folder. + +Test samples are kept in `/test/xxx/samples` folder. + +#### Running tests + +> PREREQUISITE: Install chromium via playwright by running `pnpm playwright install chromium` + +1. To run test, run `pnpm test`. +1. To run a particular test suite, use `pnpm test <suite-name>`, for example: + + ```bash + pnpm test validator + ``` + +1. To filter tests _within_ a test suite, use `pnpm test <suite-name> -- -t <test-name>`, for example: + + ```bash + pnpm test validator -- -t a11y-alt-text + ``` + + (You can also do `FILTER=<test-name> pnpm test <suite-name>` which removes other tests rather than simply skipping them — this will result in faster and more compact test results, but it's non-idiomatic. Choose your fighter.) + +##### Updating `.expected` files + +1. Tests suites like `snapshot` and `parser` assert that the generated output matches the existing snapshot. +1. To update these snapshots, run `UPDATE_SNAPSHOTS=true pnpm test`. + +### Typechecking + +To typecheck the codebase, run `pnpm check` inside `packages/svelte`. To typecheck in watch mode, run `pnpm check:watch`. + +### Style guide + +[Eslint](https://eslint.org) will catch most styling issues that may exist in your code. You can check the status of your code styling by simply running `pnpm lint`. + +#### Code conventions + +- `snake_case` for internal variable names and methods. +- `camelCase` for public variable names and methods. + +### Generating types + +Types are auto-generated from the source, but the result is checked in to ensure no accidental changes slip through. Run `pnpm generate:types` to regenerate the types. + +### Sending your pull request + +Please make sure the following is done when submitting a pull request: + +1. Describe your **test plan** in your pull request description. Make sure to test your changes. +1. Make sure your code lints (`pnpm lint`). +1. Make sure your tests pass (`pnpm test`). + +All pull requests should be opened against the `main` branch. Make sure the PR does only one thing, otherwise please split it. If this change should contribute to a version bump, run `npx changeset` at the root of the repository after a code change and select the appropriate packages. + +#### Breaking changes + +When adding a new breaking change, follow this template in your pull request: + +```md +### New breaking change here + +- **Who does this affect**: +- **How to migrate**: +- **Why make this breaking change**: +- **Severity (number of people affected x effort)**: +``` + +### Reviewing pull requests + +If you'd like to manually test a pull request in another pnpm project, you can do so by running `pnpm add -D "github:sveltejs/svelte#path:packages/svelte&branch-name"` in that project. + +## License + +By contributing to Svelte, you agree that your contributions will be licensed under its [MIT license](https://github.com/sveltejs/svelte/blob/master/LICENSE.md). + +## Questions + +Feel free to ask in [#contributing](https://discord.com/channels/457912077277855764/750401468569354431) on [Discord](https://svelte.dev/chat) if you have questions about our process, how to proceed, etc. diff --git a/FUNDING.json b/FUNDING.json new file mode 100644 index 000000000000..7ed51db691e6 --- /dev/null +++ b/FUNDING.json @@ -0,0 +1,7 @@ +{ + "drips": { + "ethereum": { + "ownedBy": "0xCE08E02c37d90d75C2bf7D9e55f7606C8DB80E70" + } + } +} diff --git a/LICENSE b/LICENSE deleted file mode 100644 index b63fe48148fa..000000000000 --- a/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -Copyright (c) 2016-19 [these people](https://github.com/sveltejs/svelte/graphs/contributors) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000000..f872adf738de --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,7 @@ +Copyright (c) 2016-2025 [Svelte Contributors](https://github.com/sveltejs/svelte/graphs/contributors) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index dc747668b0c3..7ea71647521a 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,11 @@ -<p> - <a href="https://svelte.dev"> - <img alt="Cybernetically enhanced web apps: Svelte" src="https://svelte-assets.surge.sh/banner.png"> - </a> - - <a href="https://www.npmjs.com/package/svelte"> - <img src="https://img.shields.io/npm/v/svelte.svg" alt="npm version"> - </a> - - <a href="https://packagephobia.now.sh/result?p=svelte"> - <img src="https://packagephobia.now.sh/badge?p=svelte" alt="install size"> - </a> - - <a href="https://travis-ci.org/sveltejs/svelte"> - <img src="https://api.travis-ci.org/sveltejs/svelte.svg?branch=master" - alt="build status"> - </a> - - <a href="https://github.com/sveltejs/svelte/blob/master/LICENSE"> - <img src="https://img.shields.io/npm/l/svelte.svg" alt="license"> - </a> -</p> +<a href="https://svelte.dev"> + <picture> + <source media="(prefers-color-scheme: dark)" srcset="assets/banner_dark.png"> + <img src="assets/banner.png" alt="Svelte - web development for the rest of us" /> + </picture> +</a> +[![License](https://img.shields.io/npm/l/svelte.svg)](LICENSE.md) [![Chat](https://img.shields.io/discord/457912077277855764?label=chat&logo=discord)](https://svelte.dev/chat) ## What is Svelte? @@ -28,63 +13,26 @@ Svelte is a new way to build web applications. It's a compiler that takes your d Learn more at the [Svelte website](https://svelte.dev), or stop by the [Discord chatroom](https://svelte.dev/chat). +## Supporting Svelte -## Development - -Pull requests are encouraged and always welcome. [Pick an issue](https://github.com/sveltejs/svelte/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc) and help us out! - -To install and work on Svelte locally: - -```bash -git clone https://github.com/sveltejs/svelte.git -cd svelte -npm install -``` - -> Many tests depend on newlines being preserved as `<LF>`. On Windows, you can ensure this by cloning with: -> ```bash -> git -c core.autocrlf=false clone https://github.com/sveltejs/svelte.git -> ``` - -To build the compiler, and all the other modules included in the package: - -```bash -npm run build -``` - -To watch for changes and continually rebuild the package (this is useful if you're using [npm link](https://docs.npmjs.com/cli/link.html) to test out changes in a project locally): - -```bash -npm run dev -``` - -The compiler is written in [TypeScript](https://www.typescriptlang.org/), but don't let that put you off — it's basically just JavaScript with type annotations. You'll pick it up in no time. If you're using an editor other than [Visual Studio Code](https://code.visualstudio.com/) you may need to install a plugin in order to get syntax highlighting and code hints etc. - - -### Running Tests +Svelte is an MIT-licensed open source project with its ongoing development made possible entirely by fantastic volunteers. If you'd like to support their efforts, please consider: -```bash -npm run test -``` +- [Becoming a backer on Open Collective](https://opencollective.com/svelte). -To filter tests, use `-g` (aka `--grep`). For example, to only run tests involving transitions: +Funds donated via Open Collective will be used for compensating expenses related to Svelte's development such as hosting costs. If sufficient donations are received, funds may also be used to support Svelte's development more directly. -```bash -npm run test -- -g transition -``` +## Roadmap +You may view [our roadmap](https://svelte.dev/roadmap) if you'd like to see what we're currently working on. -## svelte.dev +## Contributing -The source code for https://svelte.dev, including all the documentation, lives in the [site](site) directory. The site is built with [Sapper](https://sapper.svelte.dev). To develop locally: +Please see the [Contributing Guide](CONTRIBUTING.md) and the [`svelte`](packages/svelte) package for information on contributing to Svelte. -```bash -cd site -npm install && npm run update -npm run dev -``` +## Is svelte.dev down? +Probably not, but it's possible. If you can't seem to access any `.dev` sites, check out [this SuperUser question and answer](https://superuser.com/q/1413402). ## License -[MIT](LICENSE) +[MIT](LICENSE.md) diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 23a3ac3505cc..000000000000 --- a/appveyor.yml +++ /dev/null @@ -1,31 +0,0 @@ -# http://www.appveyor.com/docs/appveyor-yml - -version: "{build}" - -clone_depth: 10 - -init: - - git config --global core.autocrlf false - -environment: - matrix: - - nodejs_version: 8 - - nodejs_version: 10 - - nodejs_version: 12 - -install: - - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) - - npm ci || npm install - -build: off - -test_script: - - node --version && npm --version - - npm test - -matrix: - fast_finish: false - -# cache: -# - C:\Users\appveyor\AppData\Roaming\npm-cache -> package.json # npm cache -# - node_modules -> package.json # local npm modules diff --git a/assets/banner.png b/assets/banner.png new file mode 100644 index 000000000000..3428b278bfa3 Binary files /dev/null and b/assets/banner.png differ diff --git a/assets/banner_dark.png b/assets/banner_dark.png new file mode 100644 index 000000000000..1adba40d8e2f Binary files /dev/null and b/assets/banner_dark.png differ diff --git a/banner.png b/banner.png deleted file mode 100644 index 0d117c3c09d4..000000000000 Binary files a/banner.png and /dev/null differ diff --git a/benchmarking/.gitignore b/benchmarking/.gitignore new file mode 100644 index 000000000000..53752db253e3 --- /dev/null +++ b/benchmarking/.gitignore @@ -0,0 +1 @@ +output diff --git a/benchmarking/benchmarks/reactivity/index.js b/benchmarking/benchmarks/reactivity/index.js new file mode 100644 index 000000000000..58b3f5cb295b --- /dev/null +++ b/benchmarking/benchmarks/reactivity/index.js @@ -0,0 +1,55 @@ +import { kairo_avoidable_owned, kairo_avoidable_unowned } from './kairo/kairo_avoidable.js'; +import { kairo_broad_owned, kairo_broad_unowned } from './kairo/kairo_broad.js'; +import { kairo_deep_owned, kairo_deep_unowned } from './kairo/kairo_deep.js'; +import { kairo_diamond_owned, kairo_diamond_unowned } from './kairo/kairo_diamond.js'; +import { kairo_mux_unowned, kairo_mux_owned } from './kairo/kairo_mux.js'; +import { kairo_repeated_unowned, kairo_repeated_owned } from './kairo/kairo_repeated.js'; +import { kairo_triangle_owned, kairo_triangle_unowned } from './kairo/kairo_triangle.js'; +import { kairo_unstable_owned, kairo_unstable_unowned } from './kairo/kairo_unstable.js'; +import { mol_bench_owned, mol_bench_unowned } from './mol_bench.js'; +import { + sbench_create_0to1, + sbench_create_1000to1, + sbench_create_1to1, + sbench_create_1to1000, + sbench_create_1to2, + sbench_create_1to4, + sbench_create_1to8, + sbench_create_2to1, + sbench_create_4to1, + sbench_create_signals +} from './sbench.js'; + +// This benchmark has been adapted from the js-reactivity-benchmark (https://github.com/milomg/js-reactivity-benchmark) +// Not all tests are the same, and many parts have been tweaked to capture different data. + +export const reactivity_benchmarks = [ + sbench_create_signals, + sbench_create_0to1, + sbench_create_1to1, + sbench_create_2to1, + sbench_create_4to1, + sbench_create_1000to1, + sbench_create_1to2, + sbench_create_1to4, + sbench_create_1to8, + sbench_create_1to1000, + kairo_avoidable_owned, + kairo_avoidable_unowned, + kairo_broad_owned, + kairo_broad_unowned, + kairo_deep_owned, + kairo_deep_unowned, + kairo_diamond_owned, + kairo_diamond_unowned, + kairo_triangle_owned, + kairo_triangle_unowned, + kairo_mux_owned, + kairo_mux_unowned, + kairo_repeated_owned, + kairo_repeated_unowned, + kairo_unstable_owned, + kairo_unstable_unowned, + mol_bench_owned, + mol_bench_unowned +]; diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js b/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js new file mode 100644 index 000000000000..9daea6de99cb --- /dev/null +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_avoidable.js @@ -0,0 +1,91 @@ +import { assert, fastest_test } from '../../../utils.js'; +import * as $ from 'svelte/internal/client'; +import { busy } from './util.js'; + +function setup() { + let head = $.state(0); + let computed1 = $.derived(() => $.get(head)); + let computed2 = $.derived(() => ($.get(computed1), 0)); + let computed3 = $.derived(() => (busy(), $.get(computed2) + 1)); // heavy computation + let computed4 = $.derived(() => $.get(computed3) + 2); + let computed5 = $.derived(() => $.get(computed4) + 3); + + const destroy = $.effect_root(() => { + $.render_effect(() => { + $.get(computed5); + busy(); // heavy side effect + }); + }); + + return { + destroy, + run() { + $.flush(() => { + $.set(head, 1); + }); + assert($.get(computed5) === 6); + for (let i = 0; i < 1000; i++) { + $.flush(() => { + $.set(head, i); + }); + assert($.get(computed5) === 6); + } + } + }; +} + +export async function kairo_avoidable_unowned() { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + const { run, destroy } = setup(); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + destroy(); + + return { + benchmark: 'kairo_avoidable_unowned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function kairo_avoidable_owned() { + let run, destroy; + + const destroy_owned = $.effect_root(() => { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + ({ run, destroy } = setup()); + }); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + // @ts-ignore + destroy(); + destroy_owned(); + + return { + benchmark: 'kairo_avoidable_owned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js b/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js new file mode 100644 index 000000000000..8dc5710c87db --- /dev/null +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_broad.js @@ -0,0 +1,97 @@ +import { assert, fastest_test } from '../../../utils.js'; +import * as $ from 'svelte/internal/client'; + +function setup() { + let head = $.state(0); + let last = head; + let counter = 0; + + const destroy = $.effect_root(() => { + for (let i = 0; i < 50; i++) { + let current = $.derived(() => { + return $.get(head) + i; + }); + let current2 = $.derived(() => { + return $.get(current) + 1; + }); + $.render_effect(() => { + $.get(current2); + counter++; + }); + last = current2; + } + }); + + return { + destroy, + run() { + $.flush(() => { + $.set(head, 1); + }); + counter = 0; + for (let i = 0; i < 50; i++) { + $.flush(() => { + $.set(head, i); + }); + assert($.get(last) === i + 50); + } + assert(counter === 50 * 50); + } + }; +} + +export async function kairo_broad_unowned() { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + const { run, destroy } = setup(); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + destroy(); + + return { + benchmark: 'kairo_broad_unowned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function kairo_broad_owned() { + let run, destroy; + + const destroy_owned = $.effect_root(() => { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + ({ run, destroy } = setup()); + }); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + // @ts-ignore + destroy(); + destroy_owned(); + + return { + benchmark: 'kairo_broad_owned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js b/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js new file mode 100644 index 000000000000..8690c85f864a --- /dev/null +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_deep.js @@ -0,0 +1,97 @@ +import { assert, fastest_test } from '../../../utils.js'; +import * as $ from 'svelte/internal/client'; + +let len = 50; +const iter = 50; + +function setup() { + let head = $.state(0); + let current = head; + for (let i = 0; i < len; i++) { + let c = current; + current = $.derived(() => { + return $.get(c) + 1; + }); + } + let counter = 0; + + const destroy = $.effect_root(() => { + $.render_effect(() => { + $.get(current); + counter++; + }); + }); + + return { + destroy, + run() { + $.flush(() => { + $.set(head, 1); + }); + counter = 0; + for (let i = 0; i < iter; i++) { + $.flush(() => { + $.set(head, i); + }); + assert($.get(current) === len + i); + } + assert(counter === iter); + } + }; +} + +export async function kairo_deep_unowned() { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + const { run, destroy } = setup(); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + destroy(); + + return { + benchmark: 'kairo_deep_unowned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function kairo_deep_owned() { + let run, destroy; + + const destroy_owned = $.effect_root(() => { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + ({ run, destroy } = setup()); + }); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + // @ts-ignore + destroy(); + destroy_owned(); + + return { + benchmark: 'kairo_deep_owned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js b/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js new file mode 100644 index 000000000000..bf4e07ee8962 --- /dev/null +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_diamond.js @@ -0,0 +1,101 @@ +import { assert, fastest_test } from '../../../utils.js'; +import * as $ from 'svelte/internal/client'; + +let width = 5; + +function setup() { + let head = $.state(0); + let current = []; + for (let i = 0; i < width; i++) { + current.push( + $.derived(() => { + return $.get(head) + 1; + }) + ); + } + let sum = $.derived(() => { + return current.map((x) => $.get(x)).reduce((a, b) => a + b, 0); + }); + let counter = 0; + + const destroy = $.effect_root(() => { + $.render_effect(() => { + $.get(sum); + counter++; + }); + }); + + return { + destroy, + run() { + $.flush(() => { + $.set(head, 1); + }); + assert($.get(sum) === 2 * width); + counter = 0; + for (let i = 0; i < 500; i++) { + $.flush(() => { + $.set(head, i); + }); + assert($.get(sum) === (i + 1) * width); + } + assert(counter === 500); + } + }; +} + +export async function kairo_diamond_unowned() { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + const { run, destroy } = setup(); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + destroy(); + + return { + benchmark: 'kairo_diamond_unowned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function kairo_diamond_owned() { + let run, destroy; + + const destroy_owned = $.effect_root(() => { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + ({ run, destroy } = setup()); + }); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + // @ts-ignore + destroy(); + destroy_owned(); + + return { + benchmark: 'kairo_diamond_owned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js b/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js new file mode 100644 index 000000000000..fc252a27b5f8 --- /dev/null +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_mux.js @@ -0,0 +1,94 @@ +import { assert, fastest_test } from '../../../utils.js'; +import * as $ from 'svelte/internal/client'; + +function setup() { + let heads = new Array(100).fill(null).map((_) => $.state(0)); + const mux = $.derived(() => { + return Object.fromEntries(heads.map((h) => $.get(h)).entries()); + }); + const splited = heads + .map((_, index) => $.derived(() => $.get(mux)[index])) + .map((x) => $.derived(() => $.get(x) + 1)); + + const destroy = $.effect_root(() => { + splited.forEach((x) => { + $.render_effect(() => { + $.get(x); + }); + }); + }); + + return { + destroy, + run() { + for (let i = 0; i < 10; i++) { + $.flush(() => { + $.set(heads[i], i); + }); + assert($.get(splited[i]) === i + 1); + } + for (let i = 0; i < 10; i++) { + $.flush(() => { + $.set(heads[i], i * 2); + }); + assert($.get(splited[i]) === i * 2 + 1); + } + } + }; +} + +export async function kairo_mux_unowned() { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + const { run, destroy } = setup(); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + destroy(); + + return { + benchmark: 'kairo_mux_unowned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function kairo_mux_owned() { + let run, destroy; + + const destroy_owned = $.effect_root(() => { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + ({ run, destroy } = setup()); + }); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + // @ts-ignore + destroy(); + destroy_owned(); + + return { + benchmark: 'kairo_mux_owned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js b/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js new file mode 100644 index 000000000000..3bee06ca0e8f --- /dev/null +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_repeated.js @@ -0,0 +1,98 @@ +import { assert, fastest_test } from '../../../utils.js'; +import * as $ from 'svelte/internal/client'; + +let size = 30; + +function setup() { + let head = $.state(0); + let current = $.derived(() => { + let result = 0; + for (let i = 0; i < size; i++) { + result += $.get(head); + } + return result; + }); + + let counter = 0; + + const destroy = $.effect_root(() => { + $.render_effect(() => { + $.get(current); + counter++; + }); + }); + + return { + destroy, + run() { + $.flush(() => { + $.set(head, 1); + }); + assert($.get(current) === size); + counter = 0; + for (let i = 0; i < 100; i++) { + $.flush(() => { + $.set(head, i); + }); + assert($.get(current) === i * size); + } + assert(counter === 100); + } + }; +} + +export async function kairo_repeated_unowned() { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + const { run, destroy } = setup(); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + destroy(); + + return { + benchmark: 'kairo_repeated_unowned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function kairo_repeated_owned() { + let run, destroy; + + const destroy_owned = $.effect_root(() => { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + ({ run, destroy } = setup()); + }); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + // @ts-ignore + destroy(); + destroy_owned(); + + return { + benchmark: 'kairo_repeated_owned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js b/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js new file mode 100644 index 000000000000..11a419a52e7b --- /dev/null +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_triangle.js @@ -0,0 +1,111 @@ +import { assert, fastest_test } from '../../../utils.js'; +import * as $ from 'svelte/internal/client'; + +let width = 10; + +function count(number) { + return new Array(number) + .fill(0) + .map((_, i) => i + 1) + .reduce((x, y) => x + y, 0); +} + +function setup() { + let head = $.state(0); + let current = head; + let list = []; + for (let i = 0; i < width; i++) { + let c = current; + list.push(current); + current = $.derived(() => { + return $.get(c) + 1; + }); + } + let sum = $.derived(() => { + return list.map((x) => $.get(x)).reduce((a, b) => a + b, 0); + }); + + let counter = 0; + + const destroy = $.effect_root(() => { + $.render_effect(() => { + $.get(sum); + counter++; + }); + }); + + return { + destroy, + run() { + const constant = count(width); + $.flush(() => { + $.set(head, 1); + }); + assert($.get(sum) === constant); + counter = 0; + for (let i = 0; i < 100; i++) { + $.flush(() => { + $.set(head, i); + }); + assert($.get(sum) === constant - width + i * width); + } + assert(counter === 100); + } + }; +} + +export async function kairo_triangle_unowned() { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + const { run, destroy } = setup(); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + destroy(); + + return { + benchmark: 'kairo_triangle_unowned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function kairo_triangle_owned() { + let run, destroy; + + const destroy_owned = $.effect_root(() => { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + ({ run, destroy } = setup()); + }); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + // @ts-ignore + destroy(); + destroy_owned(); + + return { + benchmark: 'kairo_triangle_owned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js b/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js new file mode 100644 index 000000000000..54eb732cb29d --- /dev/null +++ b/benchmarking/benchmarks/reactivity/kairo/kairo_unstable.js @@ -0,0 +1,97 @@ +import { assert, fastest_test } from '../../../utils.js'; +import * as $ from 'svelte/internal/client'; + +function setup() { + let head = $.state(0); + const double = $.derived(() => $.get(head) * 2); + const inverse = $.derived(() => -$.get(head)); + let current = $.derived(() => { + let result = 0; + for (let i = 0; i < 20; i++) { + result += $.get(head) % 2 ? $.get(double) : $.get(inverse); + } + return result; + }); + + let counter = 0; + + const destroy = $.effect_root(() => { + $.render_effect(() => { + $.get(current); + counter++; + }); + }); + + return { + destroy, + run() { + $.flush(() => { + $.set(head, 1); + }); + assert($.get(current) === 40); + counter = 0; + for (let i = 0; i < 100; i++) { + $.flush(() => { + $.set(head, i); + }); + } + assert(counter === 100); + } + }; +} + +export async function kairo_unstable_unowned() { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + const { run, destroy } = setup(); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + destroy(); + + return { + benchmark: 'kairo_unstable_unowned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function kairo_unstable_owned() { + let run, destroy; + + const destroy_owned = $.effect_root(() => { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(); + destroy(); + } + + ({ run, destroy } = setup()); + }); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1000; i++) { + run(); + } + }); + + // @ts-ignore + destroy(); + destroy_owned(); + + return { + benchmark: 'kairo_unstable_owned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/benchmarks/reactivity/kairo/util.js b/benchmarking/benchmarks/reactivity/kairo/util.js new file mode 100644 index 000000000000..75e3641ab964 --- /dev/null +++ b/benchmarking/benchmarks/reactivity/kairo/util.js @@ -0,0 +1,6 @@ +export function busy() { + let a = 0; + for (let i = 0; i < 1_00; i++) { + a++; + } +} diff --git a/benchmarking/benchmarks/reactivity/mol_bench.js b/benchmarking/benchmarks/reactivity/mol_bench.js new file mode 100644 index 000000000000..536b078d74a4 --- /dev/null +++ b/benchmarking/benchmarks/reactivity/mol_bench.js @@ -0,0 +1,121 @@ +import { assert, fastest_test } from '../../utils.js'; +import * as $ from 'svelte/internal/client'; + +/** + * @param {number} n + */ +function fib(n) { + if (n < 2) return 1; + return fib(n - 1) + fib(n - 2); +} + +/** + * @param {number} n + */ +function hard(n) { + return n + fib(16); +} + +const numbers = Array.from({ length: 5 }, (_, i) => i); + +function setup() { + let res = []; + const A = $.state(0); + const B = $.state(0); + const C = $.derived(() => ($.get(A) % 2) + ($.get(B) % 2)); + const D = $.derived(() => numbers.map((i) => i + ($.get(A) % 2) - ($.get(B) % 2))); + D.equals = function (/** @type {number[]} */ l) { + var r = this.v; + return r !== null && l.length === r.length && l.every((v, i) => v === r[i]); + }; + const E = $.derived(() => hard($.get(C) + $.get(A) + $.get(D)[0])); + const F = $.derived(() => hard($.get(D)[0] && $.get(B))); + const G = $.derived(() => $.get(C) + ($.get(C) || $.get(E) % 2) + $.get(D)[0] + $.get(F)); + + const destroy = $.effect_root(() => { + $.render_effect(() => { + res.push(hard($.get(G))); + }); + $.render_effect(() => { + res.push($.get(G)); + }); + $.render_effect(() => { + res.push(hard($.get(F))); + }); + }); + + return { + destroy, + /** + * @param {number} i + */ + run(i) { + res.length = 0; + $.flush(() => { + $.set(B, 1); + $.set(A, 1 + i * 2); + }); + $.flush(() => { + $.set(A, 2 + i * 2); + $.set(B, 2); + }); + assert(res[0] === 3198 && res[1] === 1601 && res[2] === 3195 && res[3] === 1598); + } + }; +} + +export async function mol_bench_owned() { + let run, destroy; + + const destroy_owned = $.effect_root(() => { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(0); + destroy(); + } + + ({ run, destroy } = setup()); + }); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1e4; i++) { + run(i); + } + }); + + // @ts-ignore + destroy(); + destroy_owned(); + + return { + benchmark: 'mol_bench_owned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function mol_bench_unowned() { + // Do 10 loops to warm up JIT + for (let i = 0; i < 10; i++) { + const { run, destroy } = setup(); + run(0); + destroy(); + } + + const { run, destroy } = setup(); + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 1e4; i++) { + run(i); + } + }); + + destroy(); + + return { + benchmark: 'mol_bench_unowned', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/benchmarks/reactivity/sbench.js b/benchmarking/benchmarks/reactivity/sbench.js new file mode 100644 index 000000000000..ddeaef251485 --- /dev/null +++ b/benchmarking/benchmarks/reactivity/sbench.js @@ -0,0 +1,366 @@ +import { fastest_test } from '../../utils.js'; +import * as $ from '../../../packages/svelte/src/internal/client/index.js'; + +const COUNT = 1e5; + +/** + * @param {number} n + * @param {any[]} sources + */ +function create_data_signals(n, sources) { + for (let i = 0; i < n; i++) { + sources[i] = $.state(i); + } + return sources; +} + +/** + * @param {number} i + */ +function create_computation_0(i) { + $.derived(() => i); +} + +/** + * @param {any} s1 + */ +function create_computation_1(s1) { + $.derived(() => $.get(s1)); +} +/** + * @param {any} s1 + * @param {any} s2 + */ +function create_computation_2(s1, s2) { + $.derived(() => $.get(s1) + $.get(s2)); +} + +function create_computation_1000(ss, offset) { + $.derived(() => { + let sum = 0; + for (let i = 0; i < 1000; i++) { + sum += $.get(ss[offset + i]); + } + return sum; + }); +} + +/** + * @param {number} n + */ +function create_computations_0to1(n) { + for (let i = 0; i < n; i++) { + create_computation_0(i); + } +} + +/** + * @param {number} n + * @param {any[]} sources + */ +function create_computations_1to1(n, sources) { + for (let i = 0; i < n; i++) { + const source = sources[i]; + create_computation_1(source); + } +} + +/** + * @param {number} n + * @param {any[]} sources + */ +function create_computations_2to1(n, sources) { + for (let i = 0; i < n; i++) { + create_computation_2(sources[i * 2], sources[i * 2 + 1]); + } +} + +function create_computation_4(s1, s2, s3, s4) { + $.derived(() => $.get(s1) + $.get(s2) + $.get(s3) + $.get(s4)); +} + +function create_computations_1000to1(n, sources) { + for (let i = 0; i < n; i++) { + create_computation_1000(sources, i * 1000); + } +} + +function create_computations_1to2(n, sources) { + for (let i = 0; i < n / 2; i++) { + const source = sources[i]; + create_computation_1(source); + create_computation_1(source); + } +} + +function create_computations_1to4(n, sources) { + for (let i = 0; i < n / 4; i++) { + const source = sources[i]; + create_computation_1(source); + create_computation_1(source); + create_computation_1(source); + create_computation_1(source); + } +} + +function create_computations_1to8(n, sources) { + for (let i = 0; i < n / 8; i++) { + const source = sources[i]; + create_computation_1(source); + create_computation_1(source); + create_computation_1(source); + create_computation_1(source); + create_computation_1(source); + create_computation_1(source); + create_computation_1(source); + create_computation_1(source); + } +} + +function create_computations_1to1000(n, sources) { + for (let i = 0; i < n / 1000; i++) { + const source = sources[i]; + for (let j = 0; j < 1000; j++) { + create_computation_1(source); + } + } +} + +function create_computations_4to1(n, sources) { + for (let i = 0; i < n; i++) { + create_computation_4( + sources[i * 4], + sources[i * 4 + 1], + sources[i * 4 + 2], + sources[i * 4 + 3] + ); + } +} + +/** + * @param {any} fn + * @param {number} count + * @param {number} scount + */ +function bench(fn, count, scount) { + let sources = create_data_signals(scount, []); + + fn(count, sources); +} + +export async function sbench_create_signals() { + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + bench(create_data_signals, COUNT, COUNT); + } + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 100; i++) { + bench(create_data_signals, COUNT, COUNT); + } + }); + + return { + benchmark: 'sbench_create_signals', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function sbench_create_0to1() { + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + bench(create_computations_0to1, COUNT, 0); + } + + const { timing } = await fastest_test(10, () => { + const destroy = $.effect_root(() => { + for (let i = 0; i < 10; i++) { + bench(create_computations_0to1, COUNT, 0); + } + }); + destroy(); + }); + + return { + benchmark: 'sbench_create_0to1', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function sbench_create_1to1() { + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + bench(create_computations_1to1, COUNT, COUNT); + } + + const { timing } = await fastest_test(10, () => { + const destroy = $.effect_root(() => { + for (let i = 0; i < 10; i++) { + bench(create_computations_1to1, COUNT, COUNT); + } + }); + destroy(); + }); + + return { + benchmark: 'sbench_create_1to1', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function sbench_create_2to1() { + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + bench(create_computations_2to1, COUNT / 2, COUNT); + } + + const { timing } = await fastest_test(10, () => { + const destroy = $.effect_root(() => { + for (let i = 0; i < 10; i++) { + bench(create_computations_2to1, COUNT / 2, COUNT); + } + }); + destroy(); + }); + + return { + benchmark: 'sbench_create_2to1', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function sbench_create_4to1() { + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + bench(create_computations_4to1, COUNT / 4, COUNT); + } + + const { timing } = await fastest_test(10, () => { + const destroy = $.effect_root(() => { + for (let i = 0; i < 10; i++) { + bench(create_computations_4to1, COUNT / 4, COUNT); + } + }); + destroy(); + }); + + return { + benchmark: 'sbench_create_4to1', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function sbench_create_1000to1() { + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + bench(create_computations_1000to1, COUNT / 1000, COUNT); + } + + const { timing } = await fastest_test(10, () => { + const destroy = $.effect_root(() => { + for (let i = 0; i < 10; i++) { + bench(create_computations_1000to1, COUNT / 1000, COUNT); + } + }); + destroy(); + }); + + return { + benchmark: 'sbench_create_1000to1', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function sbench_create_1to2() { + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + bench(create_computations_1to2, COUNT, COUNT / 2); + } + + const { timing } = await fastest_test(10, () => { + const destroy = $.effect_root(() => { + for (let i = 0; i < 10; i++) { + bench(create_computations_1to2, COUNT, COUNT / 2); + } + }); + destroy(); + }); + + return { + benchmark: 'sbench_create_1to2', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function sbench_create_1to4() { + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + bench(create_computations_1to4, COUNT, COUNT / 4); + } + + const { timing } = await fastest_test(10, () => { + const destroy = $.effect_root(() => { + for (let i = 0; i < 10; i++) { + bench(create_computations_1to4, COUNT, COUNT / 4); + } + }); + destroy(); + }); + + return { + benchmark: 'sbench_create_1to4', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function sbench_create_1to8() { + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + bench(create_computations_1to8, COUNT, COUNT / 8); + } + + const { timing } = await fastest_test(10, () => { + const destroy = $.effect_root(() => { + for (let i = 0; i < 10; i++) { + bench(create_computations_1to8, COUNT, COUNT / 8); + } + }); + destroy(); + }); + + return { + benchmark: 'sbench_create_1to8', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} + +export async function sbench_create_1to1000() { + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + bench(create_computations_1to1000, COUNT, COUNT / 1000); + } + + const { timing } = await fastest_test(10, () => { + const destroy = $.effect_root(() => { + for (let i = 0; i < 10; i++) { + bench(create_computations_1to1000, COUNT, COUNT / 1000); + } + }); + destroy(); + }); + + return { + benchmark: 'sbench_create_1to1000', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/benchmarks/ssr/index.js b/benchmarking/benchmarks/ssr/index.js new file mode 100644 index 000000000000..667137d1ed12 --- /dev/null +++ b/benchmarking/benchmarks/ssr/index.js @@ -0,0 +1,3 @@ +import { wrapper_bench } from './wrapper/wrapper_bench.js'; + +export const ssr_benchmarks = [wrapper_bench]; diff --git a/benchmarking/benchmarks/ssr/wrapper/App.svelte b/benchmarking/benchmarks/ssr/wrapper/App.svelte new file mode 100644 index 000000000000..93f031f2bc9a --- /dev/null +++ b/benchmarking/benchmarks/ssr/wrapper/App.svelte @@ -0,0 +1,31 @@ +<script> + const wrapperWidth = 960; + const wrapperHeight = 720; + const cellSize = 10; + const centerX = wrapperWidth / 2; + const centerY = wrapperHeight / 2; + + let angle = 0; + let radius = 0; + + let tiles = []; + const step = cellSize; + + while (radius < Math.min(wrapperWidth, wrapperHeight) / 2) { + let x = centerX + Math.cos(angle) * radius; + let y = centerY + Math.sin(angle) * radius; + + if (x >= 0 && x <= wrapperWidth - cellSize && y >= 0 && y <= wrapperHeight - cellSize) { + tiles.push({ x, y }); + } + + angle += 0.2; + radius += step * 0.015; + } +</script> + +<div id="wrapper"> + {#each tiles as { x, y }} + <div class="tile" style="left: {x.toFixed(2)}px; top: {y.toFixed(2)}px;"></div> + {/each} +</div> diff --git a/benchmarking/benchmarks/ssr/wrapper/wrapper_bench.js b/benchmarking/benchmarks/ssr/wrapper/wrapper_bench.js new file mode 100644 index 000000000000..ba0457b80ea7 --- /dev/null +++ b/benchmarking/benchmarks/ssr/wrapper/wrapper_bench.js @@ -0,0 +1,36 @@ +import { render } from 'svelte/server'; +import { fastest_test, read_file, write } from '../../../utils.js'; +import { compile } from 'svelte/compiler'; + +const dir = `${process.cwd()}/benchmarking/benchmarks/ssr/wrapper`; + +async function compile_svelte() { + const output = compile(read_file(`${dir}/App.svelte`), { + generate: 'server' + }); + write(`${dir}/output/App.js`, output.js.code); + + const module = await import(`${dir}/output/App.js`); + + return module.default; +} + +export async function wrapper_bench() { + const App = await compile_svelte(); + // Do 3 loops to warm up JIT + for (let i = 0; i < 3; i++) { + render(App); + } + + const { timing } = await fastest_test(10, () => { + for (let i = 0; i < 100; i++) { + render(App); + } + }); + + return { + benchmark: 'wrapper_bench', + time: timing.time.toFixed(2), + gc_time: timing.gc_time.toFixed(2) + }; +} diff --git a/benchmarking/compare/index.js b/benchmarking/compare/index.js new file mode 100644 index 000000000000..9d8d279c353a --- /dev/null +++ b/benchmarking/compare/index.js @@ -0,0 +1,89 @@ +import fs from 'node:fs'; +import path from 'node:path'; +import { execSync, fork } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; + +// if (execSync('git status --porcelain').toString().trim()) { +// console.error('Working directory is not clean'); +// process.exit(1); +// } + +const filename = fileURLToPath(import.meta.url); +const runner = path.resolve(filename, '../runner.js'); +const outdir = path.resolve(filename, '../.results'); + +if (fs.existsSync(outdir)) fs.rmSync(outdir, { recursive: true }); +fs.mkdirSync(outdir); + +const branches = []; + +for (const arg of process.argv.slice(2)) { + if (arg.startsWith('--')) continue; + if (arg === filename) continue; + + branches.push(arg); +} + +if (branches.length === 0) { + branches.push( + execSync('git symbolic-ref --short -q HEAD || git rev-parse --short HEAD').toString().trim() + ); +} + +if (branches.length === 1) { + branches.push('main'); +} + +process.on('exit', () => { + execSync(`git checkout ${branches[0]}`); +}); + +for (const branch of branches) { + console.group(`Benchmarking ${branch}`); + + execSync(`git checkout ${branch}`); + + await new Promise((fulfil, reject) => { + const child = fork(runner); + + child.on('message', (results) => { + fs.writeFileSync(`${outdir}/${branch}.json`, JSON.stringify(results, null, ' ')); + fulfil(); + }); + + child.on('error', reject); + }); + + console.groupEnd(); +} + +const results = branches.map((branch) => { + return JSON.parse(fs.readFileSync(`${outdir}/${branch}.json`, 'utf-8')); +}); + +for (let i = 0; i < results[0].length; i += 1) { + console.group(`${results[0][i].benchmark}`); + + for (const metric of ['time', 'gc_time']) { + const times = results.map((result) => +result[i][metric]); + let min = Infinity; + let min_index = -1; + + for (let b = 0; b < times.length; b += 1) { + if (times[b] < min) { + min = times[b]; + min_index = b; + } + } + + if (min !== 0) { + console.group(`${metric}: fastest is ${branches[min_index]}`); + times.forEach((time, b) => { + console.log(`${branches[b]}: ${time.toFixed(2)}ms (${((time / min) * 100).toFixed(2)}%)`); + }); + console.groupEnd(); + } + } + + console.groupEnd(); +} diff --git a/benchmarking/compare/runner.js b/benchmarking/compare/runner.js new file mode 100644 index 000000000000..a2e864637969 --- /dev/null +++ b/benchmarking/compare/runner.js @@ -0,0 +1,10 @@ +import { reactivity_benchmarks } from '../benchmarks/reactivity/index.js'; + +const results = []; +for (const benchmark of reactivity_benchmarks) { + const result = await benchmark(); + console.error(result.benchmark); + results.push(result); +} + +process.send(results); diff --git a/benchmarking/run.js b/benchmarking/run.js new file mode 100644 index 000000000000..bd96b9c2dc5a --- /dev/null +++ b/benchmarking/run.js @@ -0,0 +1,55 @@ +import * as $ from '../packages/svelte/src/internal/client/index.js'; +import { reactivity_benchmarks } from './benchmarks/reactivity/index.js'; +import { ssr_benchmarks } from './benchmarks/ssr/index.js'; + +let total_time = 0; +let total_gc_time = 0; + +const suites = [ + { benchmarks: reactivity_benchmarks, name: 'reactivity benchmarks' }, + { benchmarks: ssr_benchmarks, name: 'server-side rendering benchmarks' } +]; + +// eslint-disable-next-line no-console +console.log('\x1b[1m', '-- Benchmarking Started --', '\x1b[0m'); +$.push({}, true); +try { + for (const { benchmarks, name } of suites) { + let suite_time = 0; + let suite_gc_time = 0; + // eslint-disable-next-line no-console + console.log(`\nRunning ${name}...\n`); + + for (const benchmark of benchmarks) { + const results = await benchmark(); + // eslint-disable-next-line no-console + console.log(results); + total_time += Number(results.time); + total_gc_time += Number(results.gc_time); + suite_time += Number(results.time); + suite_gc_time += Number(results.gc_time); + } + + console.log(`\nFinished ${name}.\n`); + + // eslint-disable-next-line no-console + console.log({ + suite_time: suite_time.toFixed(2), + suite_gc_time: suite_gc_time.toFixed(2) + }); + } +} catch (e) { + // eslint-disable-next-line no-console + console.log('\x1b[1m', '\n-- Benchmarking Failed --\n', '\x1b[0m'); + // eslint-disable-next-line no-console + console.error(e); + process.exit(1); +} +$.pop(); +// eslint-disable-next-line no-console +console.log('\x1b[1m', '\n-- Benchmarking Complete --\n', '\x1b[0m'); +// eslint-disable-next-line no-console +console.log({ + total_time: total_time.toFixed(2), + total_gc_time: total_gc_time.toFixed(2) +}); diff --git a/benchmarking/tsconfig.json b/benchmarking/tsconfig.json new file mode 100644 index 000000000000..81fe19744ac3 --- /dev/null +++ b/benchmarking/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "moduleResolution": "Bundler", + "target": "ESNext", + "module": "ESNext", + "verbatimModuleSyntax": true, + "isolatedModules": true, + "resolveJsonModule": true, + "sourceMap": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "checkJs": true + }, + "include": ["./run.js", "./utils.js", "./benchmarks"] +} diff --git a/benchmarking/utils.js b/benchmarking/utils.js new file mode 100644 index 000000000000..684d2ee02b4d --- /dev/null +++ b/benchmarking/utils.js @@ -0,0 +1,119 @@ +import { performance, PerformanceObserver } from 'node:perf_hooks'; +import v8 from 'v8-natives'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +// Credit to https://github.com/milomg/js-reactivity-benchmark for the logic for timing + GC tracking. + +class GarbageTrack { + track_id = 0; + observer = new PerformanceObserver((list) => this.perf_entries.push(...list.getEntries())); + perf_entries = []; + periods = []; + + watch(fn) { + this.track_id++; + const start = performance.now(); + const result = fn(); + const end = performance.now(); + this.periods.push({ track_id: this.track_id, start, end }); + + return { result, track_id: this.track_id }; + } + + /** + * @param {number} track_id + */ + async gcDuration(track_id) { + await promise_delay(10); + + const period = this.periods.find((period) => period.track_id === track_id); + if (!period) { + // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors + return Promise.reject('no period found'); + } + + const entries = this.perf_entries.filter( + (e) => e.startTime >= period.start && e.startTime < period.end + ); + return entries.reduce((t, e) => e.duration + t, 0); + } + + destroy() { + this.observer.disconnect(); + } + + constructor() { + this.observer.observe({ entryTypes: ['gc'] }); + } +} + +function promise_delay(timeout = 0) { + return new Promise((resolve) => setTimeout(resolve, timeout)); +} + +/** + * @param {{ (): void; (): any; }} fn + */ +function run_timed(fn) { + const start = performance.now(); + const result = fn(); + const time = performance.now() - start; + return { result, time }; +} + +/** + * @param {() => void} fn + */ +async function run_tracked(fn) { + v8.collectGarbage(); + const gc_track = new GarbageTrack(); + const { result: wrappedResult, track_id } = gc_track.watch(() => run_timed(fn)); + const gc_time = await gc_track.gcDuration(track_id); + const { result, time } = wrappedResult; + gc_track.destroy(); + return { result, timing: { time, gc_time } }; +} + +/** + * @param {number} times + * @param {() => void} fn + */ +export async function fastest_test(times, fn) { + const results = []; + for (let i = 0; i < times; i++) { + const run = await run_tracked(fn); + results.push(run); + } + const fastest = results.reduce((a, b) => (a.timing.time < b.timing.time ? a : b)); + + return fastest; +} + +/** + * @param {boolean} a + */ +export function assert(a) { + if (!a) { + throw new Error('Assertion failed'); + } +} + +/** + * @param {string} file + */ +export function read_file(file) { + return fs.readFileSync(file, 'utf-8').replace(/\r\n/g, '\n'); +} + +/** + * @param {string} file + * @param {string} contents + */ +export function write(file, contents) { + try { + fs.mkdirSync(path.dirname(file), { recursive: true }); + } catch {} + + fs.writeFileSync(file, contents); +} diff --git a/documentation/docs/01-introduction/01-overview.md b/documentation/docs/01-introduction/01-overview.md new file mode 100644 index 000000000000..5acbe4897bf5 --- /dev/null +++ b/documentation/docs/01-introduction/01-overview.md @@ -0,0 +1,30 @@ +--- +title: Overview +--- + +Svelte is a framework for building user interfaces on the web. It uses a compiler to turn declarative components written in HTML, CSS and JavaScript... + +```svelte +<!--- file: App.svelte ---> +<script> + function greet() { + alert('Welcome to Svelte!'); + } +</script> + +<button onclick={greet}>click me</button> + +<style> + button { + font-size: 2em; + } +</style> +``` + +...into lean, tightly optimized JavaScript. + +You can use it to build anything on the web, from standalone components to ambitious full stack apps (using Svelte's companion application framework, [SvelteKit](../kit)) and everything in between. + +These pages serve as reference documentation. If you're new to Svelte, we recommend starting with the [interactive tutorial](/tutorial) and coming back here when you have questions. + +You can also try Svelte online in the [playground](/playground) or, if you need a more fully-featured environment, on [StackBlitz](https://sveltekit.new). diff --git a/documentation/docs/01-introduction/02-getting-started.md b/documentation/docs/01-introduction/02-getting-started.md new file mode 100644 index 000000000000..c7351729ff17 --- /dev/null +++ b/documentation/docs/01-introduction/02-getting-started.md @@ -0,0 +1,32 @@ +--- +title: Getting started +--- + +We recommend using [SvelteKit](../kit), which lets you [build almost anything](../kit/project-types). It's the official application framework from the Svelte team and powered by [Vite](https://vite.dev/). Create a new project with: + +```bash +npx sv create myapp +cd myapp +npm install +npm run dev +``` + +Don't worry if you don't know Svelte yet! You can ignore all the nice features SvelteKit brings on top for now and dive into it later. + +## Alternatives to SvelteKit + +You can also use Svelte directly with Vite by running `npm create vite@latest` and selecting the `svelte` option. With this, `npm run build` will generate HTML, JS, and CSS files inside the `dist` directory using [vite-plugin-svelte](https://github.com/sveltejs/vite-plugin-svelte). In most cases, you will probably need to [choose a routing library](faq#Is-there-a-router) as well. + +>[!NOTE] Vite is often used in standalone mode to build [single page apps (SPAs)](../kit/glossary#SPA), which you can also [build with SvelteKit](../kit/single-page-apps). + +There are also plugins for [Rollup](https://github.com/sveltejs/rollup-plugin-svelte), [Webpack](https://github.com/sveltejs/svelte-loader) [and a few others](https://sveltesociety.dev/packages?category=build-plugins), but we recommend Vite. + +## Editor tooling + +The Svelte team maintains a [VS Code extension](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode), and there are integrations with various other [editors](https://sveltesociety.dev/resources#editor-support) and tools as well. + +You can also check your code from the command line using [sv check](https://github.com/sveltejs/cli). + +## Getting help + +Don't be shy about asking for help in the [Discord chatroom](/chat)! You can also find answers on [Stack Overflow](https://stackoverflow.com/questions/tagged/svelte). diff --git a/documentation/docs/01-introduction/03-svelte-files.md b/documentation/docs/01-introduction/03-svelte-files.md new file mode 100644 index 000000000000..cd98652370f3 --- /dev/null +++ b/documentation/docs/01-introduction/03-svelte-files.md @@ -0,0 +1,71 @@ +--- +title: .svelte files +--- + +Components are the building blocks of Svelte applications. They are written into `.svelte` files, using a superset of HTML. + +All three sections — script, styles and markup — are optional. + +<!-- prettier-ignore --> +```svelte +/// file: MyComponent.svelte +<script module> + // module-level logic goes here + // (you will rarely use this) +</script> + +<script> + // instance-level logic goes here +</script> + +<!-- markup (zero or more items) goes here --> + +<style> + /* styles go here */ +</style> +``` + +## `<script>` + +A `<script>` block contains JavaScript (or TypeScript, when adding the `lang="ts"` attribute) that runs when a component instance is created. Variables declared (or imported) at the top level can be referenced in the component's markup. + +In addition to normal JavaScript, you can use _runes_ to declare [component props]($props) and add reactivity to your component. Runes are covered in the next section. + +<!-- TODO describe behaviour of `export` --> + +## `<script module>` + +A `<script>` tag with a `module` attribute runs once when the module first evaluates, rather than for each component instance. Variables declared in this block can be referenced elsewhere in the component, but not vice versa. + +```svelte +<script module> + let total = 0; +</script> + +<script> + total += 1; + console.log(`instantiated ${total} times`); +</script> +``` + +You can `export` bindings from this block, and they will become exports of the compiled module. You cannot `export default`, since the default export is the component itself. + +> [!NOTE] If you are using TypeScript and import such exports from a `module` block into a `.ts` file, make sure to have your editor setup so that TypeScript knows about them. This is the case for our VS Code extension and the IntelliJ plugin, but in other cases you might need to setup our [TypeScript editor plugin](https://www.npmjs.com/package/typescript-svelte-plugin). + +> [!LEGACY] +> In Svelte 4, this script tag was created using `<script context="module">` + +## `<style>` + +CSS inside a `<style>` block will be scoped to that component. + +```svelte +<style> + p { + /* this will only affect <p> elements in this component */ + color: burlywood; + } +</style> +``` + +For more information, head to the section on [styling](scoped-styles). diff --git a/documentation/docs/01-introduction/04-svelte-js-files.md b/documentation/docs/01-introduction/04-svelte-js-files.md new file mode 100644 index 000000000000..0e05484299db --- /dev/null +++ b/documentation/docs/01-introduction/04-svelte-js-files.md @@ -0,0 +1,10 @@ +--- +title: .svelte.js and .svelte.ts files +--- + +Besides `.svelte` files, Svelte also operates on `.svelte.js` and `.svelte.ts` files. + +These behave like any other `.js` or `.ts` module, except that you can use runes. This is useful for creating reusable reactive logic, or sharing reactive state across your app. + +> [!LEGACY] +> This is a concept that didn't exist prior to Svelte 5 diff --git a/documentation/docs/01-introduction/index.md b/documentation/docs/01-introduction/index.md new file mode 100644 index 000000000000..8f14f7a7c90b --- /dev/null +++ b/documentation/docs/01-introduction/index.md @@ -0,0 +1,3 @@ +--- +title: Introduction +--- diff --git a/documentation/docs/01-introduction/xx-props.md b/documentation/docs/01-introduction/xx-props.md new file mode 100644 index 000000000000..cad854d8785d --- /dev/null +++ b/documentation/docs/01-introduction/xx-props.md @@ -0,0 +1,139 @@ +--- +title: Public API of a component +--- + +### Public API of a component + +Svelte uses the `$props` rune to declare _properties_ or _props_, which means describing the public interface of the component which becomes accessible to consumers of the component. + +> [!NOTE] `$props` is one of several runes, which are special hints for Svelte's compiler to make things reactive. + +```svelte +<script> + let { foo, bar, baz } = $props(); + + // Values that are passed in as props + // are immediately available + console.log({ foo, bar, baz }); +</script> +``` + +You can specify a fallback value for a prop. It will be used if the component's consumer doesn't specify the prop on the component when instantiating the component, or if the passed value is `undefined` at some point. + +```svelte +<script> + let { foo = 'optional default initial value' } = $props(); +</script> +``` + +To get all properties, use rest syntax: + +```svelte +<script> + let { a, b, c, ...everythingElse } = $props(); +</script> +``` + +You can use reserved words as prop names. + +```svelte +<script> + // creates a `class` property, even + // though it is a reserved word + let { class: className } = $props(); +</script> +``` + +If you're using TypeScript, you can declare the prop types: + +```svelte +<script lang="ts"> + interface Props { + required: string; + optional?: number; + [key: string]: unknown; + } + + let { required, optional, ...everythingElse }: Props = $props(); +</script> +``` + +If you're using JavaScript, you can declare the prop types using JSDoc: + +```svelte +<script> + /** @type {{ x: string }} */ + let { x } = $props(); + + // or use @typedef if you want to document the properties: + + /** + * @typedef {Object} MyProps + * @property {string} y Some documentation + */ + + /** @type {MyProps} */ + let { y } = $props(); +</script> +``` + +If you export a `const`, `class` or `function`, it is readonly from outside the component. + +```svelte +<script> + export const thisIs = 'readonly'; + + export function greet(name) { + alert(`hello ${name}!`); + } +</script> +``` + +Readonly props can be accessed as properties on the element, tied to the component using [`bind:this` syntax](bindings#bind:this). + +### Reactive variables + +To change component state and trigger a re-render, just assign to a locally declared variable that was declared using the `$state` rune. + +Update expressions (`count += 1`) and property assignments (`obj.x = y`) have the same effect. + +```svelte +<script> + let count = $state(0); + + function handleClick() { + // calling this function will trigger an + // update if the markup references `count` + count = count + 1; + } +</script> +``` + +Svelte's `<script>` blocks are run only when the component is created, so assignments within a `<script>` block are not automatically run again when a prop updates. + +```svelte +<script> + let { person } = $props(); + // this will only set `name` on component creation + // it will not update when `person` does + let { name } = person; +</script> +``` + +If you'd like to react to changes to a prop, use the `$derived` or `$effect` runes instead. + +```svelte +<script> + let count = $state(0); + + let double = $derived(count * 2); + + $effect(() => { + if (count > 10) { + alert('Too high!'); + } + }); +</script> +``` + +For more information on reactivity, read the documentation around runes. diff --git a/documentation/docs/01-introduction/xx-reactivity-fundamentals.md b/documentation/docs/01-introduction/xx-reactivity-fundamentals.md new file mode 100644 index 000000000000..d5e67ada71c8 --- /dev/null +++ b/documentation/docs/01-introduction/xx-reactivity-fundamentals.md @@ -0,0 +1,144 @@ +--- +title: Reactivity fundamentals +--- + +Reactivity is at the heart of interactive UIs. When you click a button, you expect some kind of response. It's your job as a developer to make this happen. It's Svelte's job to make your job as intuitive as possible, by providing a good API to express reactive systems. + +## Runes + +Svelte 5 uses _runes_, a powerful set of primitives for controlling reactivity inside your Svelte components and inside `.svelte.js` and `.svelte.ts` modules. + +Runes are function-like symbols that provide instructions to the Svelte compiler. You don't need to import them from anywhere — when you use Svelte, they're part of the language. + +The following sections introduce the most important runes for declare state, derived state and side effects at a high level. For more details refer to the later sections on [state](state) and [side effects](side-effects). + +## `$state` + +Reactive state is declared with the `$state` rune: + +```svelte +<script> + let count = $state(0); +</script> + +<button onclick={() => count++}> + clicks: {count} +</button> +``` + +You can also use `$state` in class fields (whether public or private): + +```js +// @errors: 7006 2554 +class Todo { + done = $state(false); + text = $state(); + + constructor(text) { + this.text = text; + } +} +``` + +> [!LEGACY] +> In Svelte 4, state was implicitly reactive if the variable was declared at the top level +> +> ```svelte +> <script> +> let count = 0; +> </script> +> +> <button on:click={() => count++}> +> clicks: {count} +> </button> +> ``` + +## `$derived` + +Derived state is declared with the `$derived` rune: + +```svelte +<script> + let count = $state(0); + let doubled = $derived(count * 2); +</script> + +<button onclick={() => count++}> + {doubled} +</button> + +<p>{count} doubled is {doubled}</p> +``` + +The expression inside `$derived(...)` should be free of side-effects. Svelte will disallow state changes (e.g. `count++`) inside derived expressions. + +As with `$state`, you can mark class fields as `$derived`. + +> [!LEGACY] +> In Svelte 4, you could use reactive statements for this. +> +> ```svelte +> <script> +> let count = 0; +> $: doubled = count * 2; +> </script> +> +> <button on:click={() => count++}> +> {doubled} +> </button> +> +> <p>{count} doubled is {doubled}</p> +> ``` +> +> This only worked at the top level of a component. + +## `$effect` + +To run _side-effects_ when the component is mounted to the DOM, and when values change, we can use the `$effect` rune ([demo](/playground/untitled#H4sIAAAAAAAAE31T24rbMBD9lUG7kAQ2sbdlX7xOYNk_aB_rQhRpbAsU2UiTW0P-vbrYubSlYGzmzMzROTPymdVKo2PFjzMzfIusYB99z14YnfoQuD1qQh-7bmdFQEonrOppVZmKNBI49QthCc-OOOH0LZ-9jxnR6c7eUpOnuv6KeT5JFdcqbvbcBcgDz1jXKGg6ncFyBedYR6IzLrAZwiN5vtSxaJA-EzadfJEjKw11C6GR22-BLH8B_wxdByWpvUYtqqal2XB6RVkG1CoHB6U1WJzbnYFDiwb3aGEdDa3Bm1oH12sQLTcNPp7r56m_00mHocSG97_zd7ICUXonA5fwKbPbkE2ZtMJGGVkEdctzQi4QzSwr9prnFYNk5hpmqVuqPQjNnfOJoMF22lUsrq_UfIN6lfSVyvQ7grB3X2mjMZYO3XO9w-U5iLx42qg29md3BP_ni5P4gy9ikTBlHxjLzAtPDlyYZmRdjAbGq7HprEQ7p64v4LU_guu0kvAkhBim3nMplWl8FreQD-CW20aZR0wq12t-KqDWeBywhvexKC3memmDwlHAv9q4Vo2ZK8KtK0CgX7u9J8wXbzdKv-nRnfF_2baTqlYoWUF2h5efl9-n0O6koAMAAA==)): + +```svelte +<script> + let size = $state(50); + let color = $state('#ff3e00'); + + let canvas; + + $effect(() => { + const context = canvas.getContext('2d'); + context.clearRect(0, 0, canvas.width, canvas.height); + + // this will re-run whenever `color` or `size` change + context.fillStyle = color; + context.fillRect(0, 0, size, size); + }); +</script> + +<canvas bind:this={canvas} width="100" height="100" /> +``` + +The function passed to `$effect` will run when the component mounts, and will re-run after any changes to the values it reads that were declared with `$state` or `$derived` (including those passed in with `$props`). Re-runs are batched (i.e. changing `color` and `size` in the same moment won't cause two separate runs), and happen after any DOM updates have been applied. + +> [!LEGACY] +> In Svelte 4, you could use reactive statements for this. +> +> ```svelte +> <script> +> let size = 50; +> let color = '#ff3e00'; +> +> let canvas; +> +> $: { +> const context = canvas.getContext('2d'); +> context.clearRect(0, 0, canvas.width, canvas.height); +> +> // this will re-run whenever `color` or `size` change +> context.fillStyle = color; +> context.fillRect(0, 0, size, size); +> } +> </script> +> +> <canvas bind:this={canvas} width="100" height="100" /> +> ``` +> +> This only worked at the top level of a component. diff --git a/documentation/docs/02-runes/01-what-are-runes.md b/documentation/docs/02-runes/01-what-are-runes.md new file mode 100644 index 000000000000..59c371eb4909 --- /dev/null +++ b/documentation/docs/02-runes/01-what-are-runes.md @@ -0,0 +1,24 @@ +--- +title: What are runes? +--- + +> [!NOTE] **rune** /ruːn/ _noun_ +> +> A letter or mark used as a mystical or magic symbol. + +Runes are symbols that you use in `.svelte` and `.svelte.js`/`.svelte.ts` files to control the Svelte compiler. If you think of Svelte as a language, runes are part of the syntax — they are _keywords_. + +Runes have a `$` prefix and look like functions: + +```js +let message = $state('hello'); +``` + +They differ from normal JavaScript functions in important ways, however: + +- You don't need to import them — they are part of the language +- They're not values — you can't assign them to a variable or pass them as arguments to a function +- Just like JavaScript keywords, they are only valid in certain positions (the compiler will help you if you put them in the wrong place) + +> [!LEGACY] +> Runes didn't exist prior to Svelte 5. diff --git a/documentation/docs/02-runes/02-$state.md b/documentation/docs/02-runes/02-$state.md new file mode 100644 index 000000000000..49e17cd08ff3 --- /dev/null +++ b/documentation/docs/02-runes/02-$state.md @@ -0,0 +1,252 @@ +--- +title: $state +--- + +The `$state` rune allows you to create _reactive state_, which means that your UI _reacts_ when it changes. + +```svelte +<script> + let count = $state(0); +</script> + +<button onclick={() => count++}> + clicks: {count} +</button> +``` + +Unlike other frameworks you may have encountered, there is no API for interacting with state — `count` is just a number, rather than an object or a function, and you can update it like you would update any other variable. + +### Deep state + +If `$state` is used with an array or a simple object, the result is a deeply reactive _state proxy_. [Proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) allow Svelte to run code when you read or write properties, including via methods like `array.push(...)`, triggering granular updates. + +> [!NOTE] Classes like `Set` and `Map` will not be proxied, but Svelte provides reactive implementations for various built-ins like these that can be imported from [`svelte/reactivity`](./svelte-reactivity). + +State is proxified recursively until Svelte finds something other than an array or simple object. In a case like this... + +```js +let todos = $state([ + { + done: false, + text: 'add more todos' + } +]); +``` + +...modifying an individual todo's property will trigger updates to anything in your UI that depends on that specific property: + +```js +let todos = [{ done: false, text: 'add more todos' }]; +// ---cut--- +todos[0].done = !todos[0].done; +``` + +If you push a new object to the array, it will also be proxified: + +```js +let todos = [{ done: false, text: 'add more todos' }]; +// ---cut--- +todos.push({ + done: false, + text: 'eat lunch' +}); +``` + +> [!NOTE] When you update properties of proxies, the original object is _not_ mutated. + +Note that if you destructure a reactive value, the references are not reactive — as in normal JavaScript, they are evaluated at the point of destructuring: + +```js +let todos = [{ done: false, text: 'add more todos' }]; +// ---cut--- +let { done, text } = todos[0]; + +// this will not affect the value of `done` +todos[0].done = !todos[0].done; +``` + +### Classes + +You can also use `$state` in class fields (whether public or private): + +```js +// @errors: 7006 2554 +class Todo { + done = $state(false); + text = $state(); + + constructor(text) { + this.text = text; + } + + reset() { + this.text = ''; + this.done = false; + } +} +``` + +> [!NOTE] The compiler transforms `done` and `text` into `get`/`set` methods on the class prototype referencing private fields. This means the properties are not enumerable. + +When calling methods in JavaScript, the value of [`this`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) matters. This won't work, because `this` inside the `reset` method will be the `<button>` rather than the `Todo`: + +```svelte +<button onclick={todo.reset}> + reset +</button> +``` + +You can either use an inline function... + +```svelte +<button onclick=+++{() => todo.reset()}>+++ + reset +</button> +``` + +...or use an arrow function in the class definition: + +```js +// @errors: 7006 2554 +class Todo { + done = $state(false); + text = $state(); + + constructor(text) { + this.text = text; + } + + +++reset = () => {+++ + this.text = ''; + this.done = false; + } +} +``` + +## `$state.raw` + +In cases where you don't want objects and arrays to be deeply reactive you can use `$state.raw`. + +State declared with `$state.raw` cannot be mutated; it can only be _reassigned_. In other words, rather than assigning to a property of an object, or using an array method like `push`, replace the object or array altogether if you'd like to update it: + +```js +let person = $state.raw({ + name: 'Heraclitus', + age: 49 +}); + +// this will have no effect +person.age += 1; + +// this will work, because we're creating a new person +person = { + name: 'Heraclitus', + age: 50 +}; +``` + +This can improve performance with large arrays and objects that you weren't planning to mutate anyway, since it avoids the cost of making them reactive. Note that raw state can _contain_ reactive state (for example, a raw array of reactive objects). + +## `$state.snapshot` + +To take a static snapshot of a deeply reactive `$state` proxy, use `$state.snapshot`: + +```svelte +<script> + let counter = $state({ count: 0 }); + + function onclick() { + // Will log `{ count: ... }` rather than `Proxy { ... }` + console.log($state.snapshot(counter)); + } +</script> +``` + +This is handy when you want to pass some state to an external library or API that doesn't expect a proxy, such as `structuredClone`. + +## Passing state into functions + +JavaScript is a _pass-by-value_ language — when you call a function, the arguments are the _values_ rather than the _variables_. In other words: + +```js +/// file: index.js +// @filename: index.js +// ---cut--- +/** + * @param {number} a + * @param {number} b + */ +function add(a, b) { + return a + b; +} + +let a = 1; +let b = 2; +let total = add(a, b); +console.log(total); // 3 + +a = 3; +b = 4; +console.log(total); // still 3! +``` + +If `add` wanted to have access to the _current_ values of `a` and `b`, and to return the current `total` value, you would need to use functions instead: + +```js +/// file: index.js +// @filename: index.js +// ---cut--- +/** + * @param {() => number} getA + * @param {() => number} getB + */ +function add(+++getA, getB+++) { + return +++() => getA() + getB()+++; +} + +let a = 1; +let b = 2; +let total = add+++(() => a, () => b)+++; +console.log(+++total()+++); // 3 + +a = 3; +b = 4; +console.log(+++total()+++); // 7 +``` + +State in Svelte is no different — when you reference something declared with the `$state` rune... + +```js +let a = +++$state(1)+++; +let b = +++$state(2)+++; +``` + +...you're accessing its _current value_. + +Note that 'functions' is broad — it encompasses properties of proxies and [`get`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get)/[`set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) properties... + +```js +/// file: index.js +// @filename: index.js +// ---cut--- +/** + * @param {{ a: number, b: number }} input + */ +function add(input) { + return { + get value() { + return input.a + input.b; + } + }; +} + +let input = $state({ a: 1, b: 2 }); +let total = add(input); +console.log(total.value); // 3 + +input.a = 3; +input.b = 4; +console.log(total.value); // 7 +``` + +...though if you find yourself writing code like that, consider using [classes](#Classes) instead. diff --git a/documentation/docs/02-runes/03-$derived.md b/documentation/docs/02-runes/03-$derived.md new file mode 100644 index 000000000000..2464aa929550 --- /dev/null +++ b/documentation/docs/02-runes/03-$derived.md @@ -0,0 +1,112 @@ +--- +title: $derived +--- + +Derived state is declared with the `$derived` rune: + +```svelte +<script> + let count = $state(0); + let doubled = $derived(count * 2); +</script> + +<button onclick={() => count++}> + {doubled} +</button> + +<p>{count} doubled is {doubled}</p> +``` + +The expression inside `$derived(...)` should be free of side-effects. Svelte will disallow state changes (e.g. `count++`) inside derived expressions. + +As with `$state`, you can mark class fields as `$derived`. + +> [!NOTE] Code in Svelte components is only executed once at creation. Without the `$derived` rune, `doubled` would maintain its original value even when `count` changes. + +## `$derived.by` + +Sometimes you need to create complex derivations that don't fit inside a short expression. In these cases, you can use `$derived.by` which accepts a function as its argument. + +```svelte +<script> + let numbers = $state([1, 2, 3]); + let total = $derived.by(() => { + let total = 0; + for (const n of numbers) { + total += n; + } + return total; + }); +</script> + +<button onclick={() => numbers.push(numbers.length + 1)}> + {numbers.join(' + ')} = {total} +</button> +``` + +In essence, `$derived(expression)` is equivalent to `$derived.by(() => expression)`. + +## Understanding dependencies + +Anything read synchronously inside the `$derived` expression (or `$derived.by` function body) is considered a _dependency_ of the derived state. When the state changes, the derived will be marked as _dirty_ and recalculated when it is next read. + +To exempt a piece of state from being treated as a dependency, use [`untrack`](svelte#untrack). + +## Overriding derived values + +Derived expressions are recalculated when their dependencies change, but you can temporarily override their values by reassigning them (unless they are declared with `const`). This can be useful for things like _optimistic UI_, where a value is derived from the 'source of truth' (such as data from your server) but you'd like to show immediate feedback to the user: + +```svelte +<script> + let { post, like } = $props(); + + let likes = $derived(post.likes); + + async function onclick() { + // increment the `likes` count immediately... + likes += 1; + + // and tell the server, which will eventually update `post` + try { + await like(); + } catch { + // failed! roll back the change + likes -= 1; + } + } +</script> + +<button {onclick}>🧡 {likes}</button> +``` + +> [!NOTE] Prior to Svelte 5.25, deriveds were read-only. + +## Deriveds and reactivity + +Unlike `$state`, which converts objects and arrays to [deeply reactive proxies]($state#Deep-state), `$derived` values are left as-is. For example, [in a case like this](/playground/untitled#H4sIAAAAAAAAE4VU22rjMBD9lUHd3aaQi9PdstS1A3t5XvpQ2Ic4D7I1iUUV2UjjNMX431eS7TRdSosxgjMzZ45mjt0yzffIYibvy0ojFJWqDKCQVBk2ZVup0LJ43TJ6rn2aBxw-FP2o67k9oCKP5dziW3hRaUJNjoYltjCyplWmM1JIIAn3FlL4ZIkTTtYez6jtj4w8WwyXv9GiIXiQxLVs9pfTMR7EuoSLIuLFbX7Z4930bZo_nBrD1bs834tlfvsBz9_SyX6PZXu9XaL4gOWn4sXjeyzftv4ZWfyxubpzxzg6LfD4MrooxELEosKCUPigQCMPKCZh0OtQE1iSxcsmdHuBvCiHZXALLXiN08EL3RRkaJ_kDVGle0HcSD5TPEeVtj67O4Nrg9aiSNtBY5oODJkrL5QsHtN2cgXp6nSJMWzpWWGasdlsGEMbzi5jPr5KFr0Ep7pdeM2-TCelCddIhDxAobi1jqF3cMaC1RKp64bAW9iFAmXGIHfd4wNXDabtOLN53w8W53VvJoZLh7xk4Rr3CoL-UNoLhWHrT1JQGcM17u96oES5K-kc2XOzkzqGCKL5De79OUTyyrg1zgwXsrEx3ESfx4Bz0M5UjVMHB24mw9SuXtXFoN13fYKOM1tyUT3FbvbWmSWCZX2Er-41u5xPoml45svRahl9Wb9aasbINJixDZwcPTbyTLZSUsAvrg_cPuCR7s782_WU8343Y72Qtlb8OYatwuOQvuN13M_hJKNfxann1v1U_B1KZ_D_mzhzhz24fw85CSz2irtN9w9HshBK7AQAAA==)... + +```svelte +let items = $state([...]); + +let index = $state(0); +let selected = $derived(items[index]); +``` + +...you can change (or `bind:` to) properties of `selected` and it will affect the underlying `items` array. If `items` was _not_ deeply reactive, mutating `selected` would have no effect. + +## Update propagation + +Svelte uses something called _push-pull reactivity_ — when state is updated, everything that depends on the state (whether directly or indirectly) is immediately notified of the change (the 'push'), but derived values are not re-evaluated until they are actually read (the 'pull'). + +If the new value of a derived is referentially identical to its previous value, downstream updates will be skipped. In other words, Svelte will only update the text inside the button when `large` changes, not when `count` changes, even though `large` depends on `count`: + +```svelte +<script> + let count = $state(0); + let large = $derived(count > 10); +</script> + +<button onclick={() => count++}> + {large} +</button> +``` diff --git a/documentation/docs/02-runes/04-$effect.md b/documentation/docs/02-runes/04-$effect.md new file mode 100644 index 000000000000..ae1a2146c9d4 --- /dev/null +++ b/documentation/docs/02-runes/04-$effect.md @@ -0,0 +1,317 @@ +--- +title: $effect +--- + +Effects are functions that run when state updates, and can be used for things like calling third-party libraries, drawing on `<canvas>` elements, or making network requests. They only run in the browser, not during server-side rendering. + +Generally speaking, you should _not_ update state inside effects, as it will make code more convoluted and will often lead to never-ending update cycles. If you find yourself doing so, see [when not to use `$effect`](#When-not-to-use-$effect) to learn about alternative approaches. + +You can create an effect with the `$effect` rune ([demo](/playground/untitled#H4sIAAAAAAAAE31S246bMBD9lZF3pSRSAqTVvrCAVPUP2sdSKY4ZwJJjkD0hSVH-vbINuWxXfQH5zMyZc2ZmZLVUaFn6a2R06ZGlHmBrpvnBvb71fWQHVOSwPbf4GS46TajJspRlVhjZU1HqkhQSWPkHIYdXS5xw-Zas3ueI6FRn7qHFS11_xSRZhIxbFtcDtw7SJb1iXaOg5XIFeQGjzyPRaevYNOGZIJ8qogbpe8CWiy_VzEpTXiQUcvPDkSVrSNZz1UlW1N5eLcqmpdXUvaQ4BmqlhZNUCgxuzFHDqUWNAxrYeUM76AzsnOsdiJbrBp_71lKpn3RRbii-4P3f-IMsRxS-wcDV_bL4PmSdBa2wl7pKnbp8DMgVvJm8ZNskKRkEM_OzyOKQFkgqOYBQ3Nq89Ns0nbIl81vMFN-jKoLMTOr-SOBOJS-Z8f5Y6D1wdcR8dFqvEBdetK-PHwj-z-cH8oHPY54wRJ8Ys7iSQ3Bg3VA9azQbmC9k35kKzYa6PoVtfwbbKVnBixBiGn7Pq0rqJoUtHiCZwAM3jdTPWCVtr_glhVrhecIa3vuksJ_b7TqFs4DPyriSjd5IwoNNQaAmNI-ESfR2p8zimzvN1swdCkvJHPH6-_oX8o1SgcIDAAA=)): + +```svelte +<script> + let size = $state(50); + let color = $state('#ff3e00'); + + let canvas; + + $effect(() => { + const context = canvas.getContext('2d'); + context.clearRect(0, 0, canvas.width, canvas.height); + + // this will re-run whenever `color` or `size` change + context.fillStyle = color; + context.fillRect(0, 0, size, size); + }); +</script> + +<canvas bind:this={canvas} width="100" height="100" /> +``` + +When Svelte runs an effect function, it tracks which pieces of state (and derived state) are accessed (unless accessed inside [`untrack`](svelte#untrack)), and re-runs the function when that state later changes. + +> [!NOTE] If you're having difficulty understanding why your `$effect` is rerunning or is not running see [understanding dependencies](#Understanding-dependencies). Effects are triggered differently than the `$:` blocks you may be used to if coming from Svelte 4. + +### Understanding lifecycle + +Your effects run after the component has been mounted to the DOM, and in a [microtask](https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide) after state changes. Re-runs are batched (i.e. changing `color` and `size` in the same moment won't cause two separate runs), and happen after any DOM updates have been applied. + +You can use `$effect` anywhere, not just at the top level of a component, as long as it is called while a parent effect is running. + +> [!NOTE] Svelte uses effects internally to represent logic and expressions in your template — this is how `<h1>hello {name}!</h1>` updates when `name` changes. + +An effect can return a _teardown function_ which will run immediately before the effect re-runs ([demo](/playground/untitled#H4sIAAAAAAAAE42SQVODMBCF_8pOxkPRKq3HCsx49K4n64xpskjGkDDJ0tph-O8uINo6HjxB3u7HvrehE07WKDbiyZEhi1osRWksRrF57gQdm6E2CKx_dd43zU3co6VB28mIf-nKO0JH_BmRRRVMQ8XWbXkAgfKtI8jhIpIkXKySu7lSG2tNRGZ1_GlYr1ZTD3ddYFmiosUigbyAbpC2lKbwWJkIB8ZhhxBQBWRSw6FCh3sM8GrYTthL-wqqku4N44TyqEgwF3lmRHr4Op0PGXoH31c5rO8mqV-eOZ49bikgtcHBL55tmhIkEMqg_cFB2TpFxjtg703we6NRL8HQFCS07oSUCZi6Rm04lz1yytIHBKoQpo1w6Gsm4gmyS8b8Y5PydeMdX8gwS2Ok4I-ov5NZtvQde95GMsccn_1wzNKfu3RZtS66cSl9lvL7qO1aIk7knbJGvefdtIOzi73M4bYvovUHDFk6AcX_0HRESxnpBOW_jfCDxIZCi_1L_wm4xGQ60wIAAA==)). + +```svelte +<script> + let count = $state(0); + let milliseconds = $state(1000); + + $effect(() => { + // This will be recreated whenever `milliseconds` changes + const interval = setInterval(() => { + count += 1; + }, milliseconds); + + return () => { + // if a teardown function is provided, it will run + // a) immediately before the effect re-runs + // b) when the component is destroyed + clearInterval(interval); + }; + }); +</script> + +<h1>{count}</h1> + +<button onclick={() => (milliseconds *= 2)}>slower</button> +<button onclick={() => (milliseconds /= 2)}>faster</button> +``` + +Teardown functions also run when the effect is destroyed, which happens when its parent is destroyed (for example, a component is unmounted) or the parent effect re-runs. + +### Understanding dependencies + +`$effect` automatically picks up any reactive values (`$state`, `$derived`, `$props`) that are _synchronously_ read inside its function body (including indirectly, via function calls) and registers them as dependencies. When those dependencies change, the `$effect` schedules a re-run. + +If `$state` and `$derived` are used directly inside the `$effect` (for example, during creation of a [reactive class](https://svelte.dev/docs/svelte/$state#Classes)), those values will _not_ be treated as dependencies. + +Values that are read _asynchronously_ — after an `await` or inside a `setTimeout`, for example — will not be tracked. Here, the canvas will be repainted when `color` changes, but not when `size` changes ([demo](/playground/untitled#H4sIAAAAAAAAE31T246bMBD9lZF3pWSlBEirfaEQqdo_2PatVIpjBrDkGGQPJGnEv1e2IZfVal-wfHzmzJyZ4cIqqdCy9M-F0blDlnqArZjmB3f72XWRHVCRw_bc4me4aDWhJstSlllhZEfbQhekkMDKfwg5PFvihMvX5OXH_CJa1Zrb0-Kpqr5jkiwC48rieuDWQbqgZ6wqFLRcvkC-hYvnkWi1dWqa8ESQTxFRjfQWsOXiWzmr0sSLhEJu3p1YsoJkNUcdZUnN9dagrBu6FVRQHAM10sJRKgUG16bXcGxQ44AGdt7SDkTDdY02iqLHnJVU6hedlWuIp94JW6Tf8oBt_8GdTxlF0b4n0C35ZLBzXb3mmYn3ae6cOW74zj0YVzDNYXRHFt9mprNgHfZSl6mzml8CMoLvTV6wTZIUDEJv5us2iwMtiJRyAKG4tXnhl8O0yhbML0Wm-B7VNlSSSd31BG7z8oIZZ6dgIffAVY_5xdU9Qrz1Bnx8fCfwtZ7v8Qc9j3nB8PqgmMWlHIID6-bkVaPZwDySfWtKNGtquxQ23Qlsq2QJT0KIqb8dL0up6xQ2eIBkAg_c1FI_YqW0neLnFCqFpwmreedJYT7XX8FVOBfwWRhXstZrSXiwKQjUhOZeMIleb5JZfHWn2Yq5pWEpmR7Hv-N_wEqT8hEEAAA=)): + +```ts +// @filename: index.ts +declare let canvas: { + width: number; + height: number; + getContext(type: '2d', options?: CanvasRenderingContext2DSettings): CanvasRenderingContext2D; +}; +declare let color: string; +declare let size: number; + +// ---cut--- +$effect(() => { + const context = canvas.getContext('2d'); + context.clearRect(0, 0, canvas.width, canvas.height); + + // this will re-run whenever `color` changes... + context.fillStyle = color; + + setTimeout(() => { + // ...but not when `size` changes + context.fillRect(0, 0, size, size); + }, 0); +}); +``` + +An effect only reruns when the object it reads changes, not when a property inside it changes. (If you want to observe changes _inside_ an object at dev time, you can use [`$inspect`]($inspect).) + +```svelte +<script> + let state = $state({ value: 0 }); + let derived = $derived({ value: state.value * 2 }); + + // this will run once, because `state` is never reassigned (only mutated) + $effect(() => { + state; + }); + + // this will run whenever `state.value` changes... + $effect(() => { + state.value; + }); + + // ...and so will this, because `derived` is a new object each time + $effect(() => { + derived; + }); +</script> + +<button onclick={() => (state.value += 1)}> + {state.value} +</button> + +<p>{state.value} doubled is {derived.value}</p> +``` + +An effect only depends on the values that it read the last time it ran. This has interesting implications for effects that have conditional code. + +For instance, if `a` is `true` in the code snippet below, the code inside the `if` block will run and `b` will be evaluated. As such, changes to either `a` or `b` [will cause the effect to re-run](/playground/untitled#H4sIAAAAAAAAE3VQzWrDMAx-FdUU4kBp71li6EPstOxge0ox8-QQK2PD-N1nLy2F0Z2Evj9_chKkP1B04pnYscc3cRCT8xhF95IEf8-Vq0DBr8rzPB_jJ3qumNERH-E2ECNxiRF9tIubWY00lgcYNAywj6wZJS8rtk83wjwgCrXHaULLUrYwKEgVGrnkx-Dx6MNFNstK5OjSbFGbwE0gdXuT_zGYrjmAuco515Hr1p_uXak3K3MgCGS9s-9D2grU-judlQYXIencnzad-tdR79qZrMyvw9wd5Z8Yv1h09dz8mn8AkM7Pfo0BAAA=). + +Conversely, if `a` is `false`, `b` will not be evaluated, and the effect will _only_ re-run when `a` changes. + +```ts +let a = false; +let b = false; +// ---cut--- +$effect(() => { + console.log('running'); + + if (a) { + console.log('b:', b); + } +}); +``` + +## `$effect.pre` + +In rare cases, you may need to run code _before_ the DOM updates. For this we can use the `$effect.pre` rune: + +```svelte +<script> + import { tick } from 'svelte'; + + let div = $state(); + let messages = $state([]); + + // ... + + $effect.pre(() => { + if (!div) return; // not yet mounted + + // reference `messages` array length so that this code re-runs whenever it changes + messages.length; + + // autoscroll when new messages are added + if (div.offsetHeight + div.scrollTop > div.scrollHeight - 20) { + tick().then(() => { + div.scrollTo(0, div.scrollHeight); + }); + } + }); +</script> + +<div bind:this={div}> + {#each messages as message} + <p>{message}</p> + {/each} +</div> +``` + +Apart from the timing, `$effect.pre` works exactly like `$effect`. + +## `$effect.tracking` + +The `$effect.tracking` rune is an advanced feature that tells you whether or not the code is running inside a tracking context, such as an effect or inside your template ([demo](/playground/untitled#H4sIAAAAAAAACn3PwYrCMBDG8VeZDYIt2PYeY8Dn2HrIhqkU08nQjItS-u6buAt7UDzmz8ePyaKGMWBS-nNRcmdU-hHUTpGbyuvI3KZvDFLal0v4qvtIgiSZUSb5eWSxPfWSc4oB2xDP1XYk8HHiSHkICeXKeruDDQ4Demlldv4y0rmq6z10HQwuJMxGVv4mVVXDwcJS0jP9u3knynwtoKz1vifT_Z9Jhm0WBCcOTlDD8kyspmML5qNpHg40jc3fFryJ0iWsp_UHgz3180oBAAA=)): + +```svelte +<script> + console.log('in component setup:', $effect.tracking()); // false + + $effect(() => { + console.log('in effect:', $effect.tracking()); // true + }); +</script> + +<p>in template: {$effect.tracking()}</p> <!-- true --> +``` + +It is used to implement abstractions like [`createSubscriber`](/docs/svelte/svelte-reactivity#createSubscriber), which will create listeners to update reactive values but _only_ if those values are being tracked (rather than, for example, read inside an event handler). + +## `$effect.root` + +The `$effect.root` rune is an advanced feature that creates a non-tracked scope that doesn't auto-cleanup. This is useful for nested effects that you want to manually control. This rune also allows for the creation of effects outside of the component initialisation phase. + +```svelte +<script> + let count = $state(0); + + const cleanup = $effect.root(() => { + $effect(() => { + console.log(count); + }); + + return () => { + console.log('effect root cleanup'); + }; + }); +</script> +``` + +## When not to use `$effect` + +In general, `$effect` is best considered something of an escape hatch — useful for things like analytics and direct DOM manipulation — rather than a tool you should use frequently. In particular, avoid using it to synchronise state. Instead of this... + +```svelte +<script> + let count = $state(0); + let doubled = $state(); + + // don't do this! + $effect(() => { + doubled = count * 2; + }); +</script> +``` + +...do this: + +```svelte +<script> + let count = $state(0); + let doubled = $derived(count * 2); +</script> +``` + +> [!NOTE] For things that are more complicated than a simple expression like `count * 2`, you can also use `$derived.by`. + +If you're using an effect because you want to be able to reassign the derived value (to build an optimistic UI, for example) note that [deriveds can be directly overridden]($derived#Overriding-derived-values) as of Svelte 5.25. + +You might be tempted to do something convoluted with effects to link one value to another. The following example shows two inputs for "money spent" and "money left" that are connected to each other. If you update one, the other should update accordingly. Don't use effects for this ([demo](/playground/untitled#H4sIAAAAAAAACpVRy26DMBD8FcvKgUhtoIdeHBwp31F6MGSJkBbHwksEQvx77aWQqooq9bgzOzP7mGTdIHipPiZJowOpGJAv0po2VmfnDv4OSBErjYdneHWzBJaCjcx91TWOToUtCIEE3cig0OIty44r5l1oDtjOkyFIsv3GINQ_CNYyGegd1DVUlCR7oU9iilDUcP8S8roYs9n8p2wdYNVFm4csTx872BxNCcjr5I11fdgonEkXsjP2CoUUZWMv6m6wBz2x7yxaM-iJvWeRsvSbSVeUy5i0uf8vKA78NIeJLSZWv1I8jQjLdyK4XuTSeIdmVKJGGI4LdjVOiezwDu1yG74My8PLCQaSiroe5s_5C2PHrkVGAgAA)): + +```svelte +<script> + let total = 100; + let spent = $state(0); + let left = $state(total); + + $effect(() => { + left = total - spent; + }); + + $effect(() => { + spent = total - left; + }); +</script> + +<label> + <input type="range" bind:value={spent} max={total} /> + {spent}/{total} spent +</label> + +<label> + <input type="range" bind:value={left} max={total} /> + {left}/{total} left +</label> +``` + +Instead, use `oninput` callbacks or — better still — [function bindings](bind#Function-bindings) where possible ([demo](/playground/untitled#H4sIAAAAAAAAE51SsW6DMBT8FcvqABINdOhCIFKXTt06lg4GHpElYyz8iECIf69tcIIipo6-u3f3fPZMJWuBpvRzkBXyTpKSy5rLq6YRbbgATdOfmeKkrMgCBt9GPpQ66RsItFjJNBzhVScRJBobmumq5wovhSxQABLskAmSk7ckOXtMKyM22ItGhhAk4Z0R0OwIN-tIQzd-90HVhvy2HsGNiQFCMltBgd7XoecV2xzXNV7XaEcth7ZfRv7kujnsTX2Qd7USb5rFjwZkJlgJwpWRcakG04cpOS9oz-QVCuoeInXW-RyEJL-sG0b7Wy6kZWM-u7CFxM5tdrIl9qg72vB74H-y7T2iXROHyVb0CLanp1yNk4D1A1jQ91hzrQSbUtIIGLcir0ylJDm9Q7urz42bX4UwIk2xH2D5Xf4A7SeMcMQCAAA=)): + +```svelte +<script> + let total = 100; + let spent = $state(0); + let left = $state(total); + + function updateSpent(value) { + spent = value; + left = total - spent; + } + + function updateLeft(value) { + left = value; + spent = total - left; + } +</script> + +<label> + <input type="range" bind:value={() => spent, updateSpent} max={total} /> + {spent}/{total} spent +</label> + +<label> + <input type="range" bind:value={() => left, updateLeft} max={total} /> + {left}/{total} left +</label> +``` + +If you absolutely have to update `$state` within an effect and run into an infinite loop because you read and write to the same `$state`, use [untrack](svelte#untrack). diff --git a/documentation/docs/02-runes/05-$props.md b/documentation/docs/02-runes/05-$props.md new file mode 100644 index 000000000000..f300fb239d77 --- /dev/null +++ b/documentation/docs/02-runes/05-$props.md @@ -0,0 +1,222 @@ +--- +title: $props +--- + +The inputs to a component are referred to as _props_, which is short for _properties_. You pass props to components just like you pass attributes to elements: + +```svelte +<!--- file: App.svelte ---> +<script> + import MyComponent from './MyComponent.svelte'; +</script> + +<MyComponent adjective="cool" /> +``` + +On the other side, inside `MyComponent.svelte`, we can receive props with the `$props` rune... + +```svelte +<!--- file: MyComponent.svelte ---> +<script> + let props = $props(); +</script> + +<p>this component is {props.adjective}</p> +``` + +...though more commonly, you'll [_destructure_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) your props: + +```svelte +<!--- file: MyComponent.svelte ---> +<script> + let +++{ adjective }+++ = $props(); +</script> + +<p>this component is {+++adjective+++}</p> +``` + +## Fallback values + +Destructuring allows us to declare fallback values, which are used if the parent component does not set a given prop: + +```js +let { adjective = 'happy' } = $props(); +``` + +> [!NOTE] Fallback values are not turned into reactive state proxies (see [Updating props](#Updating-props) for more info) + +## Renaming props + +We can also use the destructuring assignment to rename props, which is necessary if they're invalid identifiers, or a JavaScript keyword like `super`: + +```js +let { super: trouper = 'lights are gonna find me' } = $props(); +``` + +## Rest props + +Finally, we can use a _rest property_ to get, well, the rest of the props: + +```js +let { a, b, c, ...others } = $props(); +``` + +## Updating props + +References to a prop inside a component update when the prop itself updates — when `count` changes in `App.svelte`, it will also change inside `Child.svelte`. But the child component is able to temporarily override the prop value, which can be useful for unsaved ephemeral state ([demo](/playground/untitled#H4sIAAAAAAAAE6WQ0WrDMAxFf0WIQR0Wmu3VTQJln7HsIfVcZubIxlbGRvC_DzuBraN92qPula50tODZWB1RPi_IX16jLALWSOOUq6P3-_ihLWftNEZ9TVeOWBNHlNhGFYznfqCBzeRdYHh6M_YVzsFNsNs3pdpGd4eBcqPVDMrNxNDBXeSRtXioDgO1zU8ataeZ2RE4Utao924RFXQ9iHXwvoPHKpW1xY4g_Bg0cSVhKS0p560Za95612ZC02ONrD8ZJYdZp_rGQ37ff_mSP86Np2TWZaNNmdcH56P4P67K66_SXoK9pG-5dF5Z9QEAAA==)): + +```svelte +<!--- file: App.svelte ---> +<script> + import Child from './Child.svelte'; + + let count = $state(0); +</script> + +<button onclick={() => (count += 1)}> + clicks (parent): {count} +</button> + +<Child {count} /> +``` + +```svelte +<!--- file: Child.svelte ---> +<script> + let { count } = $props(); +</script> + +<button onclick={() => (count += 1)}> + clicks (child): {count} +</button> +``` + +While you can temporarily _reassign_ props, you should not _mutate_ props unless they are [bindable]($bindable). + +If the prop is a regular object, the mutation will have no effect ([demo](/playground/untitled#H4sIAAAAAAAAE3WQwU7DMBBEf2W1QmorQgJXk0RC3PkBwiExG9WQrC17U4Es_ztKUkQp9OjxzM7bjcjtSKjwyfKNp1aLORA4b13ADHszUED1HFE-3eyaBcy-Mw_O5eFAg8xa1wb6T9eWhVgCKiyD9sZJ3XAjZnTWCzzuzfAKvbcjbPJieR2jm_uGy-InweXqtd0baaliBG0nFgW3kBIUNWYo9CGoxE-UsgvIpw2_oc9-LmAPJBCPDJCggqvlVtvdH9puErEMlvVg9HsVtzuoaojzkKKAfRuALVDfk5ZZW0fmy05wXcFdwyktlUs-KIinljTXrRVnm7-kL9dYLVbUAQAA)): + +```svelte +<!--- file: App.svelte ---> +<script> + import Child from './Child.svelte'; +</script> + +<Child object={{ count: 0 }} /> +``` + +```svelte +<!--- file: Child.svelte ---> +<script> + let { object } = $props(); +</script> + +<button onclick={() => { + // has no effect + object.count += 1 +}}> + clicks: {object.count} +</button> +``` + +If the prop is a reactive state proxy, however, then mutations _will_ have an effect but you will see an [`ownership_invalid_mutation`](runtime-warnings#Client-warnings-ownership_invalid_mutation) warning, because the component is mutating state that does not 'belong' to it ([demo](/playground/untitled#H4sIAAAAAAAAE3WR0U7DMAxFf8VESBuiauG1WycheOEbKA9p67FA6kSNszJV-XeUZhMw2GN8r-1znUmQ7FGU4pn2UqsOes-SlSGRia3S6ET5Mgk-2OiJBZGdOh6szd0eNcdaIx3-V28NMRI7UYq1awdleVNTzaq3ZmB43CndwXYwPSzyYn4dWxermqJRI4Np3rFlqODasWRcTtAaT1zCHYSbVU3r4nsyrdPMKTUFKDYiE4yfLEoePIbsQpqfy3_nOVMuJIqg0wk1RFg7GOuWfwEbz2wIDLVatR_VtLyBagNTHFIUMCqtoZXeIfAOU1JoUJsR2IC3nWTMjt7GM4yKdyBhlAMpesvhydCC0y_i0ZagHByMh26WzUhXUUxKnpbcVnBfUwhznJnNlac7JkuIURL-2VVfwxflyrWcSQIAAA==)): + +```svelte +<!--- file: App.svelte ---> +<script> + import Child from './Child.svelte'; + + let object = $state({count: 0}); +</script> + +<Child {object} /> +``` + +```svelte +<!--- file: Child.svelte ---> +<script> + let { object } = $props(); +</script> + +<button onclick={() => { + // will cause the count below to update, + // but with a warning. Don't mutate + // objects you don't own! + object.count += 1 +}}> + clicks: {object.count} +</button> +``` + +The fallback value of a prop not declared with `$bindable` is left untouched — it is not turned into a reactive state proxy — meaning mutations will not cause updates ([demo](/playground/untitled#H4sIAAAAAAAAE3WQwU7DMBBEf2VkIbUVoYFraCIh7vwA4eC4G9Wta1vxpgJZ_nfkBEQp9OjxzOzTRGHlkUQlXpy9G0gq1idCL43ppDrAD84HUYheGwqieo2CP3y2Z0EU3-En79fhRIaz1slA_-nKWSbLQVRiE9SgPTetbVkfvRsYzztttugHd8RiXU6vr-jisbWb8idhN7O3bEQhmN5ZVDyMlIorcOddv_Eufq4AGmJEuG5PilEjQrnRcoV7JCTUuJlGWq7-YHYjs7NwVhmtDnVcrlA3iLmzLLGTAdaB-j736h68Oxv-JM1I0AFjoG1OzPfX023c1nhobUoT39QeKsRzS8owM8DFTG_pE6dcVl70AQAA)) + +```svelte +<!--- file: Child.svelte ---> +<script> + let { object = { count: 0 } } = $props(); +</script> + +<button onclick={() => { + // has no effect if the fallback value is used + object.count += 1 +}}> + clicks: {object.count} +</button> +``` + +In summary: don't mutate props. Either use callback props to communicate changes, or — if parent and child should share the same object — use the [`$bindable`]($bindable) rune. + +## Type safety + +You can add type safety to your components by annotating your props, as you would with any other variable declaration. In TypeScript that might look like this... + +```svelte +<script lang="ts"> + let { adjective }: { adjective: string } = $props(); +</script> +``` + +...while in JSDoc you can do this: + +```svelte +<script> + /** @type {{ adjective: string }} */ + let { adjective } = $props(); +</script> +``` + +You can, of course, separate the type declaration from the annotation: + +```svelte +<script lang="ts"> + interface Props { + adjective: string; + } + + let { adjective }: Props = $props(); +</script> +``` + +> [!NOTE] Interfaces for native DOM elements are provided in the `svelte/elements` module (see [Typing wrapper components](typescript#Typing-wrapper-components)) + +Adding types is recommended, as it ensures that people using your component can easily discover which props they should provide. + + +## `$props.id()` + +This rune, added in version 5.20.0, generates an ID that is unique to the current component instance. When hydrating a server-rendered component, the value will be consistent between server and client. + +This is useful for linking elements via attributes like `for` and `aria-labelledby`. + +```svelte +<script> + const uid = $props.id(); +</script> + +<form> + <label for="{uid}-firstname">First Name: </label> + <input id="{uid}-firstname" type="text" /> + + <label for="{uid}-lastname">Last Name: </label> + <input id="{uid}-lastname" type="text" /> +</form> +``` \ No newline at end of file diff --git a/documentation/docs/02-runes/06-$bindable.md b/documentation/docs/02-runes/06-$bindable.md new file mode 100644 index 000000000000..c12c2bf4903e --- /dev/null +++ b/documentation/docs/02-runes/06-$bindable.md @@ -0,0 +1,54 @@ +--- +title: $bindable +--- + +Ordinarily, props go one way, from parent to child. This makes it easy to understand how data flows around your app. + +In Svelte, component props can be _bound_, which means that data can also flow _up_ from child to parent. This isn't something you should do often, but it can simplify your code if used sparingly and carefully. + +It also means that a state proxy can be _mutated_ in the child. + +> [!NOTE] Mutation is also possible with normal props, but is strongly discouraged — Svelte will warn you if it detects that a component is mutating state it does not 'own'. + +To mark a prop as bindable, we use the `$bindable` rune: + +<!-- prettier-ignore --> +```svelte +/// file: FancyInput.svelte +<script> + let { value = $bindable(), ...props } = $props(); +</script> + +<input bind:value={value} {...props} /> + +<style> + input { + font-family: 'Comic Sans MS'; + color: deeppink; + } +</style> +``` + +Now, a component that uses `<FancyInput>` can add the [`bind:`](bind) directive ([demo](/playground/untitled#H4sIAAAAAAAAE3WQwWrDMBBEf2URBSfg2nfFMZRCoYeecqx6UJx1IyqvhLUONcb_XqSkTUOSk1az7DBvJtEai0HI90nw6FHIJIhckO7i78n7IhzQctS2OuAtvXHESByEFFVoeuO5VqTYdN71DC-amvGV_MDQ9q6DrCjP0skkWymKJxYZOgxBfyKs4SGwZlxke7TWZcuVoqo8-1P1z3lraCcP2g64nk4GM5S1osrXf0JV-lrkgvGbheR-wDm_g30V8JL-1vpOCZFogpQsEsWcemtxscyhKArfOx9gjps0Lq4hzRVfemaYfu-PoIqqwKPFY_XpaIqj4tYRP7a6M3aUkD27zjSw0RTgbZN6Z8WNs66XsEP03tBXUueUJFlelvYx_wCuI3leNwIAAA==)): + +<!-- prettier-ignore --> +```svelte +/// file: App.svelte +<script> + import FancyInput from './FancyInput.svelte'; + + let message = $state('hello'); +</script> + +<FancyInput bind:value={message} /> +<p>{message}</p> +``` + +The parent component doesn't _have_ to use `bind:` — it can just pass a normal prop. Some parents don't want to listen to what their children have to say. + +In this case, you can specify a fallback value for when no prop is passed at all: + +```js +/// file: FancyInput.svelte +let { value = $bindable('fallback'), ...props } = $props(); +``` diff --git a/documentation/docs/02-runes/07-$inspect.md b/documentation/docs/02-runes/07-$inspect.md new file mode 100644 index 000000000000..ff3d64757b6b --- /dev/null +++ b/documentation/docs/02-runes/07-$inspect.md @@ -0,0 +1,61 @@ +--- +title: $inspect +--- + +> [!NOTE] `$inspect` only works during development. In a production build it becomes a noop. + +The `$inspect` rune is roughly equivalent to `console.log`, with the exception that it will re-run whenever its argument changes. `$inspect` tracks reactive state deeply, meaning that updating something inside an object or array using fine-grained reactivity will cause it to re-fire ([demo](/playground/untitled#H4sIAAAAAAAACkWQ0YqDQAxFfyUMhSotdZ-tCvu431AXtGOqQ2NmmMm0LOK_r7Utfby5JzeXTOpiCIPKT5PidkSVq2_n1F7Jn3uIcEMSXHSw0evHpAjaGydVzbUQCmgbWaCETZBWMPlKj29nxBDaHj_edkAiu12JhdkYDg61JGvE_s2nR8gyuBuiJZuDJTyQ7eE-IEOzog1YD80Lb0APLfdYc5F9qnFxjiKWwbImo6_llKRQVs-2u91c_bD2OCJLkT3JZasw7KLA2XCX31qKWE6vIzNk1fKE0XbmYrBTufiI8-_8D2cUWBA_AQAA)): + +```svelte +<script> + let count = $state(0); + let message = $state('hello'); + + $inspect(count, message); // will console.log when `count` or `message` change +</script> + +<button onclick={() => count++}>Increment</button> +<input bind:value={message} /> +``` + +## $inspect(...).with + +`$inspect` returns a property `with`, which you can invoke with a callback, which will then be invoked instead of `console.log`. The first argument to the callback is either `"init"` or `"update"`; subsequent arguments are the values passed to `$inspect` ([demo](/playground/untitled#H4sIAAAAAAAACkVQ24qDMBD9lSEUqlTqPlsj7ON-w7pQG8c2VCchmVSK-O-bKMs-DefKYRYx6BG9qL4XQd2EohKf1opC8Nsm4F84MkbsTXAqMbVXTltuWmp5RAZlAjFIOHjuGLOP_BKVqB00eYuKs82Qn2fNjyxLtcWeyUE2sCRry3qATQIpJRyD7WPVMf9TW-7xFu53dBcoSzAOrsqQNyOe2XUKr0Xi5kcMvdDB2wSYO-I9vKazplV1-T-d6ltgNgSG1KjVUy7ZtmdbdjqtzRcphxMS1-XubOITJtPrQWMvKnYB15_1F7KKadA_AQAA)): + +```svelte +<script> + let count = $state(0); + + $inspect(count).with((type, count) => { + if (type === 'update') { + debugger; // or `console.trace`, or whatever you want + } + }); +</script> + +<button onclick={() => count++}>Increment</button> +``` + +A convenient way to find the origin of some change is to pass `console.trace` to `with`: + +```js +// @errors: 2304 +$inspect(stuff).with(console.trace); +``` + +## $inspect.trace(...) + +This rune, added in 5.14, causes the surrounding function to be _traced_ in development. Any time the function re-runs as part of an [effect]($effect) or a [derived]($derived), information will be printed to the console about which pieces of reactive state caused the effect to fire. + +```svelte +<script> + import { doSomeWork } from './elsewhere'; + + $effect(() => { + +++$inspect.trace();+++ + doSomeWork(); + }); +</script> +``` + +`$inspect.trace` takes an optional first argument which will be used as the label. diff --git a/documentation/docs/02-runes/08-$host.md b/documentation/docs/02-runes/08-$host.md new file mode 100644 index 000000000000..ba6f0a5b5b40 --- /dev/null +++ b/documentation/docs/02-runes/08-$host.md @@ -0,0 +1,37 @@ +--- +title: $host +--- + +When compiling a component as a [custom element](custom-elements), the `$host` rune provides access to the host element, allowing you to (for example) dispatch custom events ([demo](/playground/untitled#H4sIAAAAAAAAE41Ry2rDMBD8FSECtqkTt1fHFpSSL-ix7sFRNkTEXglrnTYY_3uRlDgxTaEHIfYxs7szA9-rBizPPwZOZwM89wmecqxbF70as7InaMjltrWFR3mpkQDJ8pwXVnbKkKiwItUa3RGLVtk7gTHQXRDR2lXda4CY1D0SK9nCUk0QPyfrCovsRoNFe17aQOAwGncgO2gBqRzihJXiQrEs2csYOhQ-7HgKHaLIbpRhhBG-I2eD_8ciM4KnnOCbeE5dD2P6h0Dz0-Yi_arNhPLJXBtSGi2TvSXdbpqwdsXvjuYsC1veabvvUTog2ylrapKH2G2XsMFLS4uDthQnq2t1cwKkGOGLvYU5PvaQxLsxOkPmsm97Io1Mo2yUPF6VnOZFkw1RMoopKLKAE_9gmGxyDFMwMcwN-Bx_ABXQWmOtAgAA)): + +<!-- prettier-ignore --> +```svelte +/// file: Stepper.svelte +<svelte:options customElement="my-stepper" /> + +<script> + function dispatch(type) { + +++$host()+++.dispatchEvent(new CustomEvent(type)); + } +</script> + +<button onclick={() => dispatch('decrement')}>decrement</button> +<button onclick={() => dispatch('increment')}>increment</button> +``` + +<!-- prettier-ignore --> +```svelte +/// file: App.svelte +<script> + import './Stepper.svelte'; + + let count = $state(0); +</script> + +<my-stepper + ondecrement={() => count -= 1} + onincrement={() => count += 1} +></my-stepper> + +<p>count: {count}</p> +``` diff --git a/documentation/docs/02-runes/index.md b/documentation/docs/02-runes/index.md new file mode 100644 index 000000000000..8ade901351fb --- /dev/null +++ b/documentation/docs/02-runes/index.md @@ -0,0 +1,3 @@ +--- +title: Runes +--- diff --git a/documentation/docs/03-template-syntax/01-basic-markup.md b/documentation/docs/03-template-syntax/01-basic-markup.md new file mode 100644 index 000000000000..5e8b4342d3c5 --- /dev/null +++ b/documentation/docs/03-template-syntax/01-basic-markup.md @@ -0,0 +1,213 @@ +--- +title: Basic markup +--- + +Markup inside a Svelte component can be thought of as HTML++. + +## Tags + +A lowercase tag, like `<div>`, denotes a regular HTML element. A capitalised tag or a tag that uses dot notation, such as `<Widget>` or `<my.stuff>`, indicates a _component_. + +```svelte +<script> + import Widget from './Widget.svelte'; +</script> + +<div> + <Widget /> +</div> +``` + +## Element attributes + +By default, attributes work exactly like their HTML counterparts. + +```svelte +<div class="foo"> + <button disabled>can't touch this</button> +</div> +``` + +As in HTML, values may be unquoted. + +<!-- prettier-ignore --> +```svelte +<input type=checkbox /> +``` + +Attribute values can contain JavaScript expressions. + +```svelte +<a href="page/{p}">page {p}</a> +``` + +Or they can _be_ JavaScript expressions. + +```svelte +<button disabled={!clickable}>...</button> +``` + +Boolean attributes are included on the element if their value is [truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) and excluded if it's [falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy). + +All other attributes are included unless their value is [nullish](https://developer.mozilla.org/en-US/docs/Glossary/Nullish) (`null` or `undefined`). + +```svelte +<input required={false} placeholder="This input field is not required" /> +<div title={null}>This div has no title attribute</div> +``` + +> [!NOTE] Quoting a singular expression does not affect how the value is parsed, but in Svelte 6 it will cause the value to be coerced to a string: +> +> <!-- prettier-ignore --> +> ```svelte +> <button disabled="{number !== 42}">...</button> +> ``` + +When the attribute name and value match (`name={name}`), they can be replaced with `{name}`. + +```svelte +<button {disabled}>...</button> +<!-- equivalent to +<button disabled={disabled}>...</button> +--> +``` + +## Component props + +By convention, values passed to components are referred to as _properties_ or _props_ rather than _attributes_, which are a feature of the DOM. + +As with elements, `name={name}` can be replaced with the `{name}` shorthand. + +```svelte +<Widget foo={bar} answer={42} text="hello" /> +``` + +_Spread attributes_ allow many attributes or properties to be passed to an element or component at once. + +An element or component can have multiple spread attributes, interspersed with regular ones. + +```svelte +<Widget {...things} /> +``` + +## Events + +Listening to DOM events is possible by adding attributes to the element that start with `on`. For example, to listen to the `click` event, add the `onclick` attribute to a button: + +```svelte +<button onclick={() => console.log('clicked')}>click me</button> +``` + +Event attributes are case sensitive. `onclick` listens to the `click` event, `onClick` listens to the `Click` event, which is different. This ensures you can listen to custom events that have uppercase characters in them. + +Because events are just attributes, the same rules as for attributes apply: + +- you can use the shorthand form: `<button {onclick}>click me</button>` +- you can spread them: `<button {...thisSpreadContainsEventAttributes}>click me</button>` + +Timing-wise, event attributes always fire after events from bindings (e.g. `oninput` always fires after an update to `bind:value`). Under the hood, some event handlers are attached directly with `addEventListener`, while others are _delegated_. + +When using `ontouchstart` and `ontouchmove` event attributes, the handlers are [passive](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#using_passive_listeners) for better performance. This greatly improves responsiveness by allowing the browser to scroll the document immediately, rather than waiting to see if the event handler calls `event.preventDefault()`. + +In the very rare cases that you need to prevent these event defaults, you should use [`on`](svelte-events#on) instead (for example inside an action). + +### Event delegation + +To reduce memory footprint and increase performance, Svelte uses a technique called event delegation. This means that for certain events — see the list below — a single event listener at the application root takes responsibility for running any handlers on the event's path. + +There are a few gotchas to be aware of: + +- when you manually dispatch an event with a delegated listener, make sure to set the `{ bubbles: true }` option or it won't reach the application root +- when using `addEventListener` directly, avoid calling `stopPropagation` or the event won't reach the application root and handlers won't be invoked. Similarly, handlers added manually inside the application root will run _before_ handlers added declaratively deeper in the DOM (with e.g. `onclick={...}`), in both capturing and bubbling phases. For these reasons it's better to use the `on` function imported from `svelte/events` rather than `addEventListener`, as it will ensure that order is preserved and `stopPropagation` is handled correctly. + +The following event handlers are delegated: + +- `beforeinput` +- `click` +- `change` +- `dblclick` +- `contextmenu` +- `focusin` +- `focusout` +- `input` +- `keydown` +- `keyup` +- `mousedown` +- `mousemove` +- `mouseout` +- `mouseover` +- `mouseup` +- `pointerdown` +- `pointermove` +- `pointerout` +- `pointerover` +- `pointerup` +- `touchend` +- `touchmove` +- `touchstart` + +## Text expressions + +A JavaScript expression can be included as text by surrounding it with curly braces. + +```svelte +{expression} +``` + +Curly braces can be included in a Svelte template by using their [HTML entity](https://developer.mozilla.org/docs/Glossary/Entity) strings: `{`, `{`, or `{` for `{` and `}`, `}`, or `}` for `}`. + +If you're using a regular expression (`RegExp`) [literal notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp#literal_notation_and_constructor), you'll need to wrap it in parentheses. + +<!-- prettier-ignore --> +```svelte +<h1>Hello {name}!</h1> +<p>{a} + {b} = {a + b}.</p> + +<div>{(/^[A-Za-z ]+$/).test(value) ? x : y}</div> +``` + +The expression will be stringified and escaped to prevent code injections. If you want to render HTML, use the `{@html}` tag instead. + +```svelte +{@html potentiallyUnsafeHtmlString} +``` + +> [!NOTE] Make sure that you either escape the passed string or only populate it with values that are under your control in order to prevent [XSS attacks](https://owasp.org/www-community/attacks/xss/) + +## Comments + +You can use HTML comments inside components. + +```svelte +<!-- this is a comment! --><h1>Hello world</h1> +``` + +Comments beginning with `svelte-ignore` disable warnings for the next block of markup. Usually, these are accessibility warnings; make sure that you're disabling them for a good reason. + +```svelte +<!-- svelte-ignore a11y_autofocus --> +<input bind:value={name} autofocus /> +``` + +You can add a special comment starting with `@component` that will show up when hovering over the component name in other files. + +````svelte +<!-- +@component +- You can use markdown here. +- You can also use code blocks here. +- Usage: + ```html + <Main name="Arethra"> + ``` +--> +<script> + let { name } = $props(); +</script> + +<main> + <h1> + Hello, {name} + </h1> +</main> +```` diff --git a/documentation/docs/03-template-syntax/02-if.md b/documentation/docs/03-template-syntax/02-if.md new file mode 100644 index 000000000000..1378733e6f29 --- /dev/null +++ b/documentation/docs/03-template-syntax/02-if.md @@ -0,0 +1,40 @@ +--- +title: {#if ...} +--- + +```svelte +<!--- copy: false ---> +{#if expression}...{/if} +``` + +```svelte +<!--- copy: false ---> +{#if expression}...{:else if expression}...{/if} +``` + +```svelte +<!--- copy: false ---> +{#if expression}...{:else}...{/if} +``` + +Content that is conditionally rendered can be wrapped in an if block. + +```svelte +{#if answer === 42} + <p>what was the question?</p> +{/if} +``` + +Additional conditions can be added with `{:else if expression}`, optionally ending in an `{:else}` clause. + +```svelte +{#if porridge.temperature > 100} + <p>too hot!</p> +{:else if 80 > porridge.temperature} + <p>too cold!</p> +{:else} + <p>just right!</p> +{/if} +``` + +(Blocks don't have to wrap elements, they can also wrap text within elements.) diff --git a/documentation/docs/03-template-syntax/03-each.md b/documentation/docs/03-template-syntax/03-each.md new file mode 100644 index 000000000000..70666f6a5798 --- /dev/null +++ b/documentation/docs/03-template-syntax/03-each.md @@ -0,0 +1,114 @@ +--- +title: {#each ...} +--- + +```svelte +<!--- copy: false ---> +{#each expression as name}...{/each} +``` + +```svelte +<!--- copy: false ---> +{#each expression as name, index}...{/each} +``` + +Iterating over values can be done with an each block. The values in question can be arrays, array-like objects (i.e. anything with a `length` property), or iterables like `Map` and `Set` — in other words, anything that can be used with `Array.from`. + +```svelte +<h1>Shopping list</h1> +<ul> + {#each items as item} + <li>{item.name} x {item.qty}</li> + {/each} +</ul> +``` + +An each block can also specify an _index_, equivalent to the second argument in an `array.map(...)` callback: + +```svelte +{#each items as item, i} + <li>{i + 1}: {item.name} x {item.qty}</li> +{/each} +``` + +## Keyed each blocks + +```svelte +<!--- copy: false ---> +{#each expression as name (key)}...{/each} +``` + +```svelte +<!--- copy: false ---> +{#each expression as name, index (key)}...{/each} +``` + +If a _key_ expression is provided — which must uniquely identify each list item — Svelte will use it to diff the list when data changes, rather than adding or removing items at the end. The key can be any object, but strings and numbers are recommended since they allow identity to persist when the objects themselves change. + +```svelte +{#each items as item (item.id)} + <li>{item.name} x {item.qty}</li> +{/each} + +<!-- or with additional index value --> +{#each items as item, i (item.id)} + <li>{i + 1}: {item.name} x {item.qty}</li> +{/each} +``` + +You can freely use destructuring and rest patterns in each blocks. + +```svelte +{#each items as { id, name, qty }, i (id)} + <li>{i + 1}: {name} x {qty}</li> +{/each} + +{#each objects as { id, ...rest }} + <li><span>{id}</span><MyComponent {...rest} /></li> +{/each} + +{#each items as [id, ...rest]} + <li><span>{id}</span><MyComponent values={rest} /></li> +{/each} +``` + +## Each blocks without an item + +```svelte +<!--- copy: false ---> +{#each expression}...{/each} +``` + +```svelte +<!--- copy: false ---> +{#each expression, index}...{/each} +``` + +In case you just want to render something `n` times, you can omit the `as` part ([demo](/playground/untitled#H4sIAAAAAAAAE3WR0W7CMAxFf8XKNAk0WsSeUEaRpn3Guoc0MbQiJFHiMlDVf18SOrZJ48259_jaVgZmxBEZZ28thgCNFV6xBdt1GgPj7wOji0t2EqI-wa_OleGEmpLWiID_6dIaQkMxhm1UdwKpRQhVzWSaVORJNdvWpqbhAYVsYQCNZk8thzWMC_DCHMZk3wPSThNQ088I3mghD9UwSwHwlLE5PMIzVFUFq3G7WUZ2OyUvU3JOuZU332wCXTRmtPy1NgzXZtUFp8WFw9536uWqpbIgPEaDsJBW90cTOHh0KGi2XsBq5-cT6-3nPauxXqHnsHJnCFZ3CvJVkyuCQ0mFF9TZyCQ162WGvteLKfG197Y3iv_pz_fmS68Hxt8iPBPj5HscP8YvCNX7uhYCAAA=)): + +```svelte +<div class="chess-board"> + {#each { length: 8 }, rank} + {#each { length: 8 }, file} + <div class:black={(rank + file) % 2 === 1}></div> + {/each} + {/each} +</div> +``` + +## Else blocks + +```svelte +<!--- copy: false ---> +{#each expression as name}...{:else}...{/each} +``` + +An each block can also have an `{:else}` clause, which is rendered if the list is empty. + +```svelte +{#each todos as todo} + <p>{todo.text}</p> +{:else} + <p>No tasks today!</p> +{/each} +``` diff --git a/documentation/docs/03-template-syntax/04-key.md b/documentation/docs/03-template-syntax/04-key.md new file mode 100644 index 000000000000..10b6ab435824 --- /dev/null +++ b/documentation/docs/03-template-syntax/04-key.md @@ -0,0 +1,24 @@ +--- +title: {#key ...} +--- + +```svelte +<!--- copy: false ---> +{#key expression}...{/key} +``` + +Key blocks destroy and recreate their contents when the value of an expression changes. When used around components, this will cause them to be reinstantiated and reinitialised: + +```svelte +{#key value} + <Component /> +{/key} +``` + +It's also useful if you want a transition to play whenever a value changes: + +```svelte +{#key value} + <div transition:fade>{value}</div> +{/key} +``` diff --git a/documentation/docs/03-template-syntax/05-await.md b/documentation/docs/03-template-syntax/05-await.md new file mode 100644 index 000000000000..842b3c7e325d --- /dev/null +++ b/documentation/docs/03-template-syntax/05-await.md @@ -0,0 +1,79 @@ +--- +title: {#await ...} +--- + +```svelte +<!--- copy: false ---> +{#await expression}...{:then name}...{:catch name}...{/await} +``` + +```svelte +<!--- copy: false ---> +{#await expression}...{:then name}...{/await} +``` + +```svelte +<!--- copy: false ---> +{#await expression then name}...{/await} +``` + +```svelte +<!--- copy: false ---> +{#await expression catch name}...{/await} +``` + +Await blocks allow you to branch on the three possible states of a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) — pending, fulfilled or rejected. + +```svelte +{#await promise} + <!-- promise is pending --> + <p>waiting for the promise to resolve...</p> +{:then value} + <!-- promise was fulfilled or not a Promise --> + <p>The value is {value}</p> +{:catch error} + <!-- promise was rejected --> + <p>Something went wrong: {error.message}</p> +{/await} +``` + +> [!NOTE] During server-side rendering, only the pending branch will be rendered. +> +> If the provided expression is not a `Promise`, only the `:then` branch will be rendered, including during server-side rendering. + +The `catch` block can be omitted if you don't need to render anything when the promise rejects (or no error is possible). + +```svelte +{#await promise} + <!-- promise is pending --> + <p>waiting for the promise to resolve...</p> +{:then value} + <!-- promise was fulfilled --> + <p>The value is {value}</p> +{/await} +``` + +If you don't care about the pending state, you can also omit the initial block. + +```svelte +{#await promise then value} + <p>The value is {value}</p> +{/await} +``` + +Similarly, if you only want to show the error state, you can omit the `then` block. + +```svelte +{#await promise catch error} + <p>The error is {error}</p> +{/await} +``` + +> [!NOTE] You can use `#await` with [`import(...)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/import) to render components lazily: +> +> ```svelte +> {#await import('./Component.svelte') then { default: Component }} +> <Component /> +> {/await} +> ``` + diff --git a/documentation/docs/03-template-syntax/06-snippet.md b/documentation/docs/03-template-syntax/06-snippet.md new file mode 100644 index 000000000000..c9951d3f3414 --- /dev/null +++ b/documentation/docs/03-template-syntax/06-snippet.md @@ -0,0 +1,272 @@ +--- +title: {#snippet ...} +--- + +```svelte +<!--- copy: false ---> +{#snippet name()}...{/snippet} +``` + +```svelte +<!--- copy: false ---> +{#snippet name(param1, param2, paramN)}...{/snippet} +``` + +Snippets, and [render tags](@render), are a way to create reusable chunks of markup inside your components. Instead of writing duplicative code like [this](/playground/untitled#H4sIAAAAAAAAE5VUYW-kIBD9K8Tmsm2yXXRzvQ-s3eR-R-0HqqOQKhAZb9sz_vdDkV1t000vRmHewMx7w2AflbIGG7GnPlK8gYhFv42JthG-m9Gwf6BGcLbVXZuPSGrzVho8ZirDGpDIhldgySN5GpEMez9kaNuckY1ANJZRamRuu2ZnhEZt6a84pvs43mzD4pMsUDDi8DMkQFYCGdkvsJwblFq5uCik9bmJ4JZwUkv1eoknWigX2eGNN6aGXa6bjV8ybP-X7sM36T58SVcrIIV2xVIaA41xeD5kKqWXuqpUJEefOqVuOkL9DfBchGrzWfu0vb-RpTd3o-zBR045Ga3HfuE5BmJpKauuhbPtENlUF2sqR9jqpsPSxWsMrlngyj3VJiyYjJXb1-lMa7IWC-iSk2M5Zzh-SJjShe-siq5kpZRPs55BbSGU5YPyte4vVV_VfFXxVb10dSLf17pS2lM5HnpPxw4Zpv6x-F57p0jI3OKlVnhv5V9wPQrNYQQ9D_f6aGHlC89fq1Z3qmDkJCTCweOGF4VUFSPJvD_DhreVdA0eu8ehJJ5x91dBaBkpWm3ureCFPt3uzRv56d4kdp-2euG38XZ6dsnd3ZmPG9yRBCrzRUvi-MccOdwz3qE-fOZ7AwAhlrtTUx3c76vRhSwlFBHDtoPhefgHX3dM0PkEAAA=)... + +```svelte +{#each images as image} + {#if image.href} + <a href={image.href}> + <figure> + <img src={image.src} alt={image.caption} width={image.width} height={image.height} /> + <figcaption>{image.caption}</figcaption> + </figure> + </a> + {:else} + <figure> + <img src={image.src} alt={image.caption} width={image.width} height={image.height} /> + <figcaption>{image.caption}</figcaption> + </figure> + {/if} +{/each} +``` + +...you can write [this](/playground/untitled#H4sIAAAAAAAAE5VUYW-bMBD9KxbRlERKY4jWfSA02n5H6QcXDmwVbMs-lnaI_z6D7TTt1moTAnPvzvfenQ_GpBEd2CS_HxPJekjy5IfWyS7BFz0b9id0CM62ajDVjBS2MkLjqZQldoBE9KwFS-7I_YyUOPqlRGuqnKw5orY5pVpUduj3mitUln5LU3pI0_UuBp9FjTwnDr9AHETLMSeHK6xiGoWSLi9yYT034cwSRjohn17zcQPNFTs8s153sK9Uv_Yh0-5_5d7-o9zbD-UqCaRWrllSYZQxLw_HUhb0ta-y4NnJUxfUvc7QuLJSaO0a3oh2MLBZat8u-wsPnXzKQvTtVVF34xK5d69ThFmHEQ4SpzeVRediTG8rjD5vBSeN3E5JyHh6R1DQK9-iml5kjzQUN_lSgVU8DhYLx7wwjSvRkMDvTjiwF4zM1kXZ7DlF1eN3A7IG85e-zRrYEjjm0FkI4Cc7Ripm0pHOChexhcWXzreeZyRMU6Mk3ljxC9w4QH-cQZ_b3T5pjHxk1VNr1CDrnJy5QDh6XLO6FrLNSRb2l9gz0wo3S6m7HErSgLsPGMHkpDZK31jOanXeHPQz-eruLHUP0z6yTbpbrn223V70uMXNSpQSZjpL0y8hcxxpNqA6_ql3BQAxlxvfpQ_uT9GrWjQC6iRHM8D0MP0GQsIi92QEAAA=): + +```svelte +{#snippet figure(image)} + <figure> + <img src={image.src} alt={image.caption} width={image.width} height={image.height} /> + <figcaption>{image.caption}</figcaption> + </figure> +{/snippet} + +{#each images as image} + {#if image.href} + <a href={image.href}> + {@render figure(image)} + </a> + {:else} + {@render figure(image)} + {/if} +{/each} +``` + +Like function declarations, snippets can have an arbitrary number of parameters, which can have default values, and you can destructure each parameter. You cannot use rest parameters, however. + +## Snippet scope + +Snippets can be declared anywhere inside your component. They can reference values declared outside themselves, for example in the `<script>` tag or in `{#each ...}` blocks ([demo](/playground/untitled#H4sIAAAAAAAAE12P0QrCMAxFfyWrwhSEvc8p-h1OcG5RC10bmkyQ0n-3HQPBx3vCPUmCemiDrOpLULYbUdXqTKR2Sj6UA7_RCKbMbvJ9Jg33XpMcW9uKQYEAIzJ3T4QD3LSUDE-PnYA4YET4uOkGMc3W5B3xZrtvbVP9HDas2GqiZHqhMW6Tr9jGbG_oOCMImcUCwrIpFk1FqRyqpRpn0cmjHdAvnrIzuscyq_4nd3dPPD01ukE_NA6qFj9hvMYvGjJADw8BAAA=))... + +```svelte +<script> + let { message = `it's great to see you!` } = $props(); +</script> + +{#snippet hello(name)} + <p>hello {name}! {message}!</p> +{/snippet} + +{@render hello('alice')} +{@render hello('bob')} +``` + +...and they are 'visible' to everything in the same lexical scope (i.e. siblings, and children of those siblings): + +```svelte +<div> + {#snippet x()} + {#snippet y()}...{/snippet} + + <!-- this is fine --> + {@render y()} + {/snippet} + + <!-- this will error, as `y` is not in scope --> + {@render y()} +</div> + +<!-- this will also error, as `x` is not in scope --> +{@render x()} +``` + +Snippets can reference themselves and each other ([demo](/playground/untitled#H4sIAAAAAAAAE2WPTQqDMBCFrxLiRqH1Zysi7TlqF1YnENBJSGJLCYGeo5tesUeosfYH3c2bee_jjaWMd6BpfrAU6x5oTvdS0g01V-mFPkNnYNRaDKrxGxto5FKCIaeu1kYwFkauwsoUWtZYPh_3W5FMY4U2mb3egL9kIwY0rbhgiO-sDTgjSEqSTvIDs-jiOP7i_MHuFGAL6p9BtiSbOTl0GtzCuihqE87cqtyam6WRGz_vRcsZh5bmRg3gju4Fptq_kzQBAAA=)): + +```svelte +{#snippet blastoff()} + <span>🚀</span> +{/snippet} + +{#snippet countdown(n)} + {#if n > 0} + <span>{n}...</span> + {@render countdown(n - 1)} + {:else} + {@render blastoff()} + {/if} +{/snippet} + +{@render countdown(10)} +``` + +## Passing snippets to components + +Within the template, snippets are values just like any other. As such, they can be passed to components as props ([demo](/playground/untitled#H4sIAAAAAAAAE3VS247aMBD9lZGpBGwDASRegonaPvQL2qdlH5zYEKvBNvbQLbL875VzAcKyj3PmzJnLGU8UOwqSkd8KJdaCk4TsZS0cyV49wYuJuQiQpGd-N2bu_ooaI1YwJ57hpVYoFDqSEepKKw3mO7VDeTTaIvxiRS1gb_URxvO0ibrS8WanIrHUyiHs7Vmigy28RmyHHmKvDMbMmFq4cQInvGSwTsBYWYoMVhCSB2rBFFPsyl0uruTlR3JZCWvlTXl1Yy_mawiR_rbZKZrellJ-5JQ0RiBUgnFhJ9OGR7HKmwVoilXeIye8DOJGfYCgRlZ3iE876TBsZPX7hPdteO75PC4QaIo8vwNPePmANQ2fMeEFHrLD7rR1jTNkW986E8C3KwfwVr8HSHOSEBT_kGRozyIkn_zQveXDL3rIfPJHtUDwzShJd_Qk3gQCbOGLsdq4yfTRJopRuin3I7nv6kL7ARRjmLdBDG3uv1mhuLA3V2mKtqNEf_oCn8p9aN-WYqH5peP4kWBl1UwJzAEPT9U7K--0fRrrWnPTXpCm1_EVdXjpNmlA8G1hPPyM1fKgMqjFHjctXGjLhZ05w0qpDhksGrybuNEHtJnCalZWsuaTlfq6nPaaBSv_HKw-K57BjzOiVj9ZKQYKzQjZodYFqydYTRN4gPhVzTDO2xnma3HsVWjaLjT8nbfwHy7Q5f2dBAAA)): + +```svelte +<script> + import Table from './Table.svelte'; + + const fruits = [ + { name: 'apples', qty: 5, price: 2 }, + { name: 'bananas', qty: 10, price: 1 }, + { name: 'cherries', qty: 20, price: 0.5 } + ]; +</script> + +{#snippet header()} + <th>fruit</th> + <th>qty</th> + <th>price</th> + <th>total</th> +{/snippet} + +{#snippet row(d)} + <td>{d.name}</td> + <td>{d.qty}</td> + <td>{d.price}</td> + <td>{d.qty * d.price}</td> +{/snippet} + +<Table data={fruits} {header} {row} /> +``` + +Think about it like passing content instead of data to a component. The concept is similar to slots in web components. + +As an authoring convenience, snippets declared directly _inside_ a component implicitly become props _on_ the component ([demo](/playground/untitled#H4sIAAAAAAAAE3VSTa_aMBD8Kyu_SkAbCA-JSzBR20N_QXt6vIMTO8SqsY29tI2s_PcqTiB8vaPHs7MzuxuIZgdBMvJLo0QlOElIJZXwJHsLBBvb_XUASc7Mb9Yu_B-hsMMK5sUzvDQahUZPMkJ96aTFfKd3KA_WOISfrFACKmcOMFmk8TWUTjY73RFLoz1C5U4SPWzhrcN2GKDrlcGEWauEnyRwxCaDdQLWyVJksII2uaMWTDPNLtzX5YX8-kgua-GcHJVXI3u5WEPb0d83O03TMZSmfRzOkG1Db7mNacOL19JagVALxoWbztq-H8U6j0SaYp2P2BGbOyQ2v8PQIFMXLKRDk177pq0zf6d8bMrzwBdd0pamyPMb-IjNEzS2f86Gz_Dwf-2F9nvNSUJQ_EOSoTuJNvngqK5v4Pas7n4-OCwlEEJcQTIMO-nSQwtb-GSdsX46e9gbRoP9yGQ11I0rEuycunu6PHx1QnPhxm3SFN15MOlYEFJZtf0dUywMbwZOeBGsrKNLYB54-1R9WNqVdki7usim6VmQphf7mnpshiQRhNAXdoOfMyX3OgMlKtz0cGEcF27uLSul3mewjPjgOOoDukxjPS9rqfh0pb-8zs6aBSt_7505aZ7B9xOi0T9YKW4UooVsr0zB1BTrWQJ3EL-oWcZ572GxFoezCk37QLe3897-B2i2U62uBAAA)): + +```svelte +<!-- this is semantically the same as the above --> +<Table data={fruits}> + {#snippet header()} + <th>fruit</th> + <th>qty</th> + <th>price</th> + <th>total</th> + {/snippet} + + {#snippet row(d)} + <td>{d.name}</td> + <td>{d.qty}</td> + <td>{d.price}</td> + <td>{d.qty * d.price}</td> + {/snippet} +</Table> +``` + +Any content inside the component tags that is _not_ a snippet declaration implicitly becomes part of the `children` snippet ([demo](/playground/untitled#H4sIAAAAAAAAE3WOQQrCMBBFrzIMggql3ddY1Du4si5sOmIwnYRkFKX07lKqglqX8_7_w2uRDw1hjlsWI5ZqTPBoLEXMdy3K3fdZDzB5Ndfep_FKVnpWHSKNce1YiCVijirqYLwUJQOYxrsgsLmIOIZjcA1M02w4n-PpomSVvTclqyEutDX6DA2pZ7_ABIVugrmEC3XJH92P55_G39GodCmWBFrQJ2PrQAwdLGHig_NxNv9xrQa1dhWIawrv1Wzeqawa8953D-8QOmaEAQAA)): + +```svelte +<!--- file: App.svelte ---> +<Button>click me</Button> +``` + +```svelte +<!--- file: Button.svelte ---> +<script> + let { children } = $props(); +</script> + +<!-- result will be <button>click me</button> --> +<button>{@render children()}</button> +``` + +> [!NOTE] Note that you cannot have a prop called `children` if you also have content inside the component — for this reason, you should avoid having props with that name + +You can declare snippet props as being optional. You can either use optional chaining to not render anything if the snippet isn't set... + +```svelte +<script> + let { children } = $props(); +</script> + +{@render children?.()} +``` + +...or use an `#if` block to render fallback content: + +```svelte +<script> + let { children } = $props(); +</script> + +{#if children} + {@render children()} +{:else} + fallback content +{/if} +``` + +## Typing snippets + +Snippets implement the `Snippet` interface imported from `'svelte'`: + +```svelte +<script lang="ts"> + import type { Snippet } from 'svelte'; + + interface Props { + data: any[]; + children: Snippet; + row: Snippet<[any]>; + } + + let { data, children, row }: Props = $props(); +</script> +``` + +With this change, red squigglies will appear if you try and use the component without providing a `data` prop and a `row` snippet. Notice that the type argument provided to `Snippet` is a tuple, since snippets can have multiple parameters. + +We can tighten things up further by declaring a generic, so that `data` and `row` refer to the same type: + +```svelte +<script lang="ts" generics="T"> + import type { Snippet } from 'svelte'; + + let { + data, + children, + row + }: { + data: T[]; + children: Snippet; + row: Snippet<[T]>; + } = $props(); +</script> +``` + +## Exporting snippets + +Snippets declared at the top level of a `.svelte` file can be exported from a `<script module>` for use in other components, provided they don't reference any declarations in a non-module `<script>` (whether directly or indirectly, via other snippets) ([demo](/playground/untitled#H4sIAAAAAAAAE3WPwY7CMAxEf8UyB1hRgdhjl13Bga8gHFJipEqtGyUGFUX5dxJUtEB3b9bYM_MckHVLWOKut50TMuC5tpbEY4GnuiGP5T6gXG0-ykLSB8vW2oW_UCNZq7Snv_Rjx0Kc4kpc-6OrrfwoVlK3uQ4CaGMgwsl1LUwXy0f54J9-KV4vf20cNo7YkMu22aqAz4-oOLUI9YKluDPF4h_at-hX5PFyzA1tZ84N3fGpf8YfUU6GvDumLqDKmEqCjjCHUEX4hqDTWCU5PJ6Or38c4g1cPu9tnAEAAA==)): + +```svelte +<script module> + export { add }; +</script> + +{#snippet add(a, b)} + {a} + {b} = {a + b} +{/snippet} +``` + +> [!NOTE] +> This requires Svelte 5.5.0 or newer + +## Programmatic snippets + +Snippets can be created programmatically with the [`createRawSnippet`](svelte#createRawSnippet) API. This is intended for advanced use cases. + +## Snippets and slots + +In Svelte 4, content can be passed to components using [slots](legacy-slots). Snippets are more powerful and flexible, and as such slots are deprecated in Svelte 5. diff --git a/documentation/docs/03-template-syntax/07-@render.md b/documentation/docs/03-template-syntax/07-@render.md new file mode 100644 index 000000000000..ecdf5cc216fc --- /dev/null +++ b/documentation/docs/03-template-syntax/07-@render.md @@ -0,0 +1,39 @@ +--- +title: {@render ...} +--- + +To render a [snippet](snippet), use a `{@render ...}` tag. + +```svelte +{#snippet sum(a, b)} + <p>{a} + {b} = {a + b}</p> +{/snippet} + +{@render sum(1, 2)} +{@render sum(3, 4)} +{@render sum(5, 6)} +``` + +The expression can be an identifier like `sum`, or an arbitrary JavaScript expression: + +```svelte +{@render (cool ? coolSnippet : lameSnippet)()} +``` + +## Optional snippets + +If the snippet is potentially undefined — for example, because it's an incoming prop — then you can use optional chaining to only render it when it _is_ defined: + +```svelte +{@render children?.()} +``` + +Alternatively, use an [`{#if ...}`](if) block with an `:else` clause to render fallback content: + +```svelte +{#if children} + {@render children()} +{:else} + <p>fallback content</p> +{/if} +``` diff --git a/documentation/docs/03-template-syntax/08-@html.md b/documentation/docs/03-template-syntax/08-@html.md new file mode 100644 index 000000000000..30456fa666eb --- /dev/null +++ b/documentation/docs/03-template-syntax/08-@html.md @@ -0,0 +1,51 @@ +--- +title: {@html ...} +--- + +To inject raw HTML into your component, use the `{@html ...}` tag: + +```svelte +<article> + {@html content} +</article> +``` + +> [!NOTE] Make sure that you either escape the passed string or only populate it with values that are under your control in order to prevent [XSS attacks](https://owasp.org/www-community/attacks/xss/). Never render unsanitized content. + +The expression should be valid standalone HTML — this will not work, because `</div>` is not valid HTML: + +```svelte +{@html '<div>'}content{@html '</div>'} +``` + +It also will not compile Svelte code. + +## Styling + +Content rendered this way is 'invisible' to Svelte and as such will not receive [scoped styles](scoped-styles) — in other words, this will not work, and the `a` and `img` styles will be regarded as unused: + +<!-- prettier-ignore --> +```svelte +<article> + {@html content} +</article> + +<style> + article { + a { color: hotpink } + img { width: 100% } + } +</style> +``` + +Instead, use the `:global` modifier to target everything inside the `<article>`: + +<!-- prettier-ignore --> +```svelte +<style> + article +++:global+++ { + a { color: hotpink } + img { width: 100% } + } +</style> +``` diff --git a/documentation/docs/03-template-syntax/09-@const.md b/documentation/docs/03-template-syntax/09-@const.md new file mode 100644 index 000000000000..2a587b7a3d7c --- /dev/null +++ b/documentation/docs/03-template-syntax/09-@const.md @@ -0,0 +1,14 @@ +--- +title: {@const ...} +--- + +The `{@const ...}` tag defines a local constant. + +```svelte +{#each boxes as box} + {@const area = box.width * box.height} + {box.width} * {box.height} = {area} +{/each} +``` + +`{@const}` is only allowed as an immediate child of a block — `{#if ...}`, `{#each ...}`, `{#snippet ...}` and so on — a `<Component />` or a `<svelte:boundary>`. diff --git a/documentation/docs/03-template-syntax/10-@debug.md b/documentation/docs/03-template-syntax/10-@debug.md new file mode 100644 index 000000000000..15e32dcae99f --- /dev/null +++ b/documentation/docs/03-template-syntax/10-@debug.md @@ -0,0 +1,35 @@ +--- +title: {@debug ...} +--- + +The `{@debug ...}` tag offers an alternative to `console.log(...)`. It logs the values of specific variables whenever they change, and pauses code execution if you have devtools open. + +```svelte +<script> + let user = { + firstname: 'Ada', + lastname: 'Lovelace' + }; +</script> + +{@debug user} + +<h1>Hello {user.firstname}!</h1> +``` + +`{@debug ...}` accepts a comma-separated list of variable names (not arbitrary expressions). + +```svelte +<!-- Compiles --> +{@debug user} +{@debug user1, user2, user3} + +<!-- WON'T compile --> +{@debug user.firstname} +{@debug myArray[0]} +{@debug !isReady} +{@debug typeof user === 'object'} +``` + +The `{@debug}` tag without any arguments will insert a `debugger` statement that gets triggered when _any_ state changes, as opposed to the specified variables. + diff --git a/documentation/docs/03-template-syntax/11-bind.md b/documentation/docs/03-template-syntax/11-bind.md new file mode 100644 index 000000000000..c23f3b52327c --- /dev/null +++ b/documentation/docs/03-template-syntax/11-bind.md @@ -0,0 +1,364 @@ +--- +title: bind: +--- + +Data ordinarily flows down, from parent to child. The `bind:` directive allows data to flow the other way, from child to parent. + +The general syntax is `bind:property={expression}`, where `expression` is an _lvalue_ (i.e. a variable or an object property). When the expression is an identifier with the same name as the property, we can omit the expression — in other words these are equivalent: + +<!-- prettier-ignore --> +```svelte +<input bind:value={value} /> +<input bind:value /> +``` + + +Svelte creates an event listener that updates the bound value. If an element already has a listener for the same event, that listener will be fired before the bound value is updated. + +Most bindings are _two-way_, meaning that changes to the value will affect the element and vice versa. A few bindings are _readonly_, meaning that changing their value will have no effect on the element. + +## Function bindings + +You can also use `bind:property={get, set}`, where `get` and `set` are functions, allowing you to perform validation and transformation: + +```svelte +<input bind:value={ + () => value, + (v) => value = v.toLowerCase()} +/> +``` + +In the case of readonly bindings like [dimension bindings](#Dimensions), the `get` value should be `null`: + +```svelte +<div + bind:clientWidth={null, redraw} + bind:clientHeight={null, redraw} +>...</div> +``` + +> [!NOTE] +> Function bindings are available in Svelte 5.9.0 and newer. + +## `<input bind:value>` + +A `bind:value` directive on an `<input>` element binds the input's `value` property: + +<!-- prettier-ignore --> +```svelte +<script> + let message = $state('hello'); +</script> + +<input bind:value={message} /> +<p>{message}</p> +``` + +In the case of a numeric input (`type="number"` or `type="range"`), the value will be coerced to a number ([demo](/playground/untitled#H4sIAAAAAAAAE6WPwYoCMQxAfyWEPeyiOOqx2w74Hds9pBql0IllmhGXYf5dKqwiyILsLXnwwsuI-5i4oPkaUX8yo7kCnKNQV7dNzoty4qSVBSr8jG-Poixa0KAt2z5mbb14TaxA4OCtKCm_rz4-f2m403WltrlrYhMFTtcLNkoeFGqZ8yhDF7j3CCHKzpwoDexGmqCL4jwuPUJHZ-dxVcfmyYGe5MAv-La5pbxYFf5Z9Zf_UJXb-sEMquFgJJhBmGyTW5yj8lnRaD_w9D1dAKSSj7zqAQAA)): + +```svelte +<script> + let a = $state(1); + let b = $state(2); +</script> + +<label> + <input type="number" bind:value={a} min="0" max="10" /> + <input type="range" bind:value={a} min="0" max="10" /> +</label> + +<label> + <input type="number" bind:value={b} min="0" max="10" /> + <input type="range" bind:value={b} min="0" max="10" /> +</label> + +<p>{a} + {b} = {a + b}</p> +``` + +If the input is empty or invalid (in the case of `type="number"`), the value is `undefined`. + +Since 5.6.0, if an `<input>` has a `defaultValue` and is part of a form, it will revert to that value instead of the empty string when the form is reset. Note that for the initial render the value of the binding takes precedence unless it is `null` or `undefined`. + +```svelte +<script> + let value = $state(''); +</script> + +<form> + <input bind:value defaultValue="not the empty string"> + <input type="reset" value="Reset"> +</form> +``` + +> [!NOTE] +> Use reset buttons sparingly, and ensure that users won't accidentally click them while trying to submit the form. + +## `<input bind:checked>` + +Checkbox and radio inputs can be bound with `bind:checked`: + +```svelte +<label> + <input type="checkbox" bind:checked={accepted} /> + Accept terms and conditions +</label> +``` + +Since 5.6.0, if an `<input>` has a `defaultChecked` attribute and is part of a form, it will revert to that value instead of `false` when the form is reset. Note that for the initial render the value of the binding takes precedence unless it is `null` or `undefined`. + +```svelte +<script> + let checked = $state(true); +</script> + +<form> + <input type="checkbox" bind:checked defaultChecked={true}> + <input type="reset" value="Reset"> +</form> +``` + +## `<input bind:group>` + +Inputs that work together can use `bind:group`. + +```svelte +<script> + let tortilla = $state('Plain'); + + /** @type {Array<string>} */ + let fillings = $state([]); +</script> + +<!-- grouped radio inputs are mutually exclusive --> +<input type="radio" bind:group={tortilla} value="Plain" /> +<input type="radio" bind:group={tortilla} value="Whole wheat" /> +<input type="radio" bind:group={tortilla} value="Spinach" /> + +<!-- grouped checkbox inputs populate an array --> +<input type="checkbox" bind:group={fillings} value="Rice" /> +<input type="checkbox" bind:group={fillings} value="Beans" /> +<input type="checkbox" bind:group={fillings} value="Cheese" /> +<input type="checkbox" bind:group={fillings} value="Guac (extra)" /> +``` + +> [!NOTE] `bind:group` only works if the inputs are in the same Svelte component. + +## `<input bind:files>` + +On `<input>` elements with `type="file"`, you can use `bind:files` to get the [`FileList` of selected files](https://developer.mozilla.org/en-US/docs/Web/API/FileList). When you want to update the files programmatically, you always need to use a `FileList` object. Currently `FileList` objects cannot be constructed directly, so you need to create a new [`DataTransfer`](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer) object and get `files` from there. + +```svelte +<script> + let files = $state(); + + function clear() { + files = new DataTransfer().files; // null or undefined does not work + } +</script> + +<label for="avatar">Upload a picture:</label> +<input accept="image/png, image/jpeg" bind:files id="avatar" name="avatar" type="file" /> +<button onclick={clear}>clear</button> +``` + +`FileList` objects also cannot be modified, so if you want to e.g. delete a single file from the list, you need to create a new `DataTransfer` object and add the files you want to keep. + +> [!NOTE] `DataTransfer` may not be available in server-side JS runtimes. Leaving the state that is bound to `files` uninitialized prevents potential errors if components are server-side rendered. + +## `<select bind:value>` + +A `<select>` value binding corresponds to the `value` property on the selected `<option>`, which can be any value (not just strings, as is normally the case in the DOM). + +```svelte +<select bind:value={selected}> + <option value={a}>a</option> + <option value={b}>b</option> + <option value={c}>c</option> +</select> +``` + +A `<select multiple>` element behaves similarly to a checkbox group. The bound variable is an array with an entry corresponding to the `value` property of each selected `<option>`. + +```svelte +<select multiple bind:value={fillings}> + <option value="Rice">Rice</option> + <option value="Beans">Beans</option> + <option value="Cheese">Cheese</option> + <option value="Guac (extra)">Guac (extra)</option> +</select> +``` + +When the value of an `<option>` matches its text content, the attribute can be omitted. + +```svelte +<select multiple bind:value={fillings}> + <option>Rice</option> + <option>Beans</option> + <option>Cheese</option> + <option>Guac (extra)</option> +</select> +``` + +You can give the `<select>` a default value by adding a `selected` attribute to the`<option>` (or options, in the case of `<select multiple>`) that should be initially selected. If the `<select>` is part of a form, it will revert to that selection when the form is reset. Note that for the initial render the value of the binding takes precedence if it's not `undefined`. + +```svelte +<select bind:value={selected}> + <option value={a}>a</option> + <option value={b} selected>b</option> + <option value={c}>c</option> +</select> +``` + +## `<audio>` + +`<audio>` elements have their own set of bindings — five two-way ones... + +- [`currentTime`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime) +- [`playbackRate`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/playbackRate) +- [`paused`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/paused) +- [`volume`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/volume) +- [`muted`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/muted) + +...and six readonly ones: + +- [`duration`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/duration) +- [`buffered`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/buffered) +- [`seekable`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seekable) +- [`seeking`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/seeking_event) +- [`ended`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/ended) +- [`readyState`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState) + +```svelte +<audio src={clip} bind:duration bind:currentTime bind:paused></audio> +``` + +## `<video>` + +`<video>` elements have all the same bindings as [`<audio>`](#audio) elements, plus readonly [`videoWidth`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/videoWidth) and [`videoHeight`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement/videoHeight) bindings. + +## `<img>` + +`<img>` elements have two readonly bindings: + +- [`naturalWidth`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalWidth) +- [`naturalHeight`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/naturalHeight) + +## `<details bind:open>` + +`<details>` elements support binding to the `open` property. + +```svelte +<details bind:open={isOpen}> + <summary>How do you comfort a JavaScript bug?</summary> + <p>You console it.</p> +</details> +``` + +## Contenteditable bindings + +Elements with the `contenteditable` attribute support the following bindings: + +- [`innerHTML`](https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML) +- [`innerText`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/innerText) +- [`textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent) + +> [!NOTE] There are [subtle differences between `innerText` and `textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent#differences_from_innertext). + +<!-- for some reason puts the comment and html on same line --> +<!-- prettier-ignore --> +```svelte +<div contenteditable="true" bind:innerHTML={html}></div> +``` + +## Dimensions + +All visible elements have the following readonly bindings, measured with a `ResizeObserver`: + +- [`clientWidth`](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth) +- [`clientHeight`](https://developer.mozilla.org/en-US/docs/Web/API/Element/clientHeight) +- [`offsetWidth`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetWidth) +- [`offsetHeight`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetHeight) + +```svelte +<div bind:offsetWidth={width} bind:offsetHeight={height}> + <Chart {width} {height} /> +</div> +``` + +> [!NOTE] `display: inline` elements do not have a width or height (except for elements with 'intrinsic' dimensions, like `<img>` and `<canvas>`), and cannot be observed with a `ResizeObserver`. You will need to change the `display` style of these elements to something else, such as `inline-block`. + +## bind:this + +```svelte +<!--- copy: false ---> +bind:this={dom_node} +``` + +To get a reference to a DOM node, use `bind:this`. The value will be `undefined` until the component is mounted — in other words, you should read it inside an effect or an event handler, but not during component initialisation: + +```svelte +<script> + /** @type {HTMLCanvasElement} */ + let canvas; + + $effect(() => { + const ctx = canvas.getContext('2d'); + drawStuff(ctx); + }); +</script> + +<canvas bind:this={canvas}></canvas> +``` + +Components also support `bind:this`, allowing you to interact with component instances programmatically. + +```svelte +<!--- file: App.svelte ---> +<ShoppingCart bind:this={cart} /> + +<button onclick={() => cart.empty()}> Empty shopping cart </button> +``` + +```svelte +<!--- file: ShoppingCart.svelte ---> +<script> + // All instance exports are available on the instance object + export function empty() { + // ... + } +</script> +``` + +## bind:_property_ for components + +```svelte +bind:property={variable} +``` + +You can bind to component props using the same syntax as for elements. + +```svelte +<Keypad bind:value={pin} /> +``` + +While Svelte props are reactive without binding, that reactivity only flows downward into the component by default. Using `bind:property` allows changes to the property from within the component to flow back up out of the component. + +To mark a property as bindable, use the [`$bindable`]($bindable) rune: + +```svelte +<script> + let { readonlyProperty, bindableProperty = $bindable() } = $props(); +</script> +``` + +Declaring a property as bindable means it _can_ be used using `bind:`, not that it _must_ be used using `bind:`. + +Bindable properties can have a fallback value: + +```svelte +<script> + let { bindableProperty = $bindable('fallback value') } = $props(); +</script> +``` + +This fallback value _only_ applies when the property is _not_ bound. When the property is bound and a fallback value is present, the parent is expected to provide a value other than `undefined`, else a runtime error is thrown. This prevents hard-to-reason-about situations where it's unclear which value should apply. diff --git a/documentation/docs/03-template-syntax/12-use.md b/documentation/docs/03-template-syntax/12-use.md new file mode 100644 index 000000000000..45de0235782b --- /dev/null +++ b/documentation/docs/03-template-syntax/12-use.md @@ -0,0 +1,80 @@ +--- +title: use: +--- + +Actions are functions that are called when an element is mounted. They are added with the `use:` directive, and will typically use an `$effect` so that they can reset any state when the element is unmounted: + +```svelte +<!--- file: App.svelte ---> +<script> + /** @type {import('svelte/action').Action} */ + function myaction(node) { + // the node has been mounted in the DOM + + $effect(() => { + // setup goes here + + return () => { + // teardown goes here + }; + }); + } +</script> + +<div use:myaction>...</div> +``` + +An action can be called with an argument: + +```svelte +<!--- file: App.svelte ---> +<script> + /** @type {import('svelte/action').Action} */ + function myaction(node, +++data+++) { + // ... + } +</script> + +<div use:myaction={+++data+++}>...</div> +``` + +The action is only called once (but not during server-side rendering) — it will _not_ run again if the argument changes. + +> [!LEGACY] +> Prior to the `$effect` rune, actions could return an object with `update` and `destroy` methods, where `update` would be called with the latest value of the argument if it changed. Using effects is preferred. + +## Typing + +The `Action` interface receives three optional type arguments — a node type (which can be `Element`, if the action applies to everything), a parameter, and any custom event handlers created by the action: + +```svelte +<!--- file: App.svelte ---> +<script> + /** + * @type {import('svelte/action').Action< + * HTMLDivElement, + * undefined, + * { + * onswiperight: (e: CustomEvent) => void; + * onswipeleft: (e: CustomEvent) => void; + * // ... + * } + * >} + */ + function gestures(node) { + $effect(() => { + // ... + node.dispatchEvent(new CustomEvent('swipeleft')); + + // ... + node.dispatchEvent(new CustomEvent('swiperight')); + }); + } +</script> + +<div + use:gestures + onswipeleft={next} + onswiperight={prev} +>...</div> +``` diff --git a/documentation/docs/03-template-syntax/13-transition.md b/documentation/docs/03-template-syntax/13-transition.md new file mode 100644 index 000000000000..51c11e8b34e9 --- /dev/null +++ b/documentation/docs/03-template-syntax/13-transition.md @@ -0,0 +1,171 @@ +--- +title: transition: +--- + +A _transition_ is triggered by an element entering or leaving the DOM as a result of a state change. + +When a block (such as an `{#if ...}` block) is transitioning out, all elements inside it, including those that do not have their own transitions, are kept in the DOM until every transition in the block has been completed. + +The `transition:` directive indicates a _bidirectional_ transition, which means it can be smoothly reversed while the transition is in progress. + +```svelte +<script> + +++import { fade } from 'svelte/transition';+++ + + let visible = $state(false); +</script> + +<button onclick={() => visible = !visible}>toggle</button> + +{#if visible} + <div +++transition:fade+++>fades in and out</div> +{/if} +``` + +## Built-in transitions + +A selection of built-in transitions can be imported from the [`svelte/transition`](svelte-transition) module. + +## Local vs global + +Transitions are local by default. Local transitions only play when the block they belong to is created or destroyed, _not_ when parent blocks are created or destroyed. + +```svelte +{#if x} + {#if y} + <p transition:fade>fades in and out only when y changes</p> + + <p transition:fade|global>fades in and out when x or y change</p> + {/if} +{/if} +``` + +## Transition parameters + +Transitions can have parameters. + +(The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.) + +```svelte +{#if visible} + <div transition:fade={{ duration: 2000 }}>fades in and out over two seconds</div> +{/if} +``` + +## Custom transition functions + +```js +/// copy: false +// @noErrors +transition = (node: HTMLElement, params: any, options: { direction: 'in' | 'out' | 'both' }) => { + delay?: number, + duration?: number, + easing?: (t: number) => number, + css?: (t: number, u: number) => string, + tick?: (t: number, u: number) => void +} +``` + +Transitions can use custom functions. If the returned object has a `css` function, Svelte will generate keyframes for a [web animation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API). + +The `t` argument passed to `css` is a value between `0` and `1` after the `easing` function has been applied. _In_ transitions run from `0` to `1`, _out_ transitions run from `1` to `0` — in other words, `1` is the element's natural state, as though no transition had been applied. The `u` argument is equal to `1 - t`. + +The function is called repeatedly _before_ the transition begins, with different `t` and `u` arguments. + +```svelte +<!--- file: App.svelte ---> +<script> + import { elasticOut } from 'svelte/easing'; + + /** @type {boolean} */ + export let visible; + + /** + * @param {HTMLElement} node + * @param {{ delay?: number, duration?: number, easing?: (t: number) => number }} params + */ + function whoosh(node, params) { + const existingTransform = getComputedStyle(node).transform.replace('none', ''); + + return { + delay: params.delay || 0, + duration: params.duration || 400, + easing: params.easing || elasticOut, + css: (t, u) => `transform: ${existingTransform} scale(${t})` + }; + } +</script> + +{#if visible} + <div in:whoosh>whooshes in</div> +{/if} +``` + +A custom transition function can also return a `tick` function, which is called _during_ the transition with the same `t` and `u` arguments. + +> [!NOTE] If it's possible to use `css` instead of `tick`, do so — web animations can run off the main thread, preventing jank on slower devices. + +```svelte +<!--- file: App.svelte ---> +<script> + export let visible = false; + + /** + * @param {HTMLElement} node + * @param {{ speed?: number }} params + */ + function typewriter(node, { speed = 1 }) { + const valid = node.childNodes.length === 1 && node.childNodes[0].nodeType === Node.TEXT_NODE; + + if (!valid) { + throw new Error(`This transition only works on elements with a single text node child`); + } + + const text = node.textContent; + const duration = text.length / (speed * 0.01); + + return { + duration, + tick: (t) => { + const i = ~~(text.length * t); + node.textContent = text.slice(0, i); + } + }; + } +</script> + +{#if visible} + <p in:typewriter={{ speed: 1 }}>The quick brown fox jumps over the lazy dog</p> +{/if} +``` + +If a transition returns a function instead of a transition object, the function will be called in the next microtask. This allows multiple transitions to coordinate, making [crossfade effects](/tutorial/deferred-transitions) possible. + +Transition functions also receive a third argument, `options`, which contains information about the transition. + +Available values in the `options` object are: + +- `direction` - one of `in`, `out`, or `both` depending on the type of transition + +## Transition events + +An element with transitions will dispatch the following events in addition to any standard DOM events: + +- `introstart` +- `introend` +- `outrostart` +- `outroend` + +```svelte +{#if visible} + <p + transition:fly={{ y: 200, duration: 2000 }} + onintrostart={() => (status = 'intro started')} + onoutrostart={() => (status = 'outro started')} + onintroend={() => (status = 'intro ended')} + onoutroend={() => (status = 'outro ended')} + > + Flies in and out + </p> +{/if} +``` diff --git a/documentation/docs/03-template-syntax/14-in-and-out.md b/documentation/docs/03-template-syntax/14-in-and-out.md new file mode 100644 index 000000000000..f4e37c845ee8 --- /dev/null +++ b/documentation/docs/03-template-syntax/14-in-and-out.md @@ -0,0 +1,22 @@ +--- +title: in: and out: +--- + +The `in:` and `out:` directives are identical to [`transition:`](transition), except that the resulting transitions are not bidirectional — an `in` transition will continue to 'play' alongside the `out` transition, rather than reversing, if the block is outroed while the transition is in progress. If an out transition is aborted, transitions will restart from scratch. + +```svelte +<script> + import { fade, fly } from 'svelte/transition'; + + let visible = $state(false); +</script> + +<label> + <input type="checkbox" bind:checked={visible}> + visible +</label> + +{#if visible} + <div in:fly={{ y: 200 }} out:fade>flies in, fades out</div> +{/if} +``` diff --git a/documentation/docs/03-template-syntax/15-animate.md b/documentation/docs/03-template-syntax/15-animate.md new file mode 100644 index 000000000000..a54e37f0b12d --- /dev/null +++ b/documentation/docs/03-template-syntax/15-animate.md @@ -0,0 +1,114 @@ +--- +title: animate: +--- + +An animation is triggered when the contents of a [keyed each block](each#Keyed-each-blocks) are re-ordered. Animations do not run when an element is added or removed, only when the index of an existing data item within the each block changes. Animate directives must be on an element that is an _immediate_ child of a keyed each block. + +Animations can be used with Svelte's [built-in animation functions](svelte-animate) or [custom animation functions](#Custom-animation-functions). + +```svelte +<!-- When `list` is reordered the animation will run --> +{#each list as item, index (item)} + <li animate:flip>{item}</li> +{/each} +``` + +## Animation Parameters + +As with actions and transitions, animations can have parameters. + +(The double `{{curlies}}` aren't a special syntax; this is an object literal inside an expression tag.) + +```svelte +{#each list as item, index (item)} + <li animate:flip={{ delay: 500 }}>{item}</li> +{/each} +``` + +## Custom animation functions + +```js +/// copy: false +// @noErrors +animation = (node: HTMLElement, { from: DOMRect, to: DOMRect } , params: any) => { + delay?: number, + duration?: number, + easing?: (t: number) => number, + css?: (t: number, u: number) => string, + tick?: (t: number, u: number) => void +} +``` + +Animations can use custom functions that provide the `node`, an `animation` object and any `parameters` as arguments. The `animation` parameter is an object containing `from` and `to` properties each containing a [DOMRect](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect#Properties) describing the geometry of the element in its `start` and `end` positions. The `from` property is the DOMRect of the element in its starting position, and the `to` property is the DOMRect of the element in its final position after the list has been reordered and the DOM updated. + +If the returned object has a `css` method, Svelte will create a [web animation](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API) that plays on the element. + +The `t` argument passed to `css` is a value that goes from `0` and `1` after the `easing` function has been applied. The `u` argument is equal to `1 - t`. + +The function is called repeatedly _before_ the animation begins, with different `t` and `u` arguments. + +<!-- TODO: Types --> + +```svelte +<!--- file: App.svelte ---> +<script> + import { cubicOut } from 'svelte/easing'; + + /** + * @param {HTMLElement} node + * @param {{ from: DOMRect; to: DOMRect }} states + * @param {any} params + */ + function whizz(node, { from, to }, params) { + const dx = from.left - to.left; + const dy = from.top - to.top; + + const d = Math.sqrt(dx * dx + dy * dy); + + return { + delay: 0, + duration: Math.sqrt(d) * 120, + easing: cubicOut, + css: (t, u) => `transform: translate(${u * dx}px, ${u * dy}px) rotate(${t * 360}deg);` + }; + } +</script> + +{#each list as item, index (item)} + <div animate:whizz>{item}</div> +{/each} +``` + +A custom animation function can also return a `tick` function, which is called _during_ the animation with the same `t` and `u` arguments. + +> [!NOTE] If it's possible to use `css` instead of `tick`, do so — web animations can run off the main thread, preventing jank on slower devices. + +```svelte +<!--- file: App.svelte ---> +<script> + import { cubicOut } from 'svelte/easing'; + + /** + * @param {HTMLElement} node + * @param {{ from: DOMRect; to: DOMRect }} states + * @param {any} params + */ + function whizz(node, { from, to }, params) { + const dx = from.left - to.left; + const dy = from.top - to.top; + + const d = Math.sqrt(dx * dx + dy * dy); + + return { + delay: 0, + duration: Math.sqrt(d) * 120, + easing: cubicOut, + tick: (t, u) => Object.assign(node.style, { color: t > 0.5 ? 'Pink' : 'Blue' }) + }; + } +</script> + +{#each list as item, index (item)} + <div animate:whizz>{item}</div> +{/each} +``` diff --git a/documentation/docs/03-template-syntax/17-style.md b/documentation/docs/03-template-syntax/17-style.md new file mode 100644 index 000000000000..749376c6e2a6 --- /dev/null +++ b/documentation/docs/03-template-syntax/17-style.md @@ -0,0 +1,41 @@ +--- +title: style: +--- + +The `style:` directive provides a shorthand for setting multiple styles on an element. + +```svelte +<!-- These are equivalent --> +<div style:color="red">...</div> +<div style="color: red;">...</div> +``` + +The value can contain arbitrary expressions: + +```svelte +<div style:color={myColor}>...</div> +``` + +The shorthand form is allowed: + +```svelte +<div style:color>...</div> +``` + +Multiple styles can be set on a single element: + +```svelte +<div style:color style:width="12rem" style:background-color={darkMode ? 'black' : 'white'}>...</div> +``` + +To mark a style as important, use the `|important` modifier: + +```svelte +<div style:color|important="red">...</div> +``` + +When `style:` directives are combined with `style` attributes, the directives will take precedence: + +```svelte +<div style="color: blue;" style:color="red">This will be red</div> +``` diff --git a/documentation/docs/03-template-syntax/18-class.md b/documentation/docs/03-template-syntax/18-class.md new file mode 100644 index 000000000000..1ea4a208dfdc --- /dev/null +++ b/documentation/docs/03-template-syntax/18-class.md @@ -0,0 +1,102 @@ +--- +title: class +--- + +There are two ways to set classes on elements: the `class` attribute, and the `class:` directive. + +## Attributes + +Primitive values are treated like any other attribute: + +```svelte +<div class={large ? 'large' : 'small'}>...</div> +``` + +> [!NOTE] +> For historical reasons, falsy values (like `false` and `NaN`) are stringified (`class="false"`), though `class={undefined}` (or `null`) cause the attribute to be omitted altogether. In a future version of Svelte, all falsy values will cause `class` to be omitted. + +### Objects and arrays + +Since Svelte 5.16, `class` can be an object or array, and is converted to a string using [clsx](https://github.com/lukeed/clsx). + +If the value is an object, the truthy keys are added: + +```svelte +<script> + let { cool } = $props(); +</script> + +<!-- results in `class="cool"` if `cool` is truthy, + `class="lame"` otherwise --> +<div class={{ cool, lame: !cool }}>...</div> +``` + +If the value is an array, the truthy values are combined: + +```svelte +<!-- if `faded` and `large` are both truthy, results in + `class="saturate-0 opacity-50 scale-200"` --> +<div class={[faded && 'saturate-0 opacity-50', large && 'scale-200']}>...</div> +``` + +Note that whether we're using the array or object form, we can set multiple classes simultaneously with a single condition, which is particularly useful if you're using things like Tailwind. + +Arrays can contain arrays and objects, and clsx will flatten them. This is useful for combining local classes with props, for example: + +```svelte +<!--- file: Button.svelte ---> +<script> + let props = $props(); +</script> + +<button {...props} class={['cool-button', props.class]}> + {@render props.children?.()} +</button> +``` + +The user of this component has the same flexibility to use a mixture of objects, arrays and strings: + +```svelte +<!--- file: App.svelte ---> +<script> + import Button from './Button.svelte'; + let useTailwind = $state(false); +</script> + +<Button + onclick={() => useTailwind = true} + class={{ 'bg-blue-700 sm:w-1/2': useTailwind }} +> + Accept the inevitability of Tailwind +</Button> +``` + +Svelte also exposes the `ClassValue` type, which is the type of value that the `class` attribute on elements accept. This is useful if you want to use a type-safe class name in component props: + +```svelte +<script lang="ts"> + import type { ClassValue } from 'svelte/elements'; + + const props: { class: ClassValue } = $props(); +</script> + +<div class={['original', props.class]}>...</div> +``` + +## The `class:` directive + +Prior to Svelte 5.16, the `class:` directive was the most convenient way to set classes on elements conditionally. + +```svelte +<!-- These are equivalent --> +<div class={{ cool, lame: !cool }}>...</div> +<div class:cool={cool} class:lame={!cool}>...</div> +``` + +As with other directives, we can use a shorthand when the name of the class coincides with the value: + +```svelte +<div class:cool class:lame={!cool}>...</div> +``` + +> [!NOTE] Unless you're using an older version of Svelte, consider avoiding `class:`, since the attribute is more powerful and composable. diff --git a/documentation/docs/03-template-syntax/index.md b/documentation/docs/03-template-syntax/index.md new file mode 100644 index 000000000000..3c4523cb9275 --- /dev/null +++ b/documentation/docs/03-template-syntax/index.md @@ -0,0 +1,3 @@ +--- +title: Template syntax +--- diff --git a/documentation/docs/03-template-syntax/xx-control-flow.md b/documentation/docs/03-template-syntax/xx-control-flow.md new file mode 100644 index 000000000000..b73917997bc5 --- /dev/null +++ b/documentation/docs/03-template-syntax/xx-control-flow.md @@ -0,0 +1,111 @@ +--- +title: Control flow +--- + +- if +- each +- await (or move that into some kind of data loading section?) +- NOT: key (move into transition section, because that's the common use case) + +Svelte augments HTML with control flow blocks to be able to express conditionally rendered content or lists. + +The syntax between these blocks is the same: + +- `{#` denotes the start of a block +- `{:` denotes a different branch part of the block. Depending on the block, there can be multiple of these +- `{/` denotes the end of a block + +## {#if ...} + +## {#each ...} + +```svelte +<!--- copy: false ---> +{#each expression as name}...{/each} +``` + +```svelte +<!--- copy: false ---> +{#each expression as name, index}...{/each} +``` + +```svelte +<!--- copy: false ---> +{#each expression as name (key)}...{/each} +``` + +```svelte +<!--- copy: false ---> +{#each expression as name, index (key)}...{/each} +``` + +```svelte +<!--- copy: false ---> +{#each expression as name}...{:else}...{/each} +``` + +Iterating over lists of values can be done with an each block. + +```svelte +<h1>Shopping list</h1> +<ul> + {#each items as item} + <li>{item.name} x {item.qty}</li> + {/each} +</ul> +``` + +You can use each blocks to iterate over any array or array-like value — that is, any object with a `length` property. + +An each block can also specify an _index_, equivalent to the second argument in an `array.map(...)` callback: + +```svelte +{#each items as item, i} + <li>{i + 1}: {item.name} x {item.qty}</li> +{/each} +``` + +If a _key_ expression is provided — which must uniquely identify each list item — Svelte will use it to diff the list when data changes, rather than adding or removing items at the end. The key can be any object, but strings and numbers are recommended since they allow identity to persist when the objects themselves change. + +```svelte +{#each items as item (item.id)} + <li>{item.name} x {item.qty}</li> +{/each} + +<!-- or with additional index value --> +{#each items as item, i (item.id)} + <li>{i + 1}: {item.name} x {item.qty}</li> +{/each} +``` + +You can freely use destructuring and rest patterns in each blocks. + +```svelte +{#each items as { id, name, qty }, i (id)} + <li>{i + 1}: {name} x {qty}</li> +{/each} + +{#each objects as { id, ...rest }} + <li><span>{id}</span><MyComponent {...rest} /></li> +{/each} + +{#each items as [id, ...rest]} + <li><span>{id}</span><MyComponent values={rest} /></li> +{/each} +``` + +An each block can also have an `{:else}` clause, which is rendered if the list is empty. + +```svelte +{#each todos as todo} + <p>{todo.text}</p> +{:else} + <p>No tasks today!</p> +{/each} +``` + +It is possible to iterate over iterables like `Map` or `Set`. Iterables need to be finite and static (they shouldn't change while being iterated over). Under the hood, they are transformed to an array using `Array.from` before being passed off to rendering. If you're writing performance-sensitive code, try to avoid iterables and use regular arrays as they are more performant. + +## Other block types + +Svelte also provides [`#snippet`](snippets), [`#key`](transitions-and-animations) and [`#await`](data-fetching) blocks. You can find out more about them in their respective sections. diff --git a/documentation/docs/03-template-syntax/xx-data-fetching.md b/documentation/docs/03-template-syntax/xx-data-fetching.md new file mode 100644 index 000000000000..4526d5133561 --- /dev/null +++ b/documentation/docs/03-template-syntax/xx-data-fetching.md @@ -0,0 +1,20 @@ +--- +title: Data fetching +--- + +Fetching data is a fundamental part of apps interacting with the outside world. Svelte is unopinionated with how you fetch your data. The simplest way would be using the built-in `fetch` method: + +```svelte +<script> + let response = $state(); + fetch('/api/data').then(async (r) => (response = r.json())); +</script> +``` + +While this works, it makes working with promises somewhat unergonomic. Svelte alleviates this problem using the `#await` block. + +## {#await ...} + +## SvelteKit loaders + +Fetching inside your components is great for simple use cases, but it's prone to data loading waterfalls and makes code harder to work with because of the promise handling. SvelteKit solves this problem by providing a opinionated data loading story that is coupled to its router. Learn more about it [in the docs](../kit). diff --git a/documentation/docs/04-styling/01-scoped-styles.md b/documentation/docs/04-styling/01-scoped-styles.md new file mode 100644 index 000000000000..eae26d0cb1ca --- /dev/null +++ b/documentation/docs/04-styling/01-scoped-styles.md @@ -0,0 +1,39 @@ +--- +title: Scoped styles +--- + +Svelte components can include a `<style>` element containing CSS that belongs to the component. This CSS is _scoped_ by default, meaning that styles will not apply to any elements on the page outside the component in question. + +This works by adding a class to affected elements, which is based on a hash of the component styles (e.g. `svelte-123xyz`). + +```svelte +<style> + p { + /* this will only affect <p> elements in this component */ + color: burlywood; + } +</style> +``` + +## Specificity + +Each scoped selector receives a [specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity) increase of 0-1-0, as a result of the scoping class (e.g. `.svelte-123xyz`) being added to the selector. This means that (for example) a `p` selector defined in a component will take precedence over a `p` selector defined in a global stylesheet, even if the global stylesheet is loaded later. + +In some cases, the scoping class must be added to a selector multiple times, but after the first occurrence it is added with `:where(.svelte-xyz123)` in order to not increase specificity further. + +## Scoped keyframes + +If a component defines `@keyframes`, the name is scoped to the component using the same hashing approach. Any `animation` rules in the component will be similarly adjusted: + +```svelte +<style> + .bouncy { + animation: bounce 10s; + } + + /* these keyframes are only accessible inside this component */ + @keyframes bounce { + /* ... */ + } +</style> +``` diff --git a/documentation/docs/04-styling/02-global-styles.md b/documentation/docs/04-styling/02-global-styles.md new file mode 100644 index 000000000000..8e9cf8d0cbec --- /dev/null +++ b/documentation/docs/04-styling/02-global-styles.md @@ -0,0 +1,65 @@ +--- +title: Global styles +--- + +## :global(...) + +To apply styles to a single selector globally, use the `:global(...)` modifier: + +```svelte +<style> + :global(body) { + /* applies to <body> */ + margin: 0; + } + + div :global(strong) { + /* applies to all <strong> elements, in any component, + that are inside <div> elements belonging + to this component */ + color: goldenrod; + } + + p:global(.big.red) { + /* applies to all <p> elements belonging to this component + with `class="big red"`, even if it is applied + programmatically (for example by a library) */ + } +</style> +``` + +If you want to make @keyframes that are accessible globally, you need to prepend your keyframe names with `-global-`. + +The `-global-` part will be removed when compiled, and the keyframe will then be referenced using just `my-animation-name` elsewhere in your code. + +```svelte +<style> + @keyframes -global-my-animation-name { + /* code goes here */ + } +</style> +``` + +## :global + +To apply styles to a group of selectors globally, create a `:global {...}` block: + +```svelte +<style> + :global { + /* applies to every <div> in your application */ + div { ... } + + /* applies to every <p> in your application */ + p { ... } + } + + .a :global { + /* applies to every `.b .c .d` element, in any component, + that is inside an `.a` element in this component */ + .b .c .d {...} + } +</style> +``` + +> [!NOTE] The second example above could also be written as an equivalent `.a :global .b .c .d` selector, where everything after the `:global` is unscoped, though the nested form is preferred. diff --git a/documentation/docs/04-styling/03-custom-properties.md b/documentation/docs/04-styling/03-custom-properties.md new file mode 100644 index 000000000000..49984c6ce4bc --- /dev/null +++ b/documentation/docs/04-styling/03-custom-properties.md @@ -0,0 +1,57 @@ +--- +title: Custom properties +--- + +You can pass CSS custom properties — both static and dynamic — to components: + +```svelte +<Slider + bind:value + min={0} + max={100} + --track-color="black" + --thumb-color="rgb({r} {g} {b})" +/> +``` + +The above code essentially desugars to this: + +```svelte +<svelte-css-wrapper style="display: contents; --track-color: black; --thumb-color: rgb({r} {g} {b})"> + <Slider + bind:value + min={0} + max={100} + /> +</svelte-css-wrapper> +``` + +For an SVG element, it would use `<g>` instead: + +```svelte +<g style="--track-color: black; --thumb-color: rgb({r} {g} {b})"> + <Slider + bind:value + min={0} + max={100} + /> +</g> +``` + +Inside the component, we can read these custom properties (and provide fallback values) using [`var(...)`](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties): + +```svelte +<style> + .track { + background: var(--track-color, #aaa); + } + + .thumb { + background: var(--thumb-color, blue); + } +</style> +``` + +You don't _have_ to specify the values directly on the component; as long as the custom properties are defined on a parent element, the component can use them. It's common to define custom properties on the `:root` element in a global stylesheet so that they apply to your entire application. + +> [!NOTE] While the extra element will not affect layout, it _will_ affect any CSS selectors that (for example) use the `>` combinator to target an element directly inside the component's container. diff --git a/documentation/docs/04-styling/04-nested-style-elements.md b/documentation/docs/04-styling/04-nested-style-elements.md new file mode 100644 index 000000000000..4fc5cfa5213a --- /dev/null +++ b/documentation/docs/04-styling/04-nested-style-elements.md @@ -0,0 +1,21 @@ +--- +title: Nested <style> elements +--- + +There can only be one top-level `<style>` tag per component. + +However, it is possible to have a `<style>` tag nested inside other elements or logic blocks. + +In that case, the `<style>` tag will be inserted as-is into the DOM; no scoping or processing will be done on the `<style>` tag. + +```svelte +<div> + <style> + /* this style tag will be inserted as-is */ + div { + /* this will apply to all `<div>` elements in the DOM */ + color: red; + } + </style> +</div> +``` diff --git a/documentation/docs/04-styling/index.md b/documentation/docs/04-styling/index.md new file mode 100644 index 000000000000..5245bd516b53 --- /dev/null +++ b/documentation/docs/04-styling/index.md @@ -0,0 +1,3 @@ +--- +title: Styling +--- diff --git a/documentation/docs/05-special-elements/01-svelte-boundary.md b/documentation/docs/05-special-elements/01-svelte-boundary.md new file mode 100644 index 000000000000..f5439b4b83e7 --- /dev/null +++ b/documentation/docs/05-special-elements/01-svelte-boundary.md @@ -0,0 +1,82 @@ +--- +title: <svelte:boundary> +--- + +```svelte +<svelte:boundary onerror={handler}>...</svelte:boundary> +``` + +> [!NOTE] +> This feature was added in 5.3.0 + +Boundaries allow you to guard against errors in part of your app from breaking the app as a whole, and to recover from those errors. + +If an error occurs while rendering or updating the children of a `<svelte:boundary>`, or running any [`$effect`]($effect) functions contained therein, the contents will be removed. + +Errors occurring outside the rendering process (for example, in event handlers or after a `setTimeout` or async work) are _not_ caught by error boundaries. + +## Properties + +For the boundary to do anything, one or both of `failed` and `onerror` must be provided. + +### `failed` + +If a `failed` snippet is provided, it will be rendered with the error that was thrown, and a `reset` function that recreates the contents ([demo](/playground/hello-world#H4sIAAAAAAAAE3VRy26DMBD8lS2tFCIh6JkAUlWp39Cq9EBg06CAbdlLArL87zWGKk8ORnhmd3ZnrD1WtOjFXqKO2BDGW96xqpBD5gXerm5QefG39mgQY9EIWHxueRMinLosti0UPsJLzggZKTeilLWgLGc51a3gkuCjKQ7DO7cXZotgJ3kLqzC6hmex1SZnSXTWYHcrj8LJjWTk0PHoZ8VqIdCOKayPykcpuQxAokJaG1dGybYj4gw4K5u6PKTasSbjXKgnIDlA8VvUdo-pzonraBY2bsH7HAl78mKSHZpgIcuHjq9jXSpZSLixRlveKYQUXhQVhL6GPobXAAb7BbNeyvNUs4qfRg3OnELLj5hqH9eQZqCnoBwR9lYcQxuVXeBzc8kMF8yXY4yNJ5oGiUzP_aaf_waTRGJib5_Ad3P_vbCuaYxzeNpbU0eUMPAOKh7Yw1YErgtoXyuYlPLzc10_xo_5A91zkQL_AgAA)): + +```svelte +<svelte:boundary> + <FlakyComponent /> + + {#snippet failed(error, reset)} + <button onclick={reset}>oops! try again</button> + {/snippet} +</svelte:boundary> +``` + +> [!NOTE] +> As with [snippets passed to components](snippet#Passing-snippets-to-components), the `failed` snippet can be passed explicitly as a property... +> +> ```svelte +> <svelte:boundary {failed}>...</svelte:boundary> +> ``` +> +> ...or implicitly by declaring it directly inside the boundary, as in the example above. + +### `onerror` + +If an `onerror` function is provided, it will be called with the same two `error` and `reset` arguments. This is useful for tracking the error with an error reporting service... + +```svelte +<svelte:boundary onerror={(e) => report(e)}> + ... +</svelte:boundary> +``` + +...or using `error` and `reset` outside the boundary itself: + +```svelte +<script> + let error = $state(null); + let reset = $state(() => {}); + + function onerror(e, r) { + error = e; + reset = r; + } +</script> + +<svelte:boundary {onerror}> + <FlakyComponent /> +</svelte:boundary> + +{#if error} + <button onclick={() => { + error = null; + reset(); + }}> + oops! try again + </button> +{/if} +``` + +If an error occurs inside the `onerror` function (or if you rethrow the error), it will be handled by a parent boundary if such exists. diff --git a/documentation/docs/05-special-elements/02-svelte-window.md b/documentation/docs/05-special-elements/02-svelte-window.md new file mode 100644 index 000000000000..d4aab36f3b27 --- /dev/null +++ b/documentation/docs/05-special-elements/02-svelte-window.md @@ -0,0 +1,44 @@ +--- +title: <svelte:window> +--- + +```svelte +<svelte:window onevent={handler} /> +``` + +```svelte +<svelte:window bind:prop={value} /> +``` + +The `<svelte:window>` element allows you to add event listeners to the `window` object without worrying about removing them when the component is destroyed, or checking for the existence of `window` when server-side rendering. + +This element may only appear at the top level of your component — it cannot be inside a block or element. + +```svelte +<script> + function handleKeydown(event) { + alert(`pressed the ${event.key} key`); + } +</script> + +<svelte:window onkeydown={handleKeydown} /> +``` + +You can also bind to the following properties: + +- `innerWidth` +- `innerHeight` +- `outerWidth` +- `outerHeight` +- `scrollX` +- `scrollY` +- `online` — an alias for `window.navigator.onLine` +- `devicePixelRatio` + +All except `scrollX` and `scrollY` are readonly. + +```svelte +<svelte:window bind:scrollY={y} /> +``` + +> [!NOTE] Note that the page will not be scrolled to the initial value to avoid accessibility issues. Only subsequent changes to the bound variable of `scrollX` and `scrollY` will cause scrolling. If you have a legitimate reason to scroll when the component is rendered, call `scrollTo()` in an `$effect`. diff --git a/documentation/docs/05-special-elements/03-svelte-document.md b/documentation/docs/05-special-elements/03-svelte-document.md new file mode 100644 index 000000000000..43f02865e6ef --- /dev/null +++ b/documentation/docs/05-special-elements/03-svelte-document.md @@ -0,0 +1,28 @@ +--- +title: <svelte:document> +--- + +```svelte +<svelte:document onevent={handler} /> +``` + +```svelte +<svelte:document bind:prop={value} /> +``` + +Similarly to `<svelte:window>`, this element allows you to add listeners to events on `document`, such as `visibilitychange`, which don't fire on `window`. It also lets you use [actions](use) on `document`. + +As with `<svelte:window>`, this element may only appear the top level of your component and must never be inside a block or element. + +```svelte +<svelte:document onvisibilitychange={handleVisibilityChange} use:someAction /> +``` + +You can also bind to the following properties: + +- `activeElement` +- `fullscreenElement` +- `pointerLockElement` +- `visibilityState` + +All are readonly. diff --git a/documentation/docs/05-special-elements/04-svelte-body.md b/documentation/docs/05-special-elements/04-svelte-body.md new file mode 100644 index 000000000000..d6536b0b7424 --- /dev/null +++ b/documentation/docs/05-special-elements/04-svelte-body.md @@ -0,0 +1,15 @@ +--- +title: <svelte:body> +--- + +```svelte +<svelte:body onevent={handler} /> +``` + +Similarly to `<svelte:window>`, this element allows you to add listeners to events on `document.body`, such as `mouseenter` and `mouseleave`, which don't fire on `window`. It also lets you use [actions](use) on the `<body>` element. + +As with `<svelte:window>` and `<svelte:document>`, this element may only appear the top level of your component and must never be inside a block or element. + +```svelte +<svelte:body onmouseenter={handleMouseenter} onmouseleave={handleMouseleave} use:someAction /> +``` diff --git a/documentation/docs/05-special-elements/05-svelte-head.md b/documentation/docs/05-special-elements/05-svelte-head.md new file mode 100644 index 000000000000..f7cd7ca20a58 --- /dev/null +++ b/documentation/docs/05-special-elements/05-svelte-head.md @@ -0,0 +1,18 @@ +--- +title: <svelte:head> +--- + +```svelte +<svelte:head>...</svelte:head> +``` + +This element makes it possible to insert elements into `document.head`. During server-side rendering, `head` content is exposed separately to the main `body` content. + +As with `<svelte:window>`, `<svelte:document>` and `<svelte:body>`, this element may only appear at the top level of your component and must never be inside a block or element. + +```svelte +<svelte:head> + <title>Hello world! + + +``` diff --git a/documentation/docs/05-special-elements/06-svelte-element.md b/documentation/docs/05-special-elements/06-svelte-element.md new file mode 100644 index 000000000000..ef7dc320662f --- /dev/null +++ b/documentation/docs/05-special-elements/06-svelte-element.md @@ -0,0 +1,33 @@ +--- +title: +--- + +```svelte + +``` + +The `` element lets you render an element that is unknown at author time, for example because it comes from a CMS. Any properties and event listeners present will be applied to the element. + +The only supported binding is `bind:this`, since Svelte's built-in bindings do not work with generic elements. + +If `this` has a nullish value, the element and its children will not be rendered. + +If `this` is the name of a [void element](https://developer.mozilla.org/en-US/docs/Glossary/Void_element) (e.g., `br`) and `` has child elements, a runtime error will be thrown in development mode: + +```svelte + + + + This text cannot appear inside an hr element + +``` + +Svelte tries its best to infer the correct namespace from the element's surroundings, but it's not always possible. You can make it explicit with an `xmlns` attribute: + +```svelte + +``` + +`this` needs to be a valid DOM element tag, things like `#text` or `svelte:head` will not work. diff --git a/documentation/docs/05-special-elements/07-svelte-options.md b/documentation/docs/05-special-elements/07-svelte-options.md new file mode 100644 index 000000000000..d29042e278d4 --- /dev/null +++ b/documentation/docs/05-special-elements/07-svelte-options.md @@ -0,0 +1,27 @@ +--- +title: +--- + +```svelte + +``` + +The `` element provides a place to specify per-component compiler options, which are detailed in the [compiler section](svelte-compiler#compile). The possible options are: + +- `runes={true}` — forces a component into _runes mode_ (see the [Legacy APIs](legacy-overview) section) +- `runes={false}` — forces a component into _legacy mode_ +- `namespace="..."` — the namespace where this component will be used, can be "html" (the default), "svg" or "mathml" +- `customElement={...}` — the [options](custom-elements#Component-options) to use when compiling this component as a custom element. If a string is passed, it is used as the `tag` option +- `css="injected"` — the component will inject its styles inline: During server side rendering, it's injected as a ` +``` + +### element_invalid_self_closing_tag + +``` +Self-closing HTML tags for non-void elements are ambiguous — use `<%name% ...>` rather than `<%name% ... />` +``` + +In HTML, there's [no such thing as a self-closing tag](https://jakearchibald.com/2023/against-self-closing-tags-in-html/). While this _looks_ like a self-contained element with some text next to it... + +```html +
+ some text! +
+``` + +...a spec-compliant HTML parser (such as a browser) will in fact parse it like this, with the text _inside_ the icon: + +```html +
+ some text! +
+``` + +Some templating languages (including Svelte) will 'fix' HTML by turning `` into ``. Others adhere to the spec. Both result in ambiguity and confusion when copy-pasting code between different contexts, and as such Svelte prompts you to resolve the ambiguity directly by having an explicit closing tag. + +To automate this, run the dedicated migration: + +```bash +npx sv migrate self-closing-tags +``` + +In a future version of Svelte, self-closing tags may be upgraded from a warning to an error. + +### event_directive_deprecated + +``` +Using `on:%name%` to listen to the %name% event is deprecated. Use the event attribute `on%name%` instead +``` + +See [the migration guide](v5-migration-guide#Event-changes) for more info. + +### export_let_unused + +``` +Component has unused export property '%name%'. If it is for external reference only, please consider using `export const %name%` +``` + +### legacy_code + +``` +`%code%` is no longer valid — please use `%suggestion%` instead +``` + +### legacy_component_creation + +``` +Svelte 5 components are no longer classes. Instantiate them using `mount` or `hydrate` (imported from 'svelte') instead. +``` + +See the [migration guide](v5-migration-guide#Components-are-no-longer-classes) for more info. + +### node_invalid_placement_ssr + +``` +%message%. When rendering this component on the server, the resulting HTML will be modified by the browser (by moving, removing, or inserting elements), likely resulting in a `hydration_mismatch` warning +``` + +HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples: + +- `

hello

world

` will result in `

hello

world

` (the `
` autoclosed the `

` because `

` cannot contain block-level elements) +- `

option a
` will result in `` (the `
` is removed) +- `
cell
` will result in `
cell
` (a `` is auto-inserted) + +This code will work when the component is rendered on the client (which is why this is a warning rather than an error), but if you use server rendering it will cause hydration to fail. + +### non_reactive_update + +``` +`%name%` is updated, but is not declared with `$state(...)`. Changing its value will not correctly trigger updates +``` + +This warning is thrown when the compiler detects the following: +- a variable was declared without `$state` or `$state.raw` +- the variable is reassigned +- the variable is read in a reactive context + +In this case, changing the value will not correctly trigger updates. Example: + +```svelte + + +

This value updates: {reactive}

+

This value does not update: {stale}

+ + +``` + +To fix this, wrap your variable declaration with `$state`. + +### options_deprecated_accessors + +``` +The `accessors` option has been deprecated. It will have no effect in runes mode +``` + +### options_deprecated_immutable + +``` +The `immutable` option has been deprecated. It will have no effect in runes mode +``` + +### options_missing_custom_element + +``` +The `customElement` option is used when generating a custom element. Did you forget the `customElement: true` compile option? +``` + +### options_removed_enable_sourcemap + +``` +The `enableSourcemap` option has been removed. Source maps are always generated now, and tooling can choose to ignore them +``` + +### options_removed_hydratable + +``` +The `hydratable` option has been removed. Svelte components are always hydratable now +``` + +### options_removed_loop_guard_timeout + +``` +The `loopGuardTimeout` option has been removed +``` + +### options_renamed_ssr_dom + +``` +`generate: "dom"` and `generate: "ssr"` options have been renamed to "client" and "server" respectively +``` + +### perf_avoid_inline_class + +``` +Avoid 'new class' — instead, declare the class at the top level scope +``` + +### perf_avoid_nested_class + +``` +Avoid declaring classes below the top level scope +``` + +### reactive_declaration_invalid_placement + +``` +Reactive declarations only exist at the top level of the instance script +``` + +### reactive_declaration_module_script_dependency + +``` +Reassignments of module-level declarations will not cause reactive statements to update +``` + +### script_context_deprecated + +``` +`context="module"` is deprecated, use the `module` attribute instead +``` + +```svelte + +``` + +### script_unknown_attribute + +``` +Unrecognized attribute — should be one of `generics`, `lang` or `module`. If this exists for a preprocessor, ensure that the preprocessor removes it +``` + +### slot_element_deprecated + +``` +Using `` to render parent content is deprecated. Use `{@render ...}` tags instead +``` + +See [the migration guide](v5-migration-guide#Snippets-instead-of-slots) for more info. + +### state_referenced_locally + +``` +State referenced in its own scope will never update. Did you mean to reference it inside a closure? +``` + +This warning is thrown when the compiler detects the following: +- A reactive variable is declared +- the variable is reassigned +- the variable is referenced inside the same scope it is declared and it is a non-reactive context + +In this case, the state reassignment will not be noticed by whatever you passed it to. For example, if you pass the state to a function, that function will not notice the updates: + +```svelte + + + + +``` + +```svelte + + + + +

The count is {count}

+``` + +To fix this, reference the variable such that it is lazily evaluated. For the above example, this can be achieved by wrapping `count` in a function: + +```svelte + + + + +``` + +```svelte + + + + +

The count is {+++count()+++}

+``` + +For more info, see [Passing state into functions]($state#Passing-state-into-functions). + +### store_rune_conflict + +``` +It looks like you're using the `$%name%` rune, but there is a local binding called `%name%`. Referencing a local variable with a `$` prefix will create a store subscription. Please rename `%name%` to avoid the ambiguity +``` + +### svelte_component_deprecated + +``` +`` is deprecated in runes mode — components are dynamic by default +``` + +In previous versions of Svelte, the component constructor was fixed when the component was rendered. In other words, if you wanted `` to re-render when `X` changed, you would either have to use `` or put the component inside a `{#key X}...{/key}` block. + +In Svelte 5 this is no longer true — if `X` changes, `` re-renders. + +In some cases `` syntax can be used as a replacement; a lowercased variable with property access is recognized as a component in Svelte 5. + +For complex component resolution logic, an intermediary, capitalized variable may be necessary. E.g. in places where `@const` can be used: + + +```svelte +{#each items as item} + ------ + +++{@const Component = item.condition ? Y : Z}+++ + ++++++ +{/each} +``` + +A derived value may be used in other contexts: + + +```svelte + + +------ +++++++ +``` + +### svelte_element_invalid_this + +``` +`this` should be an `{expression}`. Using a string attribute value will cause an error in future versions of Svelte +``` + +### svelte_self_deprecated + +``` +`` is deprecated — use self-imports (e.g. `import %name% from './%basename%'`) instead +``` + +See [the note in the docs](legacy-svelte-self) for more info. + +### unknown_code + +``` +`%code%` is not a recognised code +``` + +``` +`%code%` is not a recognised code (did you mean `%suggestion%`?) +``` diff --git a/documentation/docs/98-reference/.generated/server-errors.md b/documentation/docs/98-reference/.generated/server-errors.md new file mode 100644 index 000000000000..c3e8b53c3145 --- /dev/null +++ b/documentation/docs/98-reference/.generated/server-errors.md @@ -0,0 +1,9 @@ + + +### lifecycle_function_unavailable + +``` +`%name%(...)` is not available on the server +``` + +Certain methods such as `mount` cannot be invoked while running in a server context. Avoid calling them eagerly, i.e. not during render. diff --git a/documentation/docs/98-reference/.generated/shared-errors.md b/documentation/docs/98-reference/.generated/shared-errors.md new file mode 100644 index 000000000000..0102aafcbca1 --- /dev/null +++ b/documentation/docs/98-reference/.generated/shared-errors.md @@ -0,0 +1,67 @@ + + +### invalid_default_snippet + +``` +Cannot use `{@render children(...)}` if the parent component uses `let:` directives. Consider using a named snippet instead +``` + +This error would be thrown in a setup like this: + +```svelte + + + {entry} + +``` + +```svelte + + + +
    + {#each items as item} +
  • {@render children(item)}
  • + {/each} +
+``` + +Here, `List.svelte` is using `{@render children(item)` which means it expects `Parent.svelte` to use snippets. Instead, `Parent.svelte` uses the deprecated `let:` directive. This combination of APIs is incompatible, hence the error. + +### lifecycle_outside_component + +``` +`%name%(...)` can only be used during component initialisation +``` + +Certain lifecycle methods can only be used during component initialisation. To fix this, make sure you're invoking the method inside the _top level of the instance script_ of your component. + +```svelte + + + +``` + +### store_invalid_shape + +``` +`%name%` is not a store with a `subscribe` method +``` + +### svelte_element_invalid_this_value + +``` +The `this` prop on `` must be a string, if defined +``` diff --git a/documentation/docs/98-reference/.generated/shared-warnings.md b/documentation/docs/98-reference/.generated/shared-warnings.md new file mode 100644 index 000000000000..f449a4031ebf --- /dev/null +++ b/documentation/docs/98-reference/.generated/shared-warnings.md @@ -0,0 +1,28 @@ + + +### dynamic_void_element_content + +``` +`` is a void element — it cannot have content +``` + +Elements such as `` cannot have content, any children passed to these elements will be ignored. + +### state_snapshot_uncloneable + +``` +Value cannot be cloned with `$state.snapshot` — the original value was returned +``` + +``` +The following properties cannot be cloned with `$state.snapshot` — the return value contains the originals: + +%properties% +``` + +`$state.snapshot` tries to clone the given value in order to return a reference that no longer changes. Certain objects may not be cloneable, in which case the original value is returned. In the following example, `property` is cloned, but `window` is not, because DOM elements are uncloneable: + +```js +const object = $state({ property: 'this is cloneable', window }) +const snapshot = $state.snapshot(object); +``` diff --git a/documentation/docs/98-reference/20-svelte.md b/documentation/docs/98-reference/20-svelte.md new file mode 100644 index 000000000000..3295ab68de65 --- /dev/null +++ b/documentation/docs/98-reference/20-svelte.md @@ -0,0 +1,5 @@ +--- +title: svelte +--- + +> MODULE: svelte diff --git a/documentation/docs/98-reference/21-svelte-action.md b/documentation/docs/98-reference/21-svelte-action.md new file mode 100644 index 000000000000..53423ec4090e --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-action.md @@ -0,0 +1,5 @@ +--- +title: svelte/action +--- + +> MODULE: svelte/action diff --git a/documentation/docs/98-reference/21-svelte-animate.md b/documentation/docs/98-reference/21-svelte-animate.md new file mode 100644 index 000000000000..e8f135d07de0 --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-animate.md @@ -0,0 +1,5 @@ +--- +title: svelte/animate +--- + +> MODULE: svelte/animate diff --git a/documentation/docs/98-reference/21-svelte-compiler.md b/documentation/docs/98-reference/21-svelte-compiler.md new file mode 100644 index 000000000000..a6cc99d3b155 --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-compiler.md @@ -0,0 +1,5 @@ +--- +title: svelte/compiler +--- + +> MODULE: svelte/compiler diff --git a/documentation/docs/98-reference/21-svelte-easing.md b/documentation/docs/98-reference/21-svelte-easing.md new file mode 100644 index 000000000000..3f47963cde9a --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-easing.md @@ -0,0 +1,5 @@ +--- +title: svelte/easing +--- + +> MODULE: svelte/easing diff --git a/documentation/docs/98-reference/21-svelte-events.md b/documentation/docs/98-reference/21-svelte-events.md new file mode 100644 index 000000000000..00c7a14ee203 --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-events.md @@ -0,0 +1,5 @@ +--- +title: svelte/events +--- + +> MODULE: svelte/events diff --git a/documentation/docs/98-reference/21-svelte-legacy.md b/documentation/docs/98-reference/21-svelte-legacy.md new file mode 100644 index 000000000000..f313baca0b45 --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-legacy.md @@ -0,0 +1,7 @@ +--- +title: svelte/legacy +--- + +This module provides various functions for use during the migration, since some features can't be replaced one to one with new features. All imports are marked as deprecated and should be migrated away from over time. + +> MODULE: svelte/legacy diff --git a/documentation/docs/98-reference/21-svelte-motion.md b/documentation/docs/98-reference/21-svelte-motion.md new file mode 100644 index 000000000000..f1d5a6ce5757 --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-motion.md @@ -0,0 +1,5 @@ +--- +title: svelte/motion +--- + +> MODULE: svelte/motion diff --git a/documentation/docs/98-reference/21-svelte-reactivity-window.md b/documentation/docs/98-reference/21-svelte-reactivity-window.md new file mode 100644 index 000000000000..cc544dc5ba3f --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-reactivity-window.md @@ -0,0 +1,15 @@ +--- +title: svelte/reactivity/window +--- + +This module exports reactive versions of various `window` values, each of which has a reactive `current` property that you can reference in reactive contexts (templates, [deriveds]($derived) and [effects]($effect)) without using [``](svelte-window) bindings or manually creating your own event listeners. + +```svelte + + +

{innerWidth.current}x{innerHeight.current}

+``` + +> MODULE: svelte/reactivity/window diff --git a/documentation/docs/98-reference/21-svelte-reactivity.md b/documentation/docs/98-reference/21-svelte-reactivity.md new file mode 100644 index 000000000000..6857c1dba80d --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-reactivity.md @@ -0,0 +1,25 @@ +--- +title: svelte/reactivity +--- + +Svelte provides reactive versions of various built-ins like `SvelteMap`, `SvelteSet` and `SvelteURL`. These can be imported from `svelte/reactivity` and used just like their native counterparts. + +```svelte + + + + + + + +
+ + + +``` + +> MODULE: svelte/reactivity diff --git a/documentation/docs/98-reference/21-svelte-server.md b/documentation/docs/98-reference/21-svelte-server.md new file mode 100644 index 000000000000..7a3fc3c6a2ba --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-server.md @@ -0,0 +1,5 @@ +--- +title: svelte/server +--- + +> MODULE: svelte/server diff --git a/documentation/docs/98-reference/21-svelte-store.md b/documentation/docs/98-reference/21-svelte-store.md new file mode 100644 index 000000000000..23ff6c5e376f --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-store.md @@ -0,0 +1,5 @@ +--- +title: svelte/store +--- + +> MODULE: svelte/store diff --git a/documentation/docs/98-reference/21-svelte-transition.md b/documentation/docs/98-reference/21-svelte-transition.md new file mode 100644 index 000000000000..396bc0aebf69 --- /dev/null +++ b/documentation/docs/98-reference/21-svelte-transition.md @@ -0,0 +1,5 @@ +--- +title: svelte/transition +--- + +> MODULE: svelte/transition diff --git a/documentation/docs/98-reference/30-compiler-errors.md b/documentation/docs/98-reference/30-compiler-errors.md new file mode 100644 index 000000000000..ae22029155d3 --- /dev/null +++ b/documentation/docs/98-reference/30-compiler-errors.md @@ -0,0 +1,5 @@ +--- +title: 'Compiler errors' +--- + +@include .generated/compile-errors.md diff --git a/documentation/docs/98-reference/30-compiler-warnings.md b/documentation/docs/98-reference/30-compiler-warnings.md new file mode 100644 index 000000000000..43ba71250f5b --- /dev/null +++ b/documentation/docs/98-reference/30-compiler-warnings.md @@ -0,0 +1,21 @@ +--- +title: 'Compiler warnings' +--- + +Svelte warns you at compile time if it catches potential mistakes, such as writing inaccessible markup. + +Some warnings may be incorrect in your concrete use case. You can disable such false positives by placing a `` comment above the line that causes the warning. Example: + +```svelte + + +``` + +You can list multiple rules in a single comment (separated by commas), and add an explanatory note (in parentheses) alongside them: + +```svelte + +
...
+``` + +@include .generated/compile-warnings.md diff --git a/documentation/docs/98-reference/30-runtime-errors.md b/documentation/docs/98-reference/30-runtime-errors.md new file mode 100644 index 000000000000..43ce98958751 --- /dev/null +++ b/documentation/docs/98-reference/30-runtime-errors.md @@ -0,0 +1,15 @@ +--- +title: 'Runtime errors' +--- + +## Client errors + +@include .generated/client-errors.md + +## Server errors + +@include .generated/server-errors.md + +## Shared errors + +@include .generated/shared-errors.md diff --git a/documentation/docs/98-reference/30-runtime-warnings.md b/documentation/docs/98-reference/30-runtime-warnings.md new file mode 100644 index 000000000000..edc5890ac0fa --- /dev/null +++ b/documentation/docs/98-reference/30-runtime-warnings.md @@ -0,0 +1,11 @@ +--- +title: 'Runtime warnings' +--- + +## Client warnings + +@include .generated/client-warnings.md + +## Shared warnings + +@include .generated/shared-warnings.md diff --git a/documentation/docs/98-reference/index.md b/documentation/docs/98-reference/index.md new file mode 100644 index 000000000000..b98302768eb0 --- /dev/null +++ b/documentation/docs/98-reference/index.md @@ -0,0 +1,3 @@ +--- +title: Reference +--- diff --git a/documentation/docs/99-legacy/00-legacy-overview.md b/documentation/docs/99-legacy/00-legacy-overview.md new file mode 100644 index 000000000000..638a77ec1a76 --- /dev/null +++ b/documentation/docs/99-legacy/00-legacy-overview.md @@ -0,0 +1,14 @@ +--- +title: Overview +--- + +Svelte 5 introduced some significant changes to Svelte's API, including [runes](what-are-runes), [snippets](snippet) and event attributes. As a result, some Svelte 3/4 features are deprecated (though supported for now, unless otherwise specified) and will eventually be removed. We recommend that you incrementally [migrate your existing code](v5-migration-guide). + +The following pages document these features for + +- people still using Svelte 3/4 +- people using Svelte 5, but with components that haven't yet been migrated + +Since Svelte 3/4 syntax still works in Svelte 5, we will distinguish between _legacy mode_ and _runes mode_. Once a component is in runes mode (which you can opt into by using runes, or by explicitly setting the `runes: true` compiler option), legacy mode features are no longer available. + +If you're exclusively interested in the Svelte 3/4 syntax, you can browse its documentation at [v4.svelte.dev](https://v4.svelte.dev). diff --git a/documentation/docs/99-legacy/01-legacy-let.md b/documentation/docs/99-legacy/01-legacy-let.md new file mode 100644 index 000000000000..0d1a0a72bf11 --- /dev/null +++ b/documentation/docs/99-legacy/01-legacy-let.md @@ -0,0 +1,34 @@ +--- +title: Reactive let/var declarations +--- + +In runes mode, reactive state is explicitly declared with the [`$state` rune]($state). + +In legacy mode, variables declared at the top level of a component are automatically considered _reactive_. Reassigning or mutating these variables (`count += 1` or `object.x = y`) will cause the UI to update. + +```svelte + + + +``` + +Because Svelte's legacy mode reactivity is based on _assignments_, using array methods like `.push()` and `.splice()` won't automatically trigger updates. A subsequent assignment is required to 'tell' the compiler to update the UI: + +```svelte + +``` diff --git a/documentation/docs/99-legacy/02-legacy-reactive-assignments.md b/documentation/docs/99-legacy/02-legacy-reactive-assignments.md new file mode 100644 index 000000000000..5abd481bfc74 --- /dev/null +++ b/documentation/docs/99-legacy/02-legacy-reactive-assignments.md @@ -0,0 +1,87 @@ +--- +title: Reactive $: statements +--- + +In runes mode, reactions to state updates are handled with the [`$derived`]($derived) and [`$effect`]($effect) runes. + +In legacy mode, any top-level statement (i.e. not inside a block or a function) can be made reactive by prefixing it with a `$:` [label](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label). These statements run after other code in the ` +``` + +Statements are ordered _topologically_ by their dependencies and their assignments: since the `console.log` statement depends on `sum`, `sum` is calculated first even though it appears later in the source. + +Multiple statements can be combined by putting them in a block: + +```js +// @noErrors +$: { + // recalculate `total` when `items` changes + total = 0; + + for (const item of items) { + total += item.value; + } +} +``` + +The left-hand side of a reactive assignments can be an identifier, or it can be a destructuring assignment: + +```js +// @noErrors +$: ({ larry, moe, curly } = stooges); +``` + +## Understanding dependencies + +The dependencies of a `$:` statement are determined at compile time — they are whichever variables are referenced (but not assigned to) inside the statement. + +In other words, a statement like this will _not_ re-run when `count` changes, because the compiler cannot 'see' the dependency: + +```js +// @noErrors +let count = 0; +let double = () => count * 2; + +$: doubled = double(); +``` + +Similarly, topological ordering will fail if dependencies are referenced indirectly: `z` will never update, because `y` is not considered 'dirty' when the update occurs. Moving `$: z = y` below `$: setY(x)` will fix it: + +```svelte + +``` + +## Browser-only code + +Reactive statements run during server-side rendering as well as in the browser. This means that any code that should only run in the browser must be wrapped in an `if` block: + +```js +// @noErrors +$: if (browser) { + document.title = title; +} +``` diff --git a/documentation/docs/99-legacy/03-legacy-export-let.md b/documentation/docs/99-legacy/03-legacy-export-let.md new file mode 100644 index 000000000000..877e105b1fa2 --- /dev/null +++ b/documentation/docs/99-legacy/03-legacy-export-let.md @@ -0,0 +1,72 @@ +--- +title: export let +--- + +In runes mode, [component props](basic-markup#Component-props) are declared with the [`$props`]($props) rune, allowing parent components to pass in data. + +In legacy mode, props are marked with the `export` keyword, and can have a default value: + +```svelte + +``` + +The default value is used if it would otherwise be `undefined` when the component is created. + +> [!NOTE] Unlike in runes mode, if the parent component changes a prop from a defined value to `undefined`, it does not revert to the initial value. + +Props without default values are considered _required_, and Svelte will print a warning during development if no value is provided, which you can squelch by specifying `undefined` as the default value: + +```js +export let foo +++= undefined;+++ +``` + +## Component exports + +An exported `const`, `class` or `function` declaration is _not_ considered a prop — instead, it becomes part of the component's API: + +```svelte + + +``` + +```svelte + + + + + + +``` + +## Renaming props + +The `export` keyword can appear separately from the declaration. This is useful for renaming props, for example in the case of a reserved word: + +```svelte + + +``` diff --git a/documentation/docs/99-legacy/04-legacy-$$props-and-$$restProps.md b/documentation/docs/99-legacy/04-legacy-$$props-and-$$restProps.md new file mode 100644 index 000000000000..33cac97035af --- /dev/null +++ b/documentation/docs/99-legacy/04-legacy-$$props-and-$$restProps.md @@ -0,0 +1,30 @@ +--- +title: $$props and $$restProps +--- + +In runes mode, getting an object containing all the props that were passed in is easy, using the [`$props`]($props) rune. + +In legacy mode, we use `$$props` and `$$restProps`: + +- `$$props` contains all the props that were passed in, including ones that are not individually declared with the `export` keyword +- `$$restProps` contains all the props that were passed in _except_ the ones that were individually declared + +For example, a ` + + +``` + +In Svelte 3/4 using `$$props` and `$$restProps` creates a modest performance penalty, so they should only be used when needed. diff --git a/documentation/docs/99-legacy/10-legacy-on.md b/documentation/docs/99-legacy/10-legacy-on.md new file mode 100644 index 000000000000..f2ee694cc1e0 --- /dev/null +++ b/documentation/docs/99-legacy/10-legacy-on.md @@ -0,0 +1,136 @@ +--- +title: on: +--- + +In runes mode, event handlers are just like any other attribute or prop. + +In legacy mode, we use the `on:` directive: + +```svelte + + + + +``` + +Handlers can be declared inline with no performance penalty: + +```svelte + +``` + +Add _modifiers_ to element event handlers with the `|` character. + +```svelte +
+ +
+``` + +The following modifiers are available: + +- `preventDefault` — calls `event.preventDefault()` before running the handler +- `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element +- `stopImmediatePropagation` - calls `event.stopImmediatePropagation()`, preventing other listeners of the same event from being fired. +- `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so) +- `nonpassive` — explicitly set `passive: false` +- `capture` — fires the handler during the _capture_ phase instead of the _bubbling_ phase +- `once` — remove the handler after the first time it runs +- `self` — only trigger handler if `event.target` is the element itself +- `trusted` — only trigger handler if `event.isTrusted` is `true`. I.e. if the event is triggered by a user action. + +Modifiers can be chained together, e.g. `on:click|once|capture={...}`. + +If the `on:` directive is used without a value, the component will _forward_ the event, meaning that a consumer of the component can listen for it. + +```svelte + +``` + +It's possible to have multiple event listeners for the same event: + +```svelte + + + + +``` + +## Component events + +Components can dispatch events by creating a _dispatcher_ when they are initialised: + +```svelte + + + + + +``` + +`dispatch` creates a [`CustomEvent`](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). If a second argument is provided, it becomes the `detail` property of the event object. + +A consumer of this component can listen for the dispatched events: + +```svelte + + + n -= 1} + on:increment={() => n += 1} +/> + +

n: {n}

+``` + +Component events do not bubble — a parent component can only listen for events on its immediate children. + +Other than `once`, modifiers are not valid on component event handlers. + +> [!NOTE] +> If you're planning an eventual migration to Svelte 5, use callback props instead. This will make upgrading easier as `createEventDispatcher` is deprecated: +> +> ```svelte +> +> +> +> +> +> ``` diff --git a/documentation/docs/99-legacy/20-legacy-slots.md b/documentation/docs/99-legacy/20-legacy-slots.md new file mode 100644 index 000000000000..3474782e93ae --- /dev/null +++ b/documentation/docs/99-legacy/20-legacy-slots.md @@ -0,0 +1,122 @@ +--- +title: +--- + +In Svelte 5, content can be passed to components in the form of [snippets](snippet) and rendered using [render tags](@render). + +In legacy mode, content inside component tags is considered _slotted content_, which can be rendered by the component using a `` element: + +```svelte + + + +This is some slotted content +``` + +```svelte + + +``` + +> [!NOTE] If you want to render a regular `` element, you can use ``. + +## Named slots + +A component can have _named_ slots in addition to the default slot. On the parent side, add a `slot="..."` attribute to an element, component or [``](legacy-svelte-fragment) directly inside the component tags. + +```svelte + + + +{#if open} + + This is some slotted content + + +++
+++ + + +++
+++ +
+{/if} +``` + +On the child side, add a corresponding `` element: + +```svelte + + +``` + +## Fallback content + +If no slotted content is provided, a component can define fallback content by putting it inside the `` element: + +```svelte + + This will be rendered if no slotted content is provided + +``` + +## Passing data to slotted content + +Slots can be rendered zero or more times and can pass values _back_ to the parent using props. The parent exposes the values to the slot template using the `let:` directive. + +```svelte + +
    + {#each items as data} +
  • + + +
  • + {/each} +
+``` + +```svelte + + + +
{processed.text}
+
+``` + +The usual shorthand rules apply — `let:item` is equivalent to `let:item={item}`, and `` is equivalent to ``. + +Named slots can also expose values. The `let:` directive goes on the element with the `slot` attribute. + +```svelte + +
    + {#each items as item} +
  • + +
  • + {/each} +
+ + +``` + +```svelte + + +
{item.text}
+

Copyright (c) 2019 Svelte Industries

+
+``` + + diff --git a/documentation/docs/99-legacy/21-legacy-$$slots.md b/documentation/docs/99-legacy/21-legacy-$$slots.md new file mode 100644 index 000000000000..7ca1cef8445a --- /dev/null +++ b/documentation/docs/99-legacy/21-legacy-$$slots.md @@ -0,0 +1,27 @@ +--- +title: $$slots +--- + +In runes mode, we know which [snippets](snippet) were provided to a component, as they're just normal props. + +In legacy mode, the way to know if content was provided for a given slot is with the `$$slots` object, whose keys are the names of the slots passed into the component by the parent. + +```svelte + +
+ + {#if $$slots.description} + +
+ + {/if} +
+``` + +```svelte + + +

Blog Post Title

+ +
+``` diff --git a/documentation/docs/99-legacy/22-legacy-svelte-fragment.md b/documentation/docs/99-legacy/22-legacy-svelte-fragment.md new file mode 100644 index 000000000000..779931f94753 --- /dev/null +++ b/documentation/docs/99-legacy/22-legacy-svelte-fragment.md @@ -0,0 +1,32 @@ +--- +title: +--- + +The `` element allows you to place content in a [named slot](legacy-slots) without wrapping it in a container DOM element. This keeps the flow layout of your document intact. + +```svelte + +
+ No header was provided +

Some content between header and footer

+ +
+``` + +```svelte + + + + +

Hello

+ +

All rights reserved.

+

Copyright (c) 2019 Svelte Industries

+
+
+``` + +> [!NOTE] +> In Svelte 5+, this concept is obsolete, as snippets don't create a wrapping element diff --git a/documentation/docs/99-legacy/30-legacy-svelte-component.md b/documentation/docs/99-legacy/30-legacy-svelte-component.md new file mode 100644 index 000000000000..a0407e58bfbf --- /dev/null +++ b/documentation/docs/99-legacy/30-legacy-svelte-component.md @@ -0,0 +1,13 @@ +--- +title: +--- + +In runes mode, `` will re-render if the value of `MyComponent` changes. See the [Svelte 5 migration guide](/docs/svelte/v5-migration-guide#svelte:component-is-no-longer-necessary) for an example. + +In legacy mode, it won't — we must use ``, which destroys and recreates the component instance when the value of its `this` expression changes: + +```svelte + +``` + +If `this` is falsy, no component is rendered. diff --git a/documentation/docs/99-legacy/31-legacy-svelte-self.md b/documentation/docs/99-legacy/31-legacy-svelte-self.md new file mode 100644 index 000000000000..bfd140ac49dc --- /dev/null +++ b/documentation/docs/99-legacy/31-legacy-svelte-self.md @@ -0,0 +1,37 @@ +--- +title: +--- + +The `` element allows a component to include itself, recursively. + +It cannot appear at the top level of your markup; it must be inside an if or each block or passed to a component's slot to prevent an infinite loop. + +```svelte + + +{#if count > 0} +

counting down... {count}

+ +{:else} +

lift-off!

+{/if} +``` + +> [!NOTE] +> This concept is obsolete, as components can import themselves: +> ```svelte +> +> +> +> {#if count > 0} +>

counting down... {count}

+> +> {:else} +>

lift-off!

+> {/if} +> ``` diff --git a/documentation/docs/99-legacy/40-legacy-component-api.md b/documentation/docs/99-legacy/40-legacy-component-api.md new file mode 100644 index 000000000000..a08f53951c20 --- /dev/null +++ b/documentation/docs/99-legacy/40-legacy-component-api.md @@ -0,0 +1,200 @@ +--- +title: Imperative component API +--- + +In Svelte 3 and 4, the API for interacting with a component is different than in Svelte 5. Note that this page does _not_ apply to legacy mode components in a Svelte 5 application. + +## Creating a component + +```ts +// @noErrors +const component = new Component(options); +``` + +A client-side component — that is, a component compiled with `generate: 'dom'` (or the `generate` option left unspecified) is a JavaScript class. + +```ts +// @noErrors +import App from './App.svelte'; + +const app = new App({ + target: document.body, + props: { + // assuming App.svelte contains something like + // `export let answer`: + answer: 42 + } +}); +``` + +The following initialisation options can be provided: + +| option | default | description | +| --------- | ----------- | ---------------------------------------------------------------------------------------------------- | +| `target` | **none** | An `HTMLElement` or `ShadowRoot` to render to. This option is required | +| `anchor` | `null` | A child of `target` to render the component immediately before | +| `props` | `{}` | An object of properties to supply to the component | +| `context` | `new Map()` | A `Map` of root-level context key-value pairs to supply to the component | +| `hydrate` | `false` | See below | +| `intro` | `false` | If `true`, will play transitions on initial render, rather than waiting for subsequent state changes | + +Existing children of `target` are left where they are. + +The `hydrate` option instructs Svelte to upgrade existing DOM (usually from server-side rendering) rather than creating new elements. It will only work if the component was compiled with the [`hydratable: true` option](/docs/svelte-compiler#compile). Hydration of `` elements only works properly if the server-side rendering code was also compiled with `hydratable: true`, which adds a marker to each element in the `` so that the component knows which elements it's responsible for removing during hydration. + +Whereas children of `target` are normally left alone, `hydrate: true` will cause any children to be removed. For that reason, the `anchor` option cannot be used alongside `hydrate: true`. + +The existing DOM doesn't need to match the component — Svelte will 'repair' the DOM as it goes. + +```ts +/// file: index.js +// @noErrors +import App from './App.svelte'; + +const app = new App({ + target: document.querySelector('#server-rendered-html'), + hydrate: true +}); +``` + +> [!NOTE] +> In Svelte 5+, use [`mount`](svelte#mount) instead + +## `$set` + +```ts +// @noErrors +component.$set(props); +``` + +Programmatically sets props on an instance. `component.$set({ x: 1 })` is equivalent to `x = 1` inside the component's `'` string occurrence breaking pages ([#349](https://github.com/sveltejs/svelte/pull/349)) +- Allow reference to whitelisted globals without properties ([#333](https://github.com/sveltejs/svelte/pull/333)) +- Don't remove ` ` incorrectly ([#348](https://github.com/sveltejs/svelte/issues/348)) +- `let` -> `var` in `addCss` block ([#351](https://github.com/sveltejs/svelte/pull/351)) + +## 1.10.2 + +- Accept any case for doctype declarations ([#336](https://github.com/sveltejs/svelte/issues/336)) +- Allow non-top-level ` + + + +

{count} is even: {even}

+

{count} is odd: {odd}

+``` + +This is forbidden because it introduces instability: if `

{count} is even: {even}

` is updated before `odd` is recalculated, `even` will be stale. In most cases the solution is to make everything derived: + +```js +let count = 0; +// ---cut--- +let even = $derived(count % 2 === 0); +let odd = $derived(!even); +``` + +If side-effects are unavoidable, use [`$effect`]($effect) instead. diff --git a/packages/svelte/messages/client-warnings/warnings.md b/packages/svelte/messages/client-warnings/warnings.md new file mode 100644 index 000000000000..943cf6f01f4f --- /dev/null +++ b/packages/svelte/messages/client-warnings/warnings.md @@ -0,0 +1,198 @@ +## assignment_value_stale + +> Assignment to `%property%` property (%location%) will evaluate to the right-hand side, not the value of `%property%` following the assignment. This may result in unexpected behaviour. + +Given a case like this... + +```svelte + + + +

items: {JSON.stringify(object.items)}

+``` + +...the array being pushed to when the button is first clicked is the `[]` on the right-hand side of the assignment, but the resulting value of `object.array` is an empty state proxy. As a result, the pushed value will be discarded. + +You can fix this by separating it into two statements: + +```js +let object = { array: [0] }; +// ---cut--- +function add() { + object.array ??= []; + object.array.push(object.array.length); +} +``` + +## binding_property_non_reactive + +> `%binding%` is binding to a non-reactive property + +> `%binding%` (%location%) is binding to a non-reactive property + +## console_log_state + +> Your `console.%method%` contained `$state` proxies. Consider using `$inspect(...)` or `$state.snapshot(...)` instead + +When logging a [proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), browser devtools will log the proxy itself rather than the value it represents. In the case of Svelte, the 'target' of a `$state` proxy might not resemble its current value, which can be confusing. + +The easiest way to log a value as it changes over time is to use the [`$inspect`](/docs/svelte/$inspect) rune. Alternatively, to log things on a one-off basis (for example, inside an event handler) you can use [`$state.snapshot`](/docs/svelte/$state#$state.snapshot) to take a snapshot of the current value. + +## event_handler_invalid + +> %handler% should be a function. Did you mean to %suggestion%? + +## hydration_attribute_changed + +> The `%attribute%` attribute on `%html%` changed its value between server and client renders. The client value, `%value%`, will be ignored in favour of the server value + +Certain attributes like `src` on an `` element will not be repaired during hydration, i.e. the server value will be kept. That's because updating these attributes can cause the image to be refetched (or in the case of an ` diff --git a/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/Child.svelte b/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/Child.svelte new file mode 100644 index 000000000000..9f2fc953cf30 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/Child.svelte @@ -0,0 +1,16 @@ + + + + +

count: {count}

+ + + diff --git a/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/GrandChild.svelte b/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/GrandChild.svelte new file mode 100644 index 000000000000..9464f7b55feb --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/GrandChild.svelte @@ -0,0 +1,9 @@ + + +

inner

+ + diff --git a/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/_config.js b/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/_config.js new file mode 100644 index 000000000000..efc8db587030 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/_config.js @@ -0,0 +1,24 @@ +import { flushSync } from 'svelte'; +import { test } from '../../assert'; + +export default test({ + async test({ target, assert }) { + const button = target.querySelector('button'); + const h1 = () => + /** @type {NodeListOf} */ ( + /** @type {Window} */ ( + target.querySelector('iframe')?.contentWindow + ).document.querySelectorAll('h1') + ); + + assert.equal(h1()[0].textContent, 'count: 0'); + assert.equal(getComputedStyle(h1()[0]).color, 'rgb(255, 0, 0)'); + assert.equal(getComputedStyle(h1()[1]).color, 'rgb(0, 0, 255)'); + + flushSync(() => button?.click()); + + assert.equal(h1()[0].textContent, 'count: 1'); + assert.equal(getComputedStyle(h1()[0]).color, 'rgb(255, 0, 0)'); + assert.equal(getComputedStyle(h1()[1]).color, 'rgb(0, 0, 255)'); + } +}); diff --git a/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/main.svelte b/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/main.svelte new file mode 100644 index 000000000000..358698f8ecdd --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/mount-in-iframe/main.svelte @@ -0,0 +1,11 @@ + + + + +{#key count} + +{/key} diff --git a/packages/svelte/tests/runtime-browser/samples/sole-script-tag/_config.js b/packages/svelte/tests/runtime-browser/samples/sole-script-tag/_config.js new file mode 100644 index 000000000000..ee1e810d3094 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/sole-script-tag/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../assert'; + +export default test({ + // Test that template with sole script tag does execute when instantiated in the client. + // Needs to be in this test suite because JSDOM does not quite get this right. + mode: ['client'], + async test({ target, assert }) { + // In here to give effects etc time to execute + assert.htmlEqual(target.querySelector('div')?.innerHTML || '', 'this should be executed'); + // Check that the script tag is properly removed + target.querySelector('button')?.click(); + await new Promise((r) => setTimeout(r, 100)); + assert.equal(target.querySelector('script'), null); + } +}); diff --git a/packages/svelte/tests/runtime-browser/samples/sole-script-tag/main.svelte b/packages/svelte/tests/runtime-browser/samples/sole-script-tag/main.svelte new file mode 100644 index 000000000000..eda4cee62943 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/sole-script-tag/main.svelte @@ -0,0 +1,11 @@ + + + +{#if visible} + +{/if} +
after
diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties-dynamic/Slider.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties-dynamic/Slider.svelte new file mode 100644 index 000000000000..4863966f85a6 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties-dynamic/Slider.svelte @@ -0,0 +1,17 @@ + + +
+

Slider

+ Track +
+ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties-dynamic/_config.js b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties-dynamic/_config.js new file mode 100644 index 000000000000..37388413d8e2 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties-dynamic/_config.js @@ -0,0 +1,46 @@ +import { test } from '../../assert'; + +export default test({ + props: { + railColor1: 'black', + trackColor1: 'red', + railColor2: 'green', + trackColor2: 'blue' + }, + html: ` + +
+

Slider

+ Track +
+
+ +
+

Slider

+ Track +
+
+ `, + test({ component, assert, target }) { + component.railColor1 = 'yellow'; + component.trackColor2 = 'orange'; + + assert.htmlEqual( + target.innerHTML, + ` + +
+

Slider

+ Track +
+
+ +
+

Slider

+ Track +
+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties-dynamic/main.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties-dynamic/main.svelte new file mode 100644 index 000000000000..00be45a8a467 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties-dynamic/main.svelte @@ -0,0 +1,25 @@ + + + + + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/Slider1.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/Slider1.svelte new file mode 100644 index 000000000000..f9c9048feea7 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/Slider1.svelte @@ -0,0 +1,17 @@ + + +
+

Slider1

+ Track +
+ + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/Slider2.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/Slider2.svelte new file mode 100644 index 000000000000..eb5c286464d4 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/Slider2.svelte @@ -0,0 +1,17 @@ + + +
+

Slider2

+ Track +
+ + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/_config.js b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/_config.js new file mode 100644 index 000000000000..e9040d8979bd --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/_config.js @@ -0,0 +1,68 @@ +import { assert_ok, test } from '../../assert'; + +export default test({ + props: { + componentName: /** @type {string | undefined} */ ('Slider1') + }, + html: ` + +
+

Slider1

+ Track +
+
+ +
+

Slider1

+ Track +
+
+ `, + test({ target, window, assert, component }) { + function assert_slider_1() { + const rail_color1 = target.querySelector('#component1 p'); + const track_color1 = target.querySelector('#component1 span'); + const rail_color2 = target.querySelector('#component2 p'); + const track_color2 = target.querySelector('#component2 span'); + + assert_ok(rail_color1); + assert_ok(track_color1); + assert_ok(rail_color2); + assert_ok(track_color2); + + assert.equal(window.getComputedStyle(rail_color1).color, 'rgb(0, 0, 0)'); + assert.equal(window.getComputedStyle(track_color1).color, 'rgb(255, 0, 0)'); + assert.equal(window.getComputedStyle(rail_color2).color, 'rgb(0, 255, 0)'); + assert.equal(window.getComputedStyle(track_color2).color, 'rgb(0, 0, 255)'); + assert.equal(rail_color1.textContent, 'Slider1'); + assert.equal(rail_color2.textContent, 'Slider1'); + } + + function assert_slider_2() { + const rail_color1 = target.querySelector('#component1 p'); + const track_color1 = target.querySelector('#component1 span'); + const rail_color2 = target.querySelector('#component2 p'); + const track_color2 = target.querySelector('#component2 span'); + + assert_ok(rail_color1); + assert_ok(track_color1); + assert_ok(rail_color2); + assert_ok(track_color2); + + assert.equal(window.getComputedStyle(rail_color1).color, 'rgb(0, 0, 0)'); + assert.equal(window.getComputedStyle(track_color1).color, 'rgb(255, 0, 0)'); + assert.equal(window.getComputedStyle(rail_color2).color, 'rgb(0, 255, 0)'); + assert.equal(window.getComputedStyle(track_color2).color, 'rgb(0, 0, 255)'); + assert.equal(rail_color1.textContent, 'Slider2'); + assert.equal(rail_color2.textContent, 'Slider2'); + } + + assert_slider_1(); + component.componentName = 'Slider2'; + assert_slider_2(); + component.componentName = undefined; + assert.equal(window.document.querySelector('div')?.firstElementChild, null); + component.componentName = 'Slider1'; + assert_slider_1(); + } +}); diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/main.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/main.svelte new file mode 100644 index 000000000000..2c6d05dc2581 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties/main.svelte @@ -0,0 +1,20 @@ + + + + + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/Slider1.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/Slider1.svelte new file mode 100644 index 000000000000..f9c9048feea7 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/Slider1.svelte @@ -0,0 +1,17 @@ + + +
+

Slider1

+ Track +
+ + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/Slider2.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/Slider2.svelte new file mode 100644 index 000000000000..eb5c286464d4 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/Slider2.svelte @@ -0,0 +1,17 @@ + + +
+

Slider2

+ Track +
+ + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/_config.js b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/_config.js new file mode 100644 index 000000000000..303b1a377ce5 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/_config.js @@ -0,0 +1,70 @@ +import { assert_ok, test } from '../../assert'; + +export default test({ + props: { + componentName: /** @type {string | undefined} */ ('Slider1') + }, + html: ` +
+ +
+

Slider1

+ Track +
+
+ +
+

Slider1

+ Track +
+
+
+ `, + test({ target, window, assert, component }) { + function assert_slider_1() { + const rail_color1 = target.querySelector('#component1 p'); + const track_color1 = target.querySelector('#component1 span'); + const rail_color2 = target.querySelector('#component2 p'); + const track_color2 = target.querySelector('#component2 span'); + + assert_ok(rail_color1); + assert_ok(track_color1); + assert_ok(rail_color2); + assert_ok(track_color2); + + assert.equal(window.getComputedStyle(rail_color1).color, 'rgb(0, 0, 0)'); + assert.equal(window.getComputedStyle(track_color1).color, 'rgb(255, 0, 0)'); + assert.equal(window.getComputedStyle(rail_color2).color, 'rgb(0, 255, 0)'); + assert.equal(window.getComputedStyle(track_color2).color, 'rgb(0, 0, 255)'); + assert.equal(rail_color1.textContent, 'Slider1'); + assert.equal(rail_color2.textContent, 'Slider1'); + } + + function assert_slider_2() { + const rail_color1 = target.querySelector('#component1 p'); + const track_color1 = target.querySelector('#component1 span'); + const rail_color2 = target.querySelector('#component2 p'); + const track_color2 = target.querySelector('#component2 span'); + + assert_ok(rail_color1); + assert_ok(track_color1); + assert_ok(rail_color2); + assert_ok(track_color2); + + assert.equal(window.getComputedStyle(rail_color1).color, 'rgb(0, 0, 0)'); + assert.equal(window.getComputedStyle(track_color1).color, 'rgb(255, 0, 0)'); + assert.equal(window.getComputedStyle(rail_color2).color, 'rgb(0, 255, 0)'); + assert.equal(window.getComputedStyle(track_color2).color, 'rgb(0, 0, 255)'); + assert.equal(rail_color1.textContent, 'Slider2'); + assert.equal(rail_color2.textContent, 'Slider2'); + } + + assert_slider_1(); + component.componentName = 'Slider2'; + assert_slider_2(); + component.componentName = undefined; + assert.equal(window.document.querySelector('div')?.firstElementChild, null); + component.componentName = 'Slider1'; + assert_slider_1(); + } +}); diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/main.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/main.svelte new file mode 100644 index 000000000000..dded9b8f5cf4 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-component-css-custom-properties2/main.svelte @@ -0,0 +1,22 @@ + + +
+ + + +
diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties-dynamic/Slider.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties-dynamic/Slider.svelte new file mode 100644 index 000000000000..210e34cbe971 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties-dynamic/Slider.svelte @@ -0,0 +1,29 @@ + + +
+

Slider

+ Track +
+ +{#if count === 0} + +{/if} + + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties-dynamic/_config.js b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties-dynamic/_config.js new file mode 100644 index 000000000000..e885369deefc --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties-dynamic/_config.js @@ -0,0 +1,76 @@ +import { test } from '../../assert'; + +export default test({ + props: { + railColor1: 'black', + trackColor1: 'red', + railColor2: 'green', + trackColor2: 'blue', + nestRailColor1: 'white', + nestTrackColor1: 'gray', + nestRailColor2: 'aqua', + nestTrackColor2: 'pink' + }, + html: ` + +
+

Slider

+ Track +
+ +
+

Slider

+ Track +
+
+
+ +
+

Slider

+ Track +
+ +
+

Slider

+ Track +
+
+
+ `, + test({ component, assert, target }) { + component.railColor1 = 'yellow'; + component.trackColor2 = 'orange'; + component.nestRailColor1 = 'lime'; + component.nestTrackColor2 = 'gold'; + + assert.htmlEqual( + target.innerHTML, + ` + +
+

Slider

+ Track +
+ +
+

Slider

+ Track +
+
+
+ +
+

Slider

+ Track +
+ +
+

Slider

+ Track +
+
+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties-dynamic/main.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties-dynamic/main.svelte new file mode 100644 index 000000000000..69c31fff3592 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties-dynamic/main.svelte @@ -0,0 +1,32 @@ + + + + + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/Slider1.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/Slider1.svelte new file mode 100644 index 000000000000..20699ca853dc --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/Slider1.svelte @@ -0,0 +1,27 @@ + + +
+

Slider1

+ Track +
+ +{#if count === 0} + +{/if} + + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/Slider2.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/Slider2.svelte new file mode 100644 index 000000000000..ce799c4dc024 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/Slider2.svelte @@ -0,0 +1,27 @@ + + +
+

Slider2

+ Track +
+ +{#if count === 0} + +{/if} + + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/_config.js b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/_config.js new file mode 100644 index 000000000000..1d9037f9c339 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/_config.js @@ -0,0 +1,59 @@ +import { assert_ok, test } from '../../assert'; + +export default test({ + props: {}, + html: ` + +
+

Slider1

Track +
+ +
+

Slider1

Track
+
+ + + +
+

Slider2

Track +
+ +
+

Slider2

Track +
+
+
+ `, + test({ target, window, assert }) { + const rail_color1 = target.querySelector('#component1 p'); + const track_color1 = target.querySelector('#component1 span'); + const rail_color2 = target.querySelector('#component2 p'); + const track_color2 = target.querySelector('#component2 span'); + const nest_rail_color1 = target.querySelector('#nest-component1 p'); + const nest_track_color1 = target.querySelector('#nest-component1 span'); + const nest_rail_color2 = target.querySelector('#nest-component2 p'); + const nest_track_color2 = target.querySelector('#nest-component2 span'); + + assert_ok(rail_color1); + assert_ok(track_color1); + assert_ok(rail_color2); + assert_ok(track_color2); + assert_ok(nest_rail_color1); + assert_ok(nest_track_color1); + assert_ok(nest_rail_color2); + assert_ok(nest_track_color2); + + assert.equal(window.getComputedStyle(rail_color1).color, 'rgb(0, 0, 0)'); + assert.equal(window.getComputedStyle(track_color1).color, 'rgb(255, 0, 0)'); + assert.equal(window.getComputedStyle(rail_color2).color, 'rgb(0, 255, 0)'); + assert.equal(window.getComputedStyle(track_color2).color, 'rgb(0, 0, 255)'); + assert.equal(window.getComputedStyle(nest_rail_color1).color, 'rgb(255, 255, 0)'); + assert.equal(window.getComputedStyle(nest_track_color1).color, 'rgb(255, 0, 255)'); + assert.equal(window.getComputedStyle(nest_rail_color2).color, 'rgb(0, 255, 255)'); + assert.equal(window.getComputedStyle(nest_track_color2).color, 'rgb(255, 255, 255)'); + assert.equal(rail_color1.textContent, 'Slider1'); + assert.equal(rail_color2.textContent, 'Slider2'); + assert.equal(nest_rail_color1.textContent, 'Slider1'); + assert.equal(nest_rail_color2.textContent, 'Slider2'); + } +}); diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/main.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/main.svelte new file mode 100644 index 000000000000..1a4ed0295958 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties/main.svelte @@ -0,0 +1,16 @@ + + + + + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/Slider1.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/Slider1.svelte new file mode 100644 index 000000000000..20699ca853dc --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/Slider1.svelte @@ -0,0 +1,27 @@ + + +
+

Slider1

+ Track +
+ +{#if count === 0} + +{/if} + + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/Slider2.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/Slider2.svelte new file mode 100644 index 000000000000..ce799c4dc024 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/Slider2.svelte @@ -0,0 +1,27 @@ + + +
+

Slider2

+ Track +
+ +{#if count === 0} + +{/if} + + diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/_config.js b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/_config.js new file mode 100644 index 000000000000..8fff5736d3e7 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/_config.js @@ -0,0 +1,103 @@ +import { assert_ok, test } from '../../assert'; + +export default test({ + props: { + componentName: /** @type {string | undefined} */ ('Slider1') + }, + html: ` + +
+

Slider1

Track +
+ +
+

Slider1

Track
+
+ + + +
+

Slider1

Track +
+ +
+

Slider1

Track +
+
+
+ `, + test({ target, window, assert, component }) { + function assert_slider_1() { + const rail_color1 = target.querySelector('#component1 p'); + const track_color1 = target.querySelector('#component1 span'); + const rail_color2 = target.querySelector('#component2 p'); + const track_color2 = target.querySelector('#component2 span'); + const nest_rail_color1 = target.querySelector('#nest-component1 p'); + const nest_track_color1 = target.querySelector('#nest-component1 span'); + const nest_rail_color2 = target.querySelector('#nest-component2 p'); + const nest_track_color2 = target.querySelector('#nest-component2 span'); + assert_ok(rail_color1); + assert_ok(track_color1); + assert_ok(rail_color2); + assert_ok(track_color2); + assert_ok(nest_rail_color1); + assert_ok(nest_track_color1); + assert_ok(nest_rail_color2); + assert_ok(nest_track_color2); + + assert.equal(window.getComputedStyle(rail_color1).color, 'rgb(0, 0, 0)'); + assert.equal(window.getComputedStyle(track_color1).color, 'rgb(255, 0, 0)'); + assert.equal(window.getComputedStyle(rail_color2).color, 'rgb(0, 255, 0)'); + assert.equal(window.getComputedStyle(track_color2).color, 'rgb(0, 0, 255)'); + assert.equal(window.getComputedStyle(nest_rail_color1).color, 'rgb(255, 255, 0)'); + assert.equal(window.getComputedStyle(nest_track_color1).color, 'rgb(255, 0, 255)'); + assert.equal(window.getComputedStyle(nest_rail_color2).color, 'rgb(255, 255, 0)'); + assert.equal(window.getComputedStyle(nest_track_color2).color, 'rgb(255, 0, 255)'); + assert.equal(rail_color1.textContent, 'Slider1'); + assert.equal(rail_color2.textContent, 'Slider1'); + assert.equal(nest_rail_color1.textContent, 'Slider1'); + assert.equal(nest_rail_color2.textContent, 'Slider1'); + } + + function assert_slider_2() { + const rail_color1 = target.querySelector('#component1 p'); + const track_color1 = target.querySelector('#component1 span'); + const rail_color2 = target.querySelector('#component2 p'); + const track_color2 = target.querySelector('#component2 span'); + const nest_rail_color1 = target.querySelector('#nest-component1 p'); + const nest_track_color1 = target.querySelector('#nest-component1 span'); + const nest_rail_color2 = target.querySelector('#nest-component2 p'); + const nest_track_color2 = target.querySelector('#nest-component2 span'); + + assert_ok(rail_color1); + assert_ok(track_color1); + assert_ok(rail_color2); + assert_ok(track_color2); + assert_ok(nest_rail_color1); + assert_ok(nest_track_color1); + assert_ok(nest_rail_color2); + assert_ok(nest_track_color2); + + assert.equal(window.getComputedStyle(rail_color1).color, 'rgb(0, 0, 0)'); + assert.equal(window.getComputedStyle(track_color1).color, 'rgb(255, 0, 0)'); + assert.equal(window.getComputedStyle(rail_color2).color, 'rgb(0, 255, 0)'); + assert.equal(window.getComputedStyle(track_color2).color, 'rgb(0, 0, 255)'); + assert.equal(window.getComputedStyle(nest_rail_color1).color, 'rgb(0, 255, 255)'); + assert.equal(window.getComputedStyle(nest_track_color1).color, 'rgb(255, 255, 255)'); + assert.equal(window.getComputedStyle(nest_rail_color2).color, 'rgb(0, 255, 255)'); + assert.equal(window.getComputedStyle(nest_track_color2).color, 'rgb(255, 255, 255)'); + assert.equal(rail_color1.textContent, 'Slider2'); + assert.equal(rail_color2.textContent, 'Slider2'); + assert.equal(nest_rail_color1.textContent, 'Slider2'); + assert.equal(nest_rail_color2.textContent, 'Slider2'); + } + + assert_slider_1(); + component.componentName = 'Slider2'; + assert_slider_2(); + component.componentName = undefined; + assert.equal(window.document.querySelector('div')?.firstElementChild, null); + component.componentName = 'Slider1'; + assert_slider_1(); + } +}); diff --git a/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/main.svelte b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/main.svelte new file mode 100644 index 000000000000..2c6d05dc2581 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/samples/svelte-self-css-custom-properties2/main.svelte @@ -0,0 +1,20 @@ + + + + + diff --git a/packages/svelte/tests/runtime-browser/test-ssr.ts b/packages/svelte/tests/runtime-browser/test-ssr.ts new file mode 100644 index 000000000000..6987fac9155a --- /dev/null +++ b/packages/svelte/tests/runtime-browser/test-ssr.ts @@ -0,0 +1,53 @@ +// @vitest-environment jsdom +// Yes it's an SSR test, but we need the env to compare html +// This is in its own file because if we had the jsdom environment for the other playwright browser tests, +// esbuild would choke on it + +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { setImmediate } from 'node:timers/promises'; +import { render } from 'svelte/server'; +import { compile_directory } from '../helpers'; +import { assert_html_equal_with_options } from '../html_equal'; +import { suite } from '../suite'; +import { describe } from 'vitest'; + +export async function run_ssr_test( + config: ReturnType, + test_dir: string +) { + try { + await compile_directory(test_dir, 'server', config.compileOptions); + + const Component = (await import(`${test_dir}/_output/server/main.svelte.js`)).default; + const { body } = render(Component, { props: config.props || {}, idPrefix: config.id_prefix }); + + fs.writeFileSync(`${test_dir}/_output/rendered.html`, body); + + if (config.ssrHtml) { + assert_html_equal_with_options(body, config.ssrHtml, { + preserveComments: config.compileOptions?.preserveComments + }); + } else if (config.html) { + assert_html_equal_with_options(body, config.html, { + preserveComments: config.compileOptions?.preserveComments + }); + } + } catch (err: any) { + err.stack += `\n\ncmd-click: ${path.relative(process.cwd(), test_dir)}/main.svelte`; + throw err; + } + + // wait for vitest to report progress + await setImmediate(); +} + +const { run } = suite>(async (config, test_dir) => { + if (config.mode && !config.mode.includes('server')) return; + if (config.skip_mode?.includes('server')) return; + await run_ssr_test(config, test_dir); +}); + +describe('runtime-browser (ssr)', async () => { + await run(__dirname); +}); diff --git a/packages/svelte/tests/runtime-browser/test.ts b/packages/svelte/tests/runtime-browser/test.ts new file mode 100644 index 000000000000..582a10edf722 --- /dev/null +++ b/packages/svelte/tests/runtime-browser/test.ts @@ -0,0 +1,232 @@ +import { chromium } from '@playwright/test'; +import { build } from 'esbuild'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import { compile } from 'svelte/compiler'; +import { afterAll, assert, beforeAll, describe } from 'vitest'; +import { suite, suite_with_variants } from '../suite'; +import { write } from '../helpers'; +import type { Warning } from '#compiler'; + +const assert_file = path.resolve(__dirname, 'assert.js'); + +let browser: import('@playwright/test').Browser; + +beforeAll(async () => { + browser = await chromium.launch(); +}, 20000); + +afterAll(async () => { + if (browser) await browser.close(); +}); + +const { run: run_browser_tests } = suite_with_variants< + ReturnType, + 'dom' | 'hydrate', + void +>( + ['dom', 'hydrate'], + (variant, config) => { + if (variant === 'hydrate') { + if (config.mode && !config.mode.includes('hydrate')) return 'no-test'; + if (config.skip_mode?.includes('hydrate')) return true; + } + + return false; + }, + () => {}, + async (config, test_dir, variant) => { + await run_test(test_dir, config, variant === 'hydrate'); + } +); + +describe.concurrent( + 'runtime-browser', + () => run_browser_tests(__dirname), + // Browser tests are brittle and slow on CI + { timeout: 20000, retry: process.env.CI ? 1 : 0 } +); + +const { run: run_ce_tests } = suite>( + async (config, test_dir) => { + await run_test(test_dir, config, false); + } +); + +describe.concurrent( + 'custom-elements', + () => run_ce_tests(__dirname, 'custom-elements-samples'), + // Browser tests are brittle and slow on CI + { timeout: 20000, retry: process.env.CI ? 1 : 0 } +); + +async function run_test( + test_dir: string, + config: ReturnType, + hydrate: boolean +) { + const warnings: any[] = []; + + const build_result = await build({ + entryPoints: [`${__dirname}/driver.js`], + write: false, + define: { + __HYDRATE__: String(hydrate), + __CE_TEST__: String(test_dir.includes('custom-elements-samples')) + }, + alias: { + __MAIN_DOT_SVELTE__: path.resolve(test_dir, 'main.svelte'), + __CONFIG__: path.resolve(test_dir, '_config.js'), + 'assert.js': assert_file + }, + conditions: ['browser', 'production'], + plugins: [ + { + name: 'testing-runtime-browser', + setup(build) { + build.onLoad({ filter: /\.svelte$/ }, (args) => { + const compiled = compile(fs.readFileSync(args.path, 'utf-8').replace(/\r/g, ''), { + generate: 'client', + ...config.compileOptions, + immutable: config.immutable, + customElement: test_dir.includes('custom-elements-samples'), + accessors: 'accessors' in config ? config.accessors : true + }); + + write(`${test_dir}/_output/client/${path.basename(args.path)}.js`, compiled.js.code); + + compiled.warnings.forEach((warning) => { + if (warning.code === 'options_deprecated_accessors') return; + warnings.push(warning); + }); + + if (compiled.css !== null) { + compiled.js.code += `document.head.innerHTML += \`\``; + write( + `${test_dir}/_output/client/${path.basename(args.path)}.css`, + compiled.css.code + ); + } + + return { + contents: compiled.js.code, + loader: 'js' + }; + }); + } + } + ], + bundle: true, + format: 'iife', + globalName: 'test' + }); + + let build_result_ssr; + if (hydrate) { + const ssr_entry = path.resolve(__dirname, '../../src/index-server.js'); + + build_result_ssr = await build({ + entryPoints: [`${__dirname}/driver-ssr.js`], + write: false, + alias: { + __MAIN_DOT_SVELTE__: path.resolve(test_dir, 'main.svelte'), + __CONFIG__: path.resolve(test_dir, '_config.js') + }, + conditions: ['browser', 'production'], + plugins: [ + { + name: 'testing-runtime-browser-ssr', + setup(build) { + // When running the server version of the Svelte files, + // we also want to use the server export of the Svelte package + build.onResolve({ filter: /./ }, (args) => { + if (args.path === 'svelte') { + return { path: ssr_entry }; + } + }); + + build.onLoad({ filter: /\.svelte$/ }, (args) => { + const compiled = compile(fs.readFileSync(args.path, 'utf-8').replace(/\r/g, ''), { + generate: 'server', + ...config.compileOptions, + immutable: config.immutable, + customElement: test_dir.includes('custom-elements-samples'), + accessors: 'accessors' in config ? config.accessors : true + }); + + return { + contents: compiled.js.code, + loader: 'js' + }; + }); + } + } + ], + bundle: true, + format: 'iife', + globalName: 'test_ssr' + }); + } + + function assert_warnings() { + if (config.warnings) { + assert.deepStrictEqual( + warnings.map( + (w) => + ({ + code: w.code, + message: w.message, + start: w.start, + end: w.end + }) as Warning + ), + config.warnings + ); + } else if (warnings.length) { + /* eslint-disable no-unsafe-finally */ + console.warn(warnings); + throw new Error('Received unexpected warnings'); + } + } + + assert_warnings(); + + try { + const page = await browser.newPage(); + page.on('console', (message) => { + let method = message.type(); + if (method === 'warning') method = 'warn'; + // @ts-ignore + console[method](message.text()); + }); + + if (build_result_ssr) { + const result: any = await page.evaluate( + build_result_ssr.outputFiles[0].text + '; test_ssr.default()' + ); + await page.setContent('' + result.head + '
' + result.html + '
'); + } else { + await page.setContent('
'); + } + + // uncomment to see what was generated + // fs.writeFileSync(`${test_dir}/_actual.js`, build_result.outputFiles[0].text); + const test_result = await page.evaluate( + build_result.outputFiles[0].text + ";test.default(document.querySelector('main'))" + ); + + if (test_result) console.log(test_result); + await page.close(); + } catch (err: any) { + pretty_print_browser_assertion(err.message); + throw err; + } +} + +function pretty_print_browser_assertion(message: string) { + const match = /Error: Expected "(.+)" to equal "(.+)"/.exec(message); + + if (match) { + assert.equal(match[1], match[2]); + } +} diff --git a/packages/svelte/tests/runtime-legacy/samples/action-body/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-body/_config.js new file mode 100644 index 000000000000..8328136def55 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-body/_config.js @@ -0,0 +1,23 @@ +import { test } from '../../test'; + +export default test({ + html: '
', + + async test({ assert, target, window }) { + const enter = new window.MouseEvent('mouseenter'); + const leave = new window.MouseEvent('mouseleave'); + + await window.document.body.dispatchEvent(enter); + assert.htmlEqual( + target.innerHTML, + ` +
+
Perform an Action
+
+ ` + ); + + await window.document.body.dispatchEvent(leave); + assert.htmlEqual(target.innerHTML, '
'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-body/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-body/main.svelte new file mode 100644 index 000000000000..f793373e965a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-body/main.svelte @@ -0,0 +1,32 @@ + + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/action-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-component/_config.js new file mode 100644 index 000000000000..cd4774d4ded5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-component/_config.js @@ -0,0 +1,14 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + accessors: false, + async test({ assert, target }) { + assert.htmlEqual(target.innerHTML, '
'); + + const button = target.querySelector('button'); + button?.click(); + await tick(); + assert.htmlEqual(target.innerHTML, '
'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-component/main.svelte new file mode 100644 index 000000000000..54847ba8dc2f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-component/main.svelte @@ -0,0 +1,17 @@ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/action-component/sub.svelte b/packages/svelte/tests/runtime-legacy/samples/action-component/sub.svelte new file mode 100644 index 000000000000..53d2674ea635 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-component/sub.svelte @@ -0,0 +1,6 @@ + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each-destructured/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each-destructured/_config.js new file mode 100644 index 000000000000..fe13d43bc815 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each-destructured/_config.js @@ -0,0 +1,37 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + + +

first:

+

second:

+ `, + + test({ assert, component, target, window }) { + const event = new window.MouseEvent('click'); + + const buttons = target.querySelectorAll('button'); + + buttons[1].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + + +

first: 1

+

second: bar

+ ` + ); + + assert.equal(component.first, '1'); + assert.equal(component.second, 'bar'); + } +}); diff --git a/test/runtime/samples/action-custom-event-handler-in-each-destructured/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each-destructured/main.svelte similarity index 100% rename from test/runtime/samples/action-custom-event-handler-in-each-destructured/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each-destructured/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each/_config.js new file mode 100644 index 000000000000..83b14cb8a3c3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each/_config.js @@ -0,0 +1,37 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + + +

fromDom:

+

fromState:

+ `, + + test({ assert, component, target, window }) { + const event = new window.MouseEvent('click'); + + const buttons = target.querySelectorAll('button'); + + buttons[1].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + + +

fromDom: bar

+

fromState: bar

+ ` + ); + + assert.equal(component.fromDom, 'bar'); + assert.equal(component.fromState, 'bar'); + } +}); diff --git a/test/runtime/samples/action-custom-event-handler-in-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each/main.svelte similarity index 100% rename from test/runtime/samples/action-custom-event-handler-in-each/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-in-each/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js new file mode 100644 index 000000000000..9276ca8a5997 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/_config.js @@ -0,0 +1,20 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + + html: '', + + test({ assert, target, window }) { + const event = new window.MouseEvent('click'); + + const button = target.querySelector('button'); + ok(button); + + button.dispatchEvent(event); + flushSync(); + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/action-custom-event-handler-node-context/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/main.svelte similarity index 100% rename from test/runtime/samples/action-custom-event-handler-node-context/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-node-context/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-this/_config.js new file mode 100644 index 000000000000..46020d89c1c2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-this/_config.js @@ -0,0 +1,26 @@ +import { ok, test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + const event = new window.KeyboardEvent('keydown', { + key: 'Enter' + }); + + let blurred = false; + + input.focus(); + + input.addEventListener('blur', () => { + blurred = true; + }); + + input.dispatchEvent(event); + + assert.ok(blurred); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-this/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-this/main.svelte new file mode 100644 index 000000000000..c3ace108a5a7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-this/main.svelte @@ -0,0 +1,19 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-with-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-with-context/_config.js new file mode 100644 index 000000000000..2e6aa4dfeef3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-with-context/_config.js @@ -0,0 +1,21 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target, window }) { + const event = new window.MouseEvent('click', { + clientX: 42, + clientY: 42 + }); + + const button = target.querySelector('button'); + ok(button); + + button.dispatchEvent(event); + flushSync(); + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/action-custom-event-handler-with-context/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-with-context/main.svelte similarity index 100% rename from test/runtime/samples/action-custom-event-handler-with-context/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler-with-context/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler/_config.js new file mode 100644 index 000000000000..3769a8bd8126 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler/_config.js @@ -0,0 +1,21 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target, window }) { + const event = new window.MouseEvent('click', { + clientX: 42, + clientY: 42 + }); + + const button = target.querySelector('button'); + ok(button); + + button.dispatchEvent(event); + flushSync(); + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler/main.svelte new file mode 100644 index 000000000000..529579b1fed7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-custom-event-handler/main.svelte @@ -0,0 +1,23 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/action-document/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-document/_config.js new file mode 100644 index 000000000000..7f382cdf4c84 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-document/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + html: '
', + + async test({ assert, target, window }) { + const visibility = new window.Event('visibilitychange'); + + await window.document.dispatchEvent(visibility); + assert.htmlEqual( + target.innerHTML, + ` +
+
Perform an Action
+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-document/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-document/main.svelte new file mode 100644 index 000000000000..a29c1b7e9b84 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-document/main.svelte @@ -0,0 +1,24 @@ + + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/action-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-function/_config.js new file mode 100644 index 000000000000..239b7a5e0e72 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-function/_config.js @@ -0,0 +1,31 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + const eventEnter = new window.MouseEvent('mouseenter'); + const eventLeave = new window.MouseEvent('mouseleave'); + + await button.dispatchEvent(eventEnter); + assert.htmlEqual( + target.innerHTML, + ` + +
Perform an Action
+ ` + ); + + await button.dispatchEvent(eventLeave); + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/action-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-function/main.svelte similarity index 100% rename from test/runtime/samples/action-function/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/action-function/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/action-object-deep/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-object-deep/_config.js new file mode 100644 index 000000000000..ec9bd1430baa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-object-deep/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + `, + async test({ assert, target }) { + const button = /** @type {HTMLButtonElement & { foo: string }} */ ( + target.querySelector('button') + ); + assert.equal(button.foo, 'bar1337'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-object-deep/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-object-deep/main.svelte new file mode 100644 index 000000000000..75c35d628ddc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-object-deep/main.svelte @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/action-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-object/_config.js new file mode 100644 index 000000000000..ec9bd1430baa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-object/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + `, + async test({ assert, target }) { + const button = /** @type {HTMLButtonElement & { foo: string }} */ ( + target.querySelector('button') + ); + assert.equal(button.foo, 'bar1337'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-object/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-object/main.svelte new file mode 100644 index 000000000000..34e7475b3e31 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-object/main.svelte @@ -0,0 +1,10 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/action-receives-element-mounted/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-receives-element-mounted/_config.js new file mode 100644 index 000000000000..b409541c8ce9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-receives-element-mounted/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +/** @type {Record} */ +const result = {}; + +export default test({ + get props() { + return { result }; + }, + async test({ assert }) { + assert.notEqual(result.parentElement, null); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-receives-element-mounted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-receives-element-mounted/main.svelte new file mode 100644 index 000000000000..137ae6c2cb91 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-receives-element-mounted/main.svelte @@ -0,0 +1,8 @@ + + +

Hello!

diff --git a/packages/svelte/tests/runtime-legacy/samples/action-ternary-template/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-ternary-template/_config.js new file mode 100644 index 000000000000..e100a78d41ad --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-ternary-template/_config.js @@ -0,0 +1,26 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { target: 'World!', display: true }; + }, + + html: ` +

+ `, + + async test({ assert, target, window }) { + const header = target.querySelector('h1'); + ok(header); + + const click = new window.MouseEvent('click'); + + await header.dispatchEvent(click); + assert.htmlEqual( + target.innerHTML, + ` +

Hello World!

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-ternary-template/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-ternary-template/main.svelte new file mode 100644 index 000000000000..b8620c028e54 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-ternary-template/main.svelte @@ -0,0 +1,19 @@ + + +

diff --git a/packages/svelte/tests/runtime-legacy/samples/action-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-this/_config.js new file mode 100644 index 000000000000..0ab9305ade40 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-this/_config.js @@ -0,0 +1,16 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const click = new window.MouseEvent('click'); + + assert.htmlEqual(target.innerHTML, ''); + button.dispatchEvent(click); + flushSync(); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-this/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-this/main.svelte new file mode 100644 index 000000000000..c7d74a8b9747 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-this/main.svelte @@ -0,0 +1,20 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/Component.svelte new file mode 100644 index 000000000000..e38a0fff64bb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/Component.svelte @@ -0,0 +1,27 @@ + + + +{#if selected} +
{item.id}
+{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/_config.js new file mode 100644 index 000000000000..2411936d9c57 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/_config.js @@ -0,0 +1,17 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +
1
+ `, + async test({ assert, target, logs }) { + const button = target.querySelector('button'); + + button?.click(); + flushSync(); + + assert.deepEqual(logs, ['afterUpdate', 'onDestroy']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/main.svelte new file mode 100644 index 000000000000..7f99ce0f382e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-update-before-destroy/main.svelte @@ -0,0 +1,10 @@ + + +{#each Object.values($items) as item (item.id)} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/action-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/action-update/_config.js new file mode 100644 index 000000000000..a3fcb4232ef3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action-update/_config.js @@ -0,0 +1,46 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const enter = new window.MouseEvent('mouseenter'); + const leave = new window.MouseEvent('mouseleave'); + const ctrlPress = new window.KeyboardEvent('keydown', { ctrlKey: true }); + + button.dispatchEvent(enter); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + +
Perform an Action
+ ` + ); + + window.dispatchEvent(ctrlPress); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + +
Perform an augmented Action
+ ` + ); + + button.dispatchEvent(leave); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/action-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action-update/main.svelte similarity index 100% rename from test/runtime/samples/action-update/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/action-update/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/action/_config.js b/packages/svelte/tests/runtime-legacy/samples/action/_config.js new file mode 100644 index 000000000000..e7271f11f79c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/action/_config.js @@ -0,0 +1,32 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const eventEnter = new window.MouseEvent('mouseenter'); + const eventLeave = new window.MouseEvent('mouseleave'); + + await button.dispatchEvent(eventEnter); + assert.htmlEqual( + target.innerHTML, + ` + +
Perform an Action
+ ` + ); + + await button.dispatchEvent(eventLeave); + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/action/main.svelte b/packages/svelte/tests/runtime-legacy/samples/action/main.svelte similarity index 100% rename from test/runtime/samples/action/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/action/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/_config.js b/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/_config.js new file mode 100644 index 000000000000..39c0ef7f538a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + get props() { + return { value: 'hello!' }; + }, + + html: ` +

hello!

+

hello!

+ `, + + test({ assert, component, target }) { + component.value = 'goodbye!'; + assert.htmlEqual( + target.innerHTML, + ` +

goodbye!

+

goodbye!

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/main.svelte new file mode 100644 index 000000000000..688a25b1242b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/after-render-prevents-loop/main.svelte @@ -0,0 +1,13 @@ + + +

{value}

+

{mirror}

diff --git a/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/_config.js new file mode 100644 index 000000000000..39c0ef7f538a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + get props() { + return { value: 'hello!' }; + }, + + html: ` +

hello!

+

hello!

+ `, + + test({ assert, component, target }) { + component.value = 'goodbye!'; + assert.htmlEqual( + target.innerHTML, + ` +

goodbye!

+

goodbye!

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/main.svelte new file mode 100644 index 000000000000..3f4c15cd9613 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/after-render-triggers-update/main.svelte @@ -0,0 +1,15 @@ + + +

{value}

+

diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-css/_config.js b/packages/svelte/tests/runtime-legacy/samples/animation-css/_config.js new file mode 100644 index 000000000000..b6bd818e65db --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-css/_config.js @@ -0,0 +1,62 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + things: [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ] + }; + }, + + html: ` +
a
+
b
+
c
+
d
+
e
+ `, + + test({ assert, component, target, raf }) { + let divs = target.querySelectorAll('div'); + divs.forEach((div) => { + // @ts-expect-error + div.getBoundingClientRect = function () { + // @ts-expect-error + const index = [...this.parentNode.children].indexOf(this); + const top = index * 30; + + return { + left: 0, + right: 100, + top, + bottom: top + 20 + }; + }; + }); + + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; + + raf.tick(0); + + divs = target.querySelectorAll('div'); + assert.ok(divs[0].getAnimations().length > 0); + assert.equal(divs[1].getAnimations().length, 0); + assert.equal(divs[2].getAnimations().length, 0); + assert.equal(divs[3].getAnimations().length, 0); + assert.ok(divs[4].getAnimations().length > 0); + + raf.tick(100); + assert.deepEqual([divs[0].getAnimations().length, divs[4].getAnimations().length], [0, 0]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-css/main.svelte b/packages/svelte/tests/runtime-legacy/samples/animation-css/main.svelte new file mode 100644 index 000000000000..bd3647d73ca8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-css/main.svelte @@ -0,0 +1,17 @@ + + +{#each things as thing (thing.id)} +
{thing.name}
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-flip-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/animation-flip-2/_config.js new file mode 100644 index 000000000000..28238df40287 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-flip-2/_config.js @@ -0,0 +1,60 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + assert.htmlEqual( + target.innerHTML, + ` +
` + ); + + flushSync(() => { + button.click(); + }); + + assert.htmlEqual( + target.innerHTML, + ` +
` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-flip-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/animation-flip-2/main.svelte new file mode 100644 index 000000000000..99795007e801 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-flip-2/main.svelte @@ -0,0 +1,28 @@ + + + + +
+ {#each todos as todo (todo.id)} + + {/each} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-flip/_config.js b/packages/svelte/tests/runtime-legacy/samples/animation-flip/_config.js new file mode 100644 index 000000000000..45deb91690d9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-flip/_config.js @@ -0,0 +1,63 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + assert.htmlEqual( + target.innerHTML, + ` +
` + ); + + flushSync(() => { + button.click(); + }); + + assert.htmlEqual( + target.innerHTML, + ` +
` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-flip/main.svelte b/packages/svelte/tests/runtime-legacy/samples/animation-flip/main.svelte new file mode 100644 index 000000000000..8ab11940432a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-flip/main.svelte @@ -0,0 +1,27 @@ + + + + +
+ {#each todos as todo (todo.id)} + + {/each} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/_config.js b/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/_config.js new file mode 100644 index 000000000000..a72aed883b5c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/_config.js @@ -0,0 +1,91 @@ +// @ts-nocheck +import { ok, test } from '../../test'; + +export default test({ + skip: true, // TODO: needs fixing + + get props() { + return { + things: [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ] + }; + }, + + html: ` +
a
+
b
+
c
+
d
+
e
+ `, + + test({ assert, component, window, raf }) { + let divs = window.document.querySelectorAll('div'); + divs.forEach((div) => { + div.getBoundingClientRect = function () { + const index = [...this.parentNode.children].indexOf(this); + const top = index * 30; + + return { + left: 0, + right: 100, + top, + bottom: top + 20 + }; + }; + }); + + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; + + divs = window.document.querySelectorAll('div'); + assert.equal(divs[0].dy, 120); + assert.equal(divs[4].dy, -120); + + raf.tick(50); + assert.equal(divs[0].dy, 108); + assert.equal(divs[4].dy, -60); + + raf.tick(100); + assert.equal(divs[0].dy, 48); + assert.equal(divs[4].dy, 0); + + raf.tick(150); + assert.equal(divs[0].dy, 0); + assert.equal(divs[4].dy, 0); + + component.things = [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ]; + + divs = document.querySelectorAll('div'); + assert.equal(divs[0].dy, 120); + assert.equal(divs[4].dy, -120); + + raf.tick(200); + assert.equal(divs[0].dy, 108); + assert.equal(divs[4].dy, -60); + + raf.tick(250); + assert.equal(divs[0].dy, 48); + assert.equal(divs[4].dy, 0); + + raf.tick(300); + assert.equal(divs[0].dy, 0); + assert.equal(divs[4].dy, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/main.svelte b/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/main.svelte new file mode 100644 index 000000000000..c29394fa67b0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js-delay/main.svelte @@ -0,0 +1,21 @@ + + +{#each things as thing, i (thing.id)} +
{thing.name}
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/_config.js b/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/_config.js new file mode 100644 index 000000000000..f4a3554b29f9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/_config.js @@ -0,0 +1,63 @@ +// @ts-nocheck +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { + things: [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ] + }; + }, + + html: ` +
a
+
b
+
c
+
d
+
e
+ `, + + test({ assert, component, raf }) { + let divs = document.querySelectorAll('div'); + divs.forEach((div) => { + div.getBoundingClientRect = function () { + const index = [...this.parentNode.children].indexOf(this); + const top = index * 30; + + return { + left: 0, + right: 100, + top, + bottom: top + 20 + }; + }; + }); + + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; + + raf.tick(0); + + divs = document.querySelectorAll('div'); + assert.equal(divs[0].dy, 120); + assert.equal(divs[4].dy, -120); + + raf.tick(50); + assert.equal(divs[0].dy, 60); + assert.equal(divs[4].dy, -60); + + raf.tick(100); + assert.equal(divs[0].dy, 0); + assert.equal(divs[4].dy, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/main.svelte b/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/main.svelte new file mode 100644 index 000000000000..b376452e1575 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js-easing/main.svelte @@ -0,0 +1,25 @@ + + +{#each things as thing (thing.id)} +
{thing.name}
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js/_config.js b/packages/svelte/tests/runtime-legacy/samples/animation-js/_config.js new file mode 100644 index 000000000000..a2e17b49f869 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js/_config.js @@ -0,0 +1,86 @@ +// @ts-nocheck +import { test } from '../../test'; + +export default test({ + get props() { + return { + things: [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ] + }; + }, + + html: ` +
a
+
b
+
c
+
d
+
e
+ `, + + test({ assert, component, raf }) { + let divs = document.querySelectorAll('div'); + divs.forEach((div) => { + div.getBoundingClientRect = function () { + const index = [...this.parentNode.children].indexOf(this); + const top = index * 30; + + return { + left: 0, + right: 100, + top, + bottom: top + 20 + }; + }; + }); + + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; + + raf.tick(0); + + divs = document.querySelectorAll('div'); + assert.equal(divs[0].dy, 120); + assert.equal(divs[4].dy, -120); + + raf.tick(50); + assert.equal(divs[0].dy, 60); + assert.equal(divs[4].dy, -60); + + raf.tick(100); + assert.equal(divs[0].dy, 0); + assert.equal(divs[4].dy, 0); + + component.things = [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ]; + + raf.tick(100); + + divs = document.querySelectorAll('div'); + + assert.equal(divs[0].dy, 120); + assert.equal(divs[4].dy, -120); + + raf.tick(150); + assert.equal(divs[0].dy, 60); + assert.equal(divs[4].dy, -60); + + raf.tick(200); + assert.equal(divs[0].dy, 0); + assert.equal(divs[4].dy, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/animation-js/main.svelte b/packages/svelte/tests/runtime-legacy/samples/animation-js/main.svelte new file mode 100644 index 000000000000..4d060dd14059 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/animation-js/main.svelte @@ -0,0 +1,20 @@ + + +{#each things as thing (thing.id)} +
{thing.name}
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order-2/_config.js new file mode 100644 index 000000000000..98022d73edd1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order-2/_config.js @@ -0,0 +1,46 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +/** @type {string[]} */ +let value = []; + +export default test({ + get props() { + value = []; + return { value }; + }, + + test({ assert, target, window }) { + const inputs = target.querySelectorAll('input'); + + const event = new window.Event('input', { bubbles: true }); + + for (const input of inputs) { + input.value = 'h'; + input.dispatchEvent(event); + flushSync(); + } + + assert.deepEqual(value, [ + 'bind:this true', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10', + '11', + '12', + '13', + '14', + '15', + '16', + '17', + '18' + ]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order-2/main.svelte new file mode 100644 index 000000000000..c536d722b537 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order-2/main.svelte @@ -0,0 +1,91 @@ + + + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order/_config.js b/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order/_config.js new file mode 100644 index 000000000000..aea50afafd1f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order/_config.js @@ -0,0 +1,49 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { value: '' }; + }, + + html: ` + +

+ `, + + ssrHtml: ` + +

+ `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + const event = new window.Event('input'); + input.value = 'h'; + input.dispatchEvent(event); + flushSync(); + + assert.equal(input.value, 'H'); + assert.htmlEqual( + target.innerHTML, + ` + +

H

+ ` + ); + + input.value = 'he'; + input.dispatchEvent(event); + flushSync(); + assert.equal(input.value, 'HE'); + assert.htmlEqual( + target.innerHTML, + ` + +

HE

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order/main.svelte b/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order/main.svelte new file mode 100644 index 000000000000..be652c7b7956 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/apply-directives-in-order/main.svelte @@ -0,0 +1,10 @@ + + + +

{value}

diff --git a/packages/svelte/tests/runtime-legacy/samples/array-literal-spread-deopt/_config.js b/packages/svelte/tests/runtime-legacy/samples/array-literal-spread-deopt/_config.js new file mode 100644 index 000000000000..98a1ec2e8138 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/array-literal-spread-deopt/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
a
b
c
' +}); diff --git a/test/runtime/samples/array-literal-spread-deopt/main.svelte b/packages/svelte/tests/runtime-legacy/samples/array-literal-spread-deopt/main.svelte similarity index 100% rename from test/runtime/samples/array-literal-spread-deopt/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/array-literal-spread-deopt/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/array-rest-is-array-or-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/array-rest-is-array-or-object/_config.js new file mode 100644 index 000000000000..44e45b88e153 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/array-rest-is-array-or-object/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

1

+

2

+

3

+

5

+

10

+

20

+

30

+

6

+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/array-rest-is-array-or-object/main.svelte b/packages/svelte/tests/runtime-legacy/samples/array-rest-is-array-or-object/main.svelte new file mode 100644 index 000000000000..fb3a5b7d85c5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/array-rest-is-array-or-object/main.svelte @@ -0,0 +1,15 @@ + + +

{first}

+

{second}

+

{third}

+

{fifth}

+ +

{one}

+

{two}

+

{three}

+

{length}

+ diff --git a/packages/svelte/tests/runtime-legacy/samples/assignment-in-init/_config.js b/packages/svelte/tests/runtime-legacy/samples/assignment-in-init/_config.js new file mode 100644 index 000000000000..ee1a68c96f34 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/assignment-in-init/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component }) { + assert.equal(component.get_foo(), 1); + assert.equal(component.get_bar(), 2); + } +}); diff --git a/test/runtime/samples/assignment-in-init/main.svelte b/packages/svelte/tests/runtime-legacy/samples/assignment-in-init/main.svelte similarity index 100% rename from test/runtime/samples/assignment-in-init/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/assignment-in-init/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/assignment-to-computed-property/_config.js b/packages/svelte/tests/runtime-legacy/samples/assignment-to-computed-property/_config.js new file mode 100644 index 000000000000..fa24d9890227 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/assignment-to-computed-property/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component }) { + assert.deepEqual(component.foo, { baz: 1 }); + } +}); diff --git a/test/runtime/samples/assignment-to-computed-property/main.svelte b/packages/svelte/tests/runtime-legacy/samples/assignment-to-computed-property/main.svelte similarity index 100% rename from test/runtime/samples/assignment-to-computed-property/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/assignment-to-computed-property/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/assignment-to-const1/_config.js b/packages/svelte/tests/runtime-legacy/samples/assignment-to-const1/_config.js new file mode 100644 index 000000000000..76aefb87c57f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/assignment-to-const1/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

2, 1

' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/assignment-to-const1/main.svelte b/packages/svelte/tests/runtime-legacy/samples/assignment-to-const1/main.svelte new file mode 100644 index 000000000000..f221249193b6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/assignment-to-const1/main.svelte @@ -0,0 +1,6 @@ + + +

{arr[0]}, {arr[1]}

diff --git a/packages/svelte/tests/runtime-legacy/samples/assignment-to-const2/_config.js b/packages/svelte/tests/runtime-legacy/samples/assignment-to-const2/_config.js new file mode 100644 index 000000000000..3f03993f4be4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/assignment-to-const2/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

[{"a":2},100]

' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/assignment-to-const2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/assignment-to-const2/main.svelte new file mode 100644 index 000000000000..c805e4b5897e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/assignment-to-const2/main.svelte @@ -0,0 +1,7 @@ + + +

{JSON.stringify(arr)}

diff --git a/packages/svelte/tests/runtime-legacy/samples/async-generator-object-methods/main.svelte b/packages/svelte/tests/runtime-legacy/samples/async-generator-object-methods/main.svelte new file mode 100644 index 000000000000..76dff53556fa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/async-generator-object-methods/main.svelte @@ -0,0 +1,10 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-case-insensitive/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-case-insensitive/_config.js new file mode 100644 index 000000000000..817d311478ee --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-case-insensitive/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-case-insensitive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-case-insensitive/main.svelte new file mode 100644 index 000000000000..bcc418511fa7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-case-insensitive/main.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-false/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-false/_config.js new file mode 100644 index 000000000000..275395672501 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-false/_config.js @@ -0,0 +1,10 @@ +import { ok, test } from '../../test'; + +export default test({ + html: '', + test({ assert, target }) { + const textarea = target.querySelector('textarea'); + ok(textarea); + assert.ok(textarea.readOnly === false); + } +}); diff --git a/test/runtime/samples/attribute-boolean-false/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-false/main.svelte similarity index 100% rename from test/runtime/samples/attribute-boolean-false/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/attribute-boolean-false/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-hidden/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-hidden/_config.js new file mode 100644 index 000000000000..443e41ff5c1a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-hidden/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { hidden: true }; + }, + html: '', + test({ assert, component, target }) { + component.hidden = false; + assert.htmlEqual(target.innerHTML, '
'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-hidden/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-hidden/main.svelte new file mode 100644 index 000000000000..3fdebdc99cbc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-hidden/main.svelte @@ -0,0 +1,5 @@ + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-indeterminate/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-indeterminate/_config.js new file mode 100644 index 000000000000..e9f3e8d8b068 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-indeterminate/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { indeterminate: true }; + }, + + test({ assert, component, target, variant }) { + if (variant === 'dom') { + // hydration also has indeterminate which is harmless but would break the test unnecessarily + assert.htmlEqual(target.innerHTML, ''); + } + + const input = target.querySelector('input'); + ok(input); + + assert.ok(input.indeterminate); + component.indeterminate = false; + assert.ok(!input.indeterminate); + } +}); diff --git a/test/runtime/samples/attribute-boolean-indeterminate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-indeterminate/main.svelte similarity index 100% rename from test/runtime/samples/attribute-boolean-indeterminate/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/attribute-boolean-indeterminate/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/_config.js new file mode 100644 index 000000000000..26fbbc955ba1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + ssrHtml: ` +
+
some div
+ `, + + get props() { + return { inert: true }; + }, + + test({ assert, target, component }) { + const [div1, div2] = target.querySelectorAll('div'); + assert.ok(!div1.inert); + assert.ok(div2.inert); + + component.inert = false; + assert.ok(!div2.inert); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/main.svelte new file mode 100644 index 000000000000..3b9792371326 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-inert/main.svelte @@ -0,0 +1,6 @@ + + +
+
some div
diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-true/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-true/_config.js new file mode 100644 index 000000000000..f096ae4c87f3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-true/_config.js @@ -0,0 +1,11 @@ +import { ok, test } from '../../test'; + +export default test({ + html: '', + test({ assert, target }) { + const textarea = target.querySelector('textarea'); + ok(textarea); + assert.equal(textarea.dataset.attr, 'true'); + assert.ok(textarea.readOnly); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-true/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-true/main.svelte new file mode 100644 index 000000000000..64746447490a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-boolean-true/main.svelte @@ -0,0 +1 @@ +', + test({ assert, target }) { + const textarea = target.querySelector('textarea'); + ok(textarea); + assert.ok(textarea.readOnly); + } +}); diff --git a/test/runtime/samples/attribute-static-boolean/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-static-boolean/main.svelte similarity index 100% rename from test/runtime/samples/attribute-static-boolean/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/attribute-static-boolean/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-static-quotemarks/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-static-quotemarks/_config.js new file mode 100644 index 000000000000..9af6d359e57f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-static-quotemarks/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + foo + bar + + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-static-quotemarks/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-static-quotemarks/main.svelte new file mode 100644 index 000000000000..e01af9f09880 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-static-quotemarks/main.svelte @@ -0,0 +1,4 @@ + + foo + bar + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-static/_config.js new file mode 100644 index 000000000000..b0c514146cf8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-static/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
' +}); diff --git a/test/hydration/samples/element-attribute-unchanged/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-static/main.svelte similarity index 100% rename from test/hydration/samples/element-attribute-unchanged/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/attribute-static/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-undefined/_config.js new file mode 100644 index 000000000000..8ff46df1b1f5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-undefined/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-undefined/main.svelte new file mode 100644 index 000000000000..5108aa873f02 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-undefined/main.svelte @@ -0,0 +1 @@ +
diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-unknown-without-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-unknown-without-value/_config.js new file mode 100644 index 000000000000..b0664fda5f82 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-unknown-without-value/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
' +}); diff --git a/test/runtime/samples/attribute-unknown-without-value/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-unknown-without-value/main.svelte similarity index 100% rename from test/runtime/samples/attribute-unknown-without-value/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/attribute-unknown-without-value/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/attribute-url/_config.js b/packages/svelte/tests/runtime-legacy/samples/attribute-url/_config.js new file mode 100644 index 000000000000..698ee028bd69 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/attribute-url/_config.js @@ -0,0 +1,11 @@ +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target }) { + const div = target.querySelector('div'); + ok(div); + + assert.equal(div.style.backgroundImage, 'url(https://example.com/foo.jpg)'); + assert.equal(div.style.color, 'red'); + } +}); diff --git a/test/runtime/samples/attribute-url/main.svelte b/packages/svelte/tests/runtime-legacy/samples/attribute-url/main.svelte similarity index 100% rename from test/runtime/samples/attribute-url/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/attribute-url/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/autofocus-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/autofocus-2/_config.js new file mode 100644 index 000000000000..24b45b376174 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/autofocus-2/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target, window }) { + assert.equal(target.querySelector('input'), window.document.activeElement); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/autofocus-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/autofocus-2/main.svelte new file mode 100644 index 000000000000..e3ea9a76d40c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/autofocus-2/main.svelte @@ -0,0 +1,2 @@ +

wat

+ diff --git a/packages/svelte/tests/runtime-legacy/samples/autofocus-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/autofocus-3/_config.js new file mode 100644 index 000000000000..24b45b376174 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/autofocus-3/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target, window }) { + assert.equal(target.querySelector('input'), window.document.activeElement); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/autofocus-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/autofocus-3/main.svelte new file mode 100644 index 000000000000..31d2cbc0ec62 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/autofocus-3/main.svelte @@ -0,0 +1,3 @@ +
+ +
diff --git a/packages/svelte/tests/runtime-legacy/samples/autofocus/_config.js b/packages/svelte/tests/runtime-legacy/samples/autofocus/_config.js new file mode 100644 index 000000000000..351b02929cbf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/autofocus/_config.js @@ -0,0 +1,38 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + async test({ assert, component, target, window }) { + component.active = 'default'; + assert.equal(target.querySelector('input[title="default"]'), window.document.activeElement); + + component.active = 'dynamic-false'; + assert.notEqual( + target.querySelector('input[title="dynamic-false"]'), + window.document.activeElement + ); + + // when dynamically set autofocus to true, don't autofocus + component.autofocusFalse = true; + assert.notEqual( + target.querySelector('input[title="dynamic-false"]'), + window.document.activeElement + ); + + component.active = 'dynamic-true'; + assert.equal( + target.querySelector('input[title="dynamic-true"]'), + window.document.activeElement + ); + + component.active = 'spread'; + assert.equal(target.querySelector('input[title="spread"]'), window.document.activeElement); + + component.active = 'spread-override'; + assert.notEqual( + target.querySelector('input[title="spread-override"]'), + window.document.activeElement + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/autofocus/main.svelte b/packages/svelte/tests/runtime-legacy/samples/autofocus/main.svelte new file mode 100644 index 000000000000..ecdb1beb5e02 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/autofocus/main.svelte @@ -0,0 +1,18 @@ + + +{#if active === 'default'} + +{:else if active === 'dynamic-false'} + +{:else if active === 'dynamic-true'} + +{:else if active === 'spread'} + +{:else if active === 'spread-override'} + +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-block-func-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-block-func-function/_config.js new file mode 100644 index 000000000000..3125eafb539d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-block-func-function/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + thePromise: new Promise((_) => {}) + }; + }, + + html: ` + Waiting... + `, + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve({ func: 12345 })); + + assert.htmlEqual(target.innerHTML, '12345'); + + try { + await (component.thePromise = Promise.reject({ func: 67890 })); + } catch (e) { + // do nothing + } + + assert.htmlEqual(target.innerHTML, '67890'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-block-func-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-block-func-function/main.svelte new file mode 100644 index 000000000000..6d36038d6f4f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-block-func-function/main.svelte @@ -0,0 +1,11 @@ + + +{#await thePromise} + Waiting... +{:then { func }} + {(() => func)()} +{:catch { func: func_1 }} + {(() => func_1)()} +{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-catch-no-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-catch-no-expression/_config.js new file mode 100644 index 000000000000..a13e636f3c90 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-catch-no-expression/_config.js @@ -0,0 +1,48 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { thePromise: deferred.promise }; + }, + + html: ` +
+

the promise is pending

+ `, + + async test({ assert, component, target }) { + deferred.resolve(42); + + await deferred.promise; + + assert.htmlEqual(target.innerHTML, '
'); + + deferred = create_deferred(); + component.thePromise = deferred.promise; + + assert.htmlEqual(target.innerHTML, '

the promise is pending

'); + + const rejection = deferred.promise + .catch(() => {}) + .finally(async () => { + assert.htmlEqual( + target.innerHTML, + `

oh no! Something broke!

+
+

oh no! Something broke!

` + ); + }); + + deferred.reject(new Error()); + + await rejection; + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-catch-no-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-catch-no-expression/main.svelte new file mode 100644 index 000000000000..0da0d1209288 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-catch-no-expression/main.svelte @@ -0,0 +1,15 @@ + + +{#await thePromise catch} +

oh no! Something broke!

+{/await} + +
+ +{#await thePromise} +

the promise is pending

+{:catch} +

oh no! Something broke!

+{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-catch-shorthand/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-catch-shorthand/_config.js new file mode 100644 index 000000000000..dac311e07262 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-catch-shorthand/_config.js @@ -0,0 +1,39 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { thePromise: deferred.promise }; + }, + + html: '', + + test({ assert, component, target }) { + deferred.resolve(42); + + return deferred.promise + .then(() => { + assert.htmlEqual(target.innerHTML, ''); + + deferred = create_deferred(); + + component.thePromise = deferred.promise; + + assert.htmlEqual(target.innerHTML, ''); + + deferred.reject(new Error('something broke')); + + return deferred.promise.catch(() => {}); + }) + .then(() => { + assert.htmlEqual(target.innerHTML, '

oh no! something broke

'); + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-catch-shorthand/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-catch-shorthand/main.svelte new file mode 100644 index 000000000000..844e7da08c1d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-catch-shorthand/main.svelte @@ -0,0 +1,7 @@ + + +{#await thePromise catch theError} +

oh no! {theError.message}

+{/await} \ No newline at end of file diff --git a/test/runtime/samples/await-component-oncreate/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/await-component-oncreate/Foo.svelte similarity index 100% rename from test/runtime/samples/await-component-oncreate/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-component-oncreate/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-component-oncreate/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-component-oncreate/_config.js new file mode 100644 index 000000000000..0cf0cf770de8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-component-oncreate/_config.js @@ -0,0 +1,23 @@ +import { test } from '../../test'; + +const promise = Promise.resolve(42); + +export default test({ + get props() { + return { promise }; + }, + + test({ assert, target }) { + return promise.then(async () => { + await Promise.resolve(); + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + ` +

42

+

true

+ ` + ); + }); + } +}); diff --git a/test/runtime/samples/await-component-oncreate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-component-oncreate/main.svelte similarity index 100% rename from test/runtime/samples/await-component-oncreate/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-component-oncreate/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/_config.js new file mode 100644 index 000000000000..c36d75ea1f1c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; +import { sleep } from './sleep.js'; + +export default test({ + html: ` +

loading...

+ `, + + test({ assert, target }) { + return sleep(50).then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

the answer is 42

+

count: 1

+ ` + ); + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/main.svelte new file mode 100644 index 000000000000..91c9a6c4c2f2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/main.svelte @@ -0,0 +1,19 @@ + + +{#await get_promise()} +

loading...

+{:then value} +

the answer is {value}

+

count: {count}

+{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/sleep.js b/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/sleep.js new file mode 100644 index 000000000000..1df7390e6221 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-conservative-update/sleep.js @@ -0,0 +1,13 @@ +export let stopped = false; + +export const stop = () => (stopped = true); + +/** @param {number} ms */ +export const sleep = (ms) => + new Promise((f) => { + if (stopped) return; + setTimeout(() => { + if (stopped) return; + f(undefined); + }, ms); + }); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-containing-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-containing-if/_config.js new file mode 100644 index 000000000000..3c9bab013f13 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-containing-if/_config.js @@ -0,0 +1,43 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { thePromise: deferred.promise, show: true }; + }, + + html: ` +

loading...

+ `, + + test({ assert, component, target }) { + deferred.resolve(42); + + return deferred.promise.then(async () => { + assert.htmlEqual( + target.innerHTML, + ` +

the value is 42

+ ` + ); + + component.show = false; + assert.htmlEqual(target.innerHTML, '
'); + + component.show = true; + assert.htmlEqual( + target.innerHTML, + ` +

the value is 42

+ ` + ); + }); + } +}); diff --git a/test/runtime/samples/await-containing-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-containing-if/main.svelte similarity index 100% rename from test/runtime/samples/await-containing-if/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-containing-if/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-function-promise/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-function-promise/_config.js new file mode 100644 index 000000000000..3bde129401cb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-function-promise/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +const realPromise = Promise.resolve(42); + +const promise = () => {}; +promise.then = realPromise.then.bind(realPromise); +promise.catch = realPromise.catch.bind(realPromise); + +export default test({ + get props() { + return { promise }; + }, + + test({ assert, target }) { + return promise.then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

42

+ ` + ); + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-function-promise/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-function-promise/main.svelte new file mode 100644 index 000000000000..aaefc6b7823e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-function-promise/main.svelte @@ -0,0 +1,7 @@ + + +{#await promise then value} +

{JSON.stringify(value)}

+{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-in-dynamic-component/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/await-in-dynamic-component/Widget.svelte new file mode 100644 index 000000000000..78118e944d22 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-in-dynamic-component/Widget.svelte @@ -0,0 +1 @@ +{#await null}{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-in-dynamic-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-in-dynamic-component/_config.js new file mode 100644 index 000000000000..5a5b0af64ef5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-in-dynamic-component/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ component }) { + component.flag = false; + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-in-dynamic-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-in-dynamic-component/main.svelte new file mode 100644 index 000000000000..c395cb449957 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-in-dynamic-component/main.svelte @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-in-each/_config.js new file mode 100644 index 000000000000..71831276a649 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-in-each/_config.js @@ -0,0 +1,38 @@ +import { test } from '../../test'; + +/** @type {(value: any) => void} */ +let fulfil; + +const thePromise = new Promise((f) => { + fulfil = f; +}); + +const items = [ + { + title: 'a title', + data: thePromise + } +]; + +export default test({ + get props() { + return { items }; + }, + + html: ` +

a title: loading...

+ `, + + test({ assert, target }) { + fulfil(42); + + return thePromise.then(async () => { + assert.htmlEqual( + target.innerHTML, + ` +

a title: 42

+ ` + ); + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-in-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-in-each/main.svelte new file mode 100644 index 000000000000..7c7ceb4d1836 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-in-each/main.svelte @@ -0,0 +1,18 @@ + + +{#each items as item} + {#await item.data} +

{item.title}: loading...

+ {:then result} +

{item.title}: {result}

+ {/await} +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-in-removed-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-in-removed-if/_config.js new file mode 100644 index 000000000000..be51c25c9a65 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-in-removed-if/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +/** @type {(value?: any) => void} */ +let fulfil; + +const promise = new Promise((f) => { + fulfil = f; +}); + +export default test({ + get props() { + return { promise, condition: true }; + }, + + html: '', + + async test({ assert, component, target }) { + component.condition = false; + + fulfil(); + await new Promise((f) => setTimeout(f, 0)); + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/await-in-removed-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-in-removed-if/main.svelte similarity index 100% rename from test/runtime/samples/await-in-removed-if/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-in-removed-if/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/Component.svelte new file mode 100644 index 000000000000..f1f5971a06b5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/Component.svelte @@ -0,0 +1,15 @@ + + +{state} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/_config.js new file mode 100644 index 000000000000..e207ef31d67b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: 'Loading...', + async test({ assert, component, target }) { + await component.test(); + + assert.htmlEqual(target.innerHTML, '1'); + assert.deepEqual(component.logs, ['mount 0', 'unmount 0', 'mount 1']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/main.svelte new file mode 100644 index 000000000000..d8dc75288b8a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-mount-and-unmount-immediately/main.svelte @@ -0,0 +1,36 @@ + + +{#await promise} + Loading... +{:then state} + +{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/Card.svelte b/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/Card.svelte new file mode 100644 index 000000000000..e481297e041f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/Card.svelte @@ -0,0 +1,8 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/_config.js new file mode 100644 index 000000000000..70268a0e1d65 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/_config.js @@ -0,0 +1,23 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + `\n-------` + ); + + const [b1] = target.querySelectorAll('button'); + + b1.click(); + Promise.resolve(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + `\n-------\n` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/main.svelte new file mode 100644 index 000000000000..ddc1a3142c52 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-mutate-array/main.svelte @@ -0,0 +1,30 @@ + + +{#await p_cards then cards} + {#each cards.filter((card) => !card.fav) as card} + {card.fav = !card.fav}}> + {/each} + ------- + {#each cards.filter((card) => card.fav) as card} + {card.fav = !card.fav}}> + {/each} +{/await} + diff --git a/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous-reactive/_config.js new file mode 100644 index 000000000000..1d775465cd47 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous-reactive/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + html: '

wait for it...

', + test({ assert, component, target }) { + return component.promise.then(async () => { + assert.htmlEqual( + target.innerHTML, + ` +

the answer is 42!

+

the answer100 is 4200!

+ ` + ); + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous-reactive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous-reactive/main.svelte new file mode 100644 index 000000000000..c1bbac66be2b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous-reactive/main.svelte @@ -0,0 +1,21 @@ + + +{#if promise} + {#await promise} +

wait for it...

+ {:then _} +

the answer is {answer}!

+

the answer100 is {answer100}!

+ {:catch error} +

well that's odd

+ {/await} +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous/_config.js new file mode 100644 index 000000000000..9fe8683973e4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + const promise = Promise.resolve().then(() => { + component.answer = 42; + }); + + component.promise = promise; + + assert.htmlEqual(target.innerHTML, '

wait for it...

'); + + return promise.then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

the answer is 42!

+ ` + ); + }); + } +}); diff --git a/test/runtime/samples/await-set-simultaneous/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous/main.svelte similarity index 100% rename from test/runtime/samples/await-set-simultaneous/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-set-simultaneous/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/Widget.svelte new file mode 100644 index 000000000000..cfd918558b14 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/Widget.svelte @@ -0,0 +1,15 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/_config.js new file mode 100644 index 000000000000..665b8d94b6f1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/_config.js @@ -0,0 +1,26 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + assert.htmlEqual(target.innerHTML, 'Loading...'); + + await component.promise; + await Promise.resolve(); + const span = target.querySelector('span'); + ok(span); + assert.equal(span.textContent, 'a'); + + const select = target.querySelector('select'); + ok(select); + const options = [...target.querySelectorAll('option')]; + + const change = new window.Event('change'); + + options[1].selected = true; + select.dispatchEvent(change); + flushSync(); + + assert.equal(span.textContent, 'b'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/main.svelte new file mode 100644 index 000000000000..eb55465de09d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-blowback-reactive/main.svelte @@ -0,0 +1,12 @@ + + +{#await promise} + Loading... +{:then options} + + {value} +{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-anchor/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-anchor/_config.js new file mode 100644 index 000000000000..d778d2c8d2ad --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-anchor/_config.js @@ -0,0 +1,46 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { thePromise: deferred.promise }; + }, + + html: ` +

loading...

+ `, + + test({ assert, component, target }) { + deferred.resolve(42); + + return deferred.promise + .then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

the value is 42

+ ` + ); + + deferred = create_deferred(); + + component.thePromise = deferred.promise; + + assert.htmlEqual(target.innerHTML, '

loading...

'); + + deferred.reject(new Error('something broke')); + + return deferred.promise.catch(() => {}); + }) + .then(() => { + assert.htmlEqual(target.innerHTML, '

oh no! something broke

'); + }); + } +}); diff --git a/test/runtime/samples/await-then-catch-anchor/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-anchor/main.svelte similarity index 100% rename from test/runtime/samples/await-then-catch-anchor/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch-anchor/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-event/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-event/_config.js new file mode 100644 index 000000000000..26d22b8c1a3b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-event/_config.js @@ -0,0 +1,51 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + get props() { + return { + thePromise: deferred.promise + }; + }, + + html: ` +

loading...

+ `, + + test({ assert, component, target, window }) { + deferred.resolve(42); + + return deferred.promise + .then(async () => { + await tick(); + assert.htmlEqual(target.innerHTML, ''); + + const { button } = component; + + const click = new window.Event('click', { bubbles: true }); + button.dispatchEvent(click); + + assert.equal(component.clicked, 42); + + const thePromise = Promise.resolve(43); + component.thePromise = thePromise; + + return thePromise; + }) + .then(() => { + const { button } = component; + + const click = new window.Event('click', { bubbles: true }); + button.dispatchEvent(click); + + assert.equal(component.clicked, 43); + }); + } +}); diff --git a/test/runtime/samples/await-then-catch-event/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-event/main.svelte similarity index 100% rename from test/runtime/samples/await-then-catch-event/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch-event/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-if/_config.js new file mode 100644 index 000000000000..d68f1597fce3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-if/_config.js @@ -0,0 +1,51 @@ +import { test } from '../../test'; + +/** @type {(value: any) => void} */ +let fulfil; + +const thePromise = new Promise((f) => { + fulfil = f; +}); + +export default test({ + get props() { + return { show: true, thePromise }; + }, + + html: ` +

loading...

+ `, + + test({ assert, component, target }) { + fulfil(42); + + return thePromise.then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

the value is 42

+ ` + ); + + component.show = false; + + assert.htmlEqual( + target.innerHTML, + ` +

Else

+ ` + ); + + component.show = true; + + return thePromise.then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

the value is 42

+ ` + ); + }); + }); + } +}); diff --git a/test/runtime/samples/await-then-catch-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-if/main.svelte similarity index 100% rename from test/runtime/samples/await-then-catch-if/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch-if/main.svelte diff --git a/test/runtime/samples/await-then-catch-in-slot/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/Foo.svelte similarity index 100% rename from test/runtime/samples/await-then-catch-in-slot/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/_config.js new file mode 100644 index 000000000000..09ab6e39123a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/_config.js @@ -0,0 +1,38 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { thePromise: deferred.promise }; + }, + + html: ` +

loading...

+ `, + + async test({ assert, component, target }) { + deferred.resolve(42); + + await deferred.promise; + assert.htmlEqual(target.innerHTML, '

the value is 42

'); + + deferred = create_deferred(); + component.thePromise = deferred.promise; + assert.htmlEqual(target.innerHTML, '

loading...

'); + + deferred.reject(new Error('something broke')); + + try { + await deferred.promise; + } catch {} + + assert.htmlEqual(target.innerHTML, '

oh no! something broke

'); + } +}); diff --git a/test/runtime/samples/await-then-catch-in-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/main.svelte similarity index 100% rename from test/runtime/samples/await-then-catch-in-slot/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch-in-slot/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-multiple/_config.js new file mode 100644 index 000000000000..719484ff0e4c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-multiple/_config.js @@ -0,0 +1,60 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { thePromise: deferred.promise }; + }, + + html: ` +

loading...

+

loading...

+ `, + + test({ assert, component, target }) { + deferred.resolve(42); + + return deferred.promise + .then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

the value is 42

+

the value is 42

+ ` + ); + + deferred = create_deferred(); + + component.thePromise = deferred.promise; + + assert.htmlEqual( + target.innerHTML, + ` +

loading...

+

loading...

+ ` + ); + + deferred.reject(new Error('something broke')); + + return deferred.promise.catch(() => {}); + }) + .then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

oh no! something broke

+

oh no! something broke

+ ` + ); + }); + } +}); diff --git a/test/runtime/samples/await-then-catch-multiple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-multiple/main.svelte similarity index 100% rename from test/runtime/samples/await-then-catch-multiple/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch-multiple/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-no-values/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-no-values/_config.js new file mode 100644 index 000000000000..4608be3edd66 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-no-values/_config.js @@ -0,0 +1,39 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { thePromise: deferred.promise }; + }, + + html: 'waiting', + + test({ assert, component, target }) { + deferred.resolve(9000); + + return deferred.promise + .then(() => { + assert.htmlEqual(target.innerHTML, 'resolved'); + + deferred = create_deferred(); + + component.thePromise = deferred.promise; + + assert.htmlEqual(target.innerHTML, 'waiting'); + + deferred.reject(new Error('something broke')); + + return deferred.promise.catch(() => {}); + }) + .then(() => { + assert.htmlEqual(target.innerHTML, 'rejected'); + }); + } +}); diff --git a/test/runtime/samples/await-then-catch-no-values/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-no-values/main.svelte similarity index 100% rename from test/runtime/samples/await-then-catch-no-values/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch-no-values/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-non-promise/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-non-promise/_config.js new file mode 100644 index 000000000000..3ea561f02db8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-non-promise/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { thePromise: 'not actually a promise' }; + }, + + html: ` +

the value is not actually a promise

+ `, + + test({ assert, component, target }) { + component.thePromise = 'still not a promise'; + + assert.htmlEqual( + target.innerHTML, + ` +

the value is still not a promise

+ ` + ); + } +}); diff --git a/test/runtime/samples/await-then-catch-non-promise/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-non-promise/main.svelte similarity index 100% rename from test/runtime/samples/await-then-catch-non-promise/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch-non-promise/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-order/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-order/_config.js new file mode 100644 index 000000000000..e4ef68a75e9e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-order/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +/** @type {(value: any) => void} */ +let fulfil; + +const thePromise = new Promise((f) => { + fulfil = f; +}); + +export default test({ + get props() { + return { thePromise }; + }, + + html: ` +

loading...

true!

+ `, + + test({ assert, target }) { + fulfil(42); + + return thePromise.then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

the value is 42

true!

+ ` + ); + }); + } +}); diff --git a/test/runtime/samples/await-then-catch-order/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-order/main.svelte similarity index 100% rename from test/runtime/samples/await-then-catch-order/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch-order/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-static/_config.js new file mode 100644 index 000000000000..46608c41e87d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-static/_config.js @@ -0,0 +1,57 @@ +import { test } from '../../test'; + +/** @type {(value: any) => void} */ +let fulfil; + +let promise = new Promise((f) => { + fulfil = f; +}); + +export default test({ + get props() { + return { promise }; + }, + + html: ` +

loading...

+ `, + + test({ assert, component, target }) { + fulfil(42); + + return promise + .then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

loaded

+ ` + ); + + promise = new Promise((f, _) => { + fulfil = f; + }); + + component.promise = promise; + + assert.htmlEqual( + target.innerHTML, + ` +

loading...

+ ` + ); + + fulfil(43); + + return promise.then(() => {}); + }) + .then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

loaded

+ ` + ); + }); + } +}); diff --git a/test/runtime/samples/await-then-catch-static/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch-static/main.svelte similarity index 100% rename from test/runtime/samples/await-then-catch-static/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch-static/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-catch/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-catch/_config.js new file mode 100644 index 000000000000..33a8eb2babc5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-catch/_config.js @@ -0,0 +1,46 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { thePromise: deferred.promise }; + }, + + html: ` +

loading...

+ `, + + test({ assert, component, target }) { + deferred.resolve(42); + + return deferred.promise + .then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

the value is 42

+ ` + ); + + deferred = create_deferred(); + + component.thePromise = deferred.promise; + + assert.htmlEqual(target.innerHTML, '

loading...

'); + + deferred.reject(new Error('something broke')); + + return deferred.promise.catch(() => {}); + }) + .then(() => { + assert.htmlEqual(target.innerHTML, '

oh no! something broke

'); + }); + } +}); diff --git a/test/runtime/samples/await-then-catch/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-catch/main.svelte similarity index 100% rename from test/runtime/samples/await-then-catch/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-catch/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array-nested-rest/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array-nested-rest/_config.js new file mode 100644 index 000000000000..ee8b8e4a0e9a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array-nested-rest/_config.js @@ -0,0 +1,73 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + thePromise: new Promise((_) => {}) + }; + }, + + html: ` + loading... + `, + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve([1, 2, 3, 4, 5, 6, 7, 8])); + + assert.htmlEqual( + target.innerHTML, + ` +

a: 1

+

b: 2

+

c: 5

+

remaining length: 3

+ ` + ); + + await (component.thePromise = Promise.resolve([9, 10, 11, 12, 13, 14, 15])); + + assert.htmlEqual( + target.innerHTML, + ` +

a: 9

+

b: 10

+

c: 13

+

remaining length: 2

+ ` + ); + + try { + await (component.thePromise = Promise.reject([16, 17, 18, 19, 20, 21, 22])); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

c: 16

+

d: 17

+

e: 18

+

f: 19

+

g: 22

+ ` + ); + + try { + await (component.thePromise = Promise.reject([23, 24, 25, 26, 27, 28, 29, 30, 31])); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

c: 23

+

d: 24

+

e: 25

+

f: 26

+

g: 29

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array-nested-rest/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array-nested-rest/main.svelte new file mode 100644 index 000000000000..4bb8ad0077b6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array-nested-rest/main.svelte @@ -0,0 +1,18 @@ + + +{#await thePromise} + loading... +{:then [ a, b, ...[,, c, ...{ length } ]]} +

a: {a}

+

b: {b}

+

c: {c}

+

remaining length: {length}

+{:catch [c, ...[d, e, f, ...[,,g]]]} +

c: {c}

+

d: {d}

+

e: {e}

+

f: {f}

+

g: {g}

+{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array/_config.js new file mode 100644 index 000000000000..1d830ce582f6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array/_config.js @@ -0,0 +1,65 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + thePromise: new Promise((_) => {}) + }; + }, + + html: ` + loading... + `, + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve([1, 2])); + + assert.htmlEqual( + target.innerHTML, + ` +

a: 1

+

b: 2

+ ` + ); + + await (component.thePromise = Promise.resolve([4, 5])); + + assert.htmlEqual( + target.innerHTML, + ` +

a: 4

+

b: 5

+ ` + ); + + try { + await (component.thePromise = Promise.reject(['a', [6, 7]])); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

c: a

+

d: 6

+

e: 7

+ ` + ); + + try { + await (component.thePromise = Promise.reject(['b', [8, 9]])); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

c: b

+

d: 8

+

e: 9

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array/main.svelte new file mode 100644 index 000000000000..cc0d217f7984 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-array/main.svelte @@ -0,0 +1,14 @@ + + +{#await thePromise} + loading... +{:then [ a, b ]} +

a: {a}

+

b: {b}

+{:catch [c, [d, e]]} +

c: {c}

+

d: {d}

+

e: {e}

+{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-computed-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-computed-props/_config.js new file mode 100644 index 000000000000..5c873067ee14 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-computed-props/_config.js @@ -0,0 +1,39 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + ` +

propA: 3

+

propB: 7

+

num: 3

+

rest: {"prop3":{"prop9":9,"prop10":10}}

+

propZ: 5

+

propY: 6

+

rest: {"propX":7,"propW":8}

+ ` + ); + + await (component.object = Promise.resolve({ + prop1: 'one', + prop2: 'two', + prop3: { prop7: 'seven' }, + prop4: { prop10: 'ten' } + })); + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + ` +

propA: seven

+

propB: ten

+

num: 5

+

rest: {"prop1":"one","prop2":"two"}

+

propZ: 5

+

propY: 6

+

rest: {"propX":7,"propW":8}

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-computed-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-computed-props/main.svelte new file mode 100644 index 000000000000..71756d6cf38f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-computed-props/main.svelte @@ -0,0 +1,23 @@ + + +{#await object then { [`prop${num++}`]: { [`prop${num + 3}`]: propA }, [`prop${num++}`]: { [`prop${num + 5}`]: propB }, ...rest }} +

propA: {propA}

+

propB: {propB}

+

num: {num}

+

rest: {JSON.stringify(rest)}

+{/await} + +{#await objectReject then value} + resolved +{:catch { [`${prop}Z`]: propZ, [`${prop}Y`]: propY, ...rest }} +

propZ: {propZ}

+

propY: {propY}

+

rest: {JSON.stringify(rest)}

+{/await} + diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-default/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-default/_config.js new file mode 100644 index 000000000000..6915eb2c1ea0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-default/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + ` +

a: 3

+

b: 2

+

c: 3

+

a: 1

+

b: 2

+

c: 3

+

a: 3

+

b: 2

+

c: 3

+

a: 1

+

b: 2

+

c: 3

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-default/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-default/main.svelte new file mode 100644 index 000000000000..d559aadab163 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-default/main.svelte @@ -0,0 +1,34 @@ + + +{#await object then { a = 3, b = 4, c }} +

a: {a}

+

b: {b}

+

c: {c}

+{/await} + +{#await array then [a, b, c = 3]} +

a: {a}

+

b: {b}

+

c: {c}

+{/await} + +{#await objectReject then value} + resolved +{:catch { a = 3, b = 4, c }} +

a: {a}

+

b: {b}

+

c: {c}

+{/await} + +{#await arrayReject then value} + resolved +{:catch [a, b, c = 3]} +

a: {a}

+

b: {b}

+

c: {c}

+{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-number-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-number-props/_config.js new file mode 100644 index 000000000000..a5d1e2195e21 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-number-props/_config.js @@ -0,0 +1,67 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + thePromise: new Promise((_) => {}) + }; + }, + + html: ` + loading... + `, + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve([10, 11, 12, 13, 14, 15])); + + assert.htmlEqual( + target.innerHTML, + ` +

[1] 11

+

[3] 13

+

[4] 14

+ ` + ); + + await (component.thePromise = Promise.resolve({ 1: 21, 3: 23, 4: 24 })); + + assert.htmlEqual( + target.innerHTML, + ` +

[1] 21

+

[3] 23

+

[4] 24

+ ` + ); + + try { + await (component.thePromise = Promise.reject([30, 31, 32, 33, 34, 35])); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

[0] 30

+

[2] 32

+

[5] 35

+ ` + ); + + try { + await (component.thePromise = Promise.reject({ 0: 40, 2: 42, 5: 45 })); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

[0] 40

+

[2] 42

+

[5] 45

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-number-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-number-props/main.svelte new file mode 100644 index 000000000000..aaeee9b35353 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-number-props/main.svelte @@ -0,0 +1,15 @@ + + +{#await thePromise} + loading... +{:then { 1: a, 3: b, 4: c }} +

[1] {a}

+

[3] {b}

+

[4] {c}

+{:catch { 0: d, 2: e, 5: f }} +

[0] {d}

+

[2] {e}

+

[5] {f}

+{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object-if/_config.js new file mode 100644 index 000000000000..af04467749cb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object-if/_config.js @@ -0,0 +1,36 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { + thePromise: Promise.resolve({ result: 1 }) + }; + }, + + html: '', + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve({ result: 1 })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

result: 1

+

count: 0

+ ` + ); + + await new Promise((resolve) => setTimeout(resolve, 1)); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

result: 1

+

count: 1

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object-if/main.svelte new file mode 100644 index 000000000000..3425979e2c8b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object-if/main.svelte @@ -0,0 +1,19 @@ + + +{#await thePromise then { result }} + {#if result} +

result: {result}

+

count: {count}

+ {:else} +

result: {result}

+

count: {count}

+ {/if} +{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object/_config.js new file mode 100644 index 000000000000..5c7989c933e9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object/_config.js @@ -0,0 +1,66 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + thePromise: new Promise((_) => {}) + }; + }, + + html: ` + loading... + `, + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve({ error: 'error message' })); + assert.htmlEqual( + target.innerHTML, + ` +

error: error message

+

result:

+ ` + ); + + await (component.thePromise = Promise.resolve({ result: '42' })); + + assert.htmlEqual( + target.innerHTML, + ` +

error:

+

result: 42

+ ` + ); + + try { + await (component.thePromise = Promise.reject({ + error: { message: 'oops', code: '123' } + })); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

message: oops

+

code: 123

+ ` + ); + + try { + await (component.thePromise = Promise.reject({ + error: { message: 'timeout', code: '456' } + })); + } catch (e) { + // do nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

message: timeout

+

code: 456

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object/main.svelte new file mode 100644 index 000000000000..ff574b7be806 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-object/main.svelte @@ -0,0 +1,13 @@ + + +{#await thePromise} + loading... +{:then { result, error }} +

error: {error}

+

result: {result}

+{:catch { error: { message, code } }} +

message: {message}

+

code: {code}

+{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-rest/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-rest/_config.js new file mode 100644 index 000000000000..a2ff942f4eed --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-rest/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + ` +

a: 1

+

rest: {"b":2,"c":3}

+

a: 1

+

b: 2

+

rest: [3,4,5,6]

+

a: 1

+

rest: {"b":2,"c":3}

+

a: 1

+

b: 2

+

rest: [3,4,5,6]

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-rest/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-rest/main.svelte new file mode 100644 index 000000000000..a2d57dabf384 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-rest/main.svelte @@ -0,0 +1,32 @@ + + +{#await object then { a, ...rest }} +

a: {a}

+

rest: {JSON.stringify(rest)}

+{/await} + +{#await array then [a, b, ...rest]} +

a: {a}

+

b: {b}

+

rest: {JSON.stringify(rest)}

+{/await} + +{#await objectReject then value} + resolved +{:catch { a, ...rest }} +

a: {a}

+

rest: {JSON.stringify(rest)}

+{/await} + +{#await arrayReject then value} + resolved +{:catch [a, b, ...rest]} +

a: {a}

+

b: {b}

+

rest: {JSON.stringify(rest)}

+{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-string-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-string-props/_config.js new file mode 100644 index 000000000000..89bf13613ddc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-string-props/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + ` +

prop-1: 1

+

prop4: 4

+

rest: {"prop2":2,"prop-3":3}

+

prop-7: 7

+

prop6: 6

+

rest: {"prop-5":5,"prop8":8}

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-string-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-string-props/main.svelte new file mode 100644 index 000000000000..608b1161f5c1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-destruct-string-props/main.svelte @@ -0,0 +1,19 @@ + + +{#await object then { 'prop-1': prop1, 'prop4': fourthProp, ...rest }} +

prop-1: {prop1}

+

prop4: {fourthProp}

+

rest: {JSON.stringify(rest)}

+{/await} + +{#await objectReject then value} + resolved +{:catch { 'prop-7': prop7, 'prop6': sixthProp, ...rest }} +

prop-7: {prop7}

+

prop6: {sixthProp}

+

rest: {JSON.stringify(rest)}

+{/await} + diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-if/_config.js new file mode 100644 index 000000000000..27b111d68b56 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-if/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +/** @type {(value: any) => void} */ +let fulfil; + +const thePromise = new Promise((f) => { + fulfil = f; +}); + +export default test({ + get props() { + return { thePromise }; + }, + + html: ` + loading... + `, + + async test({ assert, target }) { + fulfil([]); + + await thePromise; + + assert.htmlEqual( + target.innerHTML, + ` +

promise array is empty

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-if/main.svelte new file mode 100644 index 000000000000..d292067b3070 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-if/main.svelte @@ -0,0 +1,13 @@ + + +{#await thePromise} + loading... +{:then r} + {#if r.length < 1} +

promise array is empty

+ {:else} +

promise array is not empty

+ {/if} +{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-no-context/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-no-context/main.svelte new file mode 100644 index 000000000000..c72951214921 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-no-context/main.svelte @@ -0,0 +1,12 @@ + + +{#await promise} +
waiting
+{:then} + {#each test as t} +
t
+ {/each} +{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-no-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-no-expression/_config.js new file mode 100644 index 000000000000..7790a06d4def --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-no-expression/_config.js @@ -0,0 +1,65 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { thePromise: deferred.promise }; + }, + + html: ` +
+
+

the promise is pending

+ `, + + expect_unhandled_rejections: true, + async test({ assert, component, target }) { + deferred.resolve(); + + await deferred.promise; + + assert.htmlEqual( + target.innerHTML, + ` +

the promise is resolved

+
+

the promise is resolved

+
+

the promise is resolved

+ ` + ); + + const local = (deferred = create_deferred()); + + component.thePromise = local.promise; + + assert.htmlEqual( + target.innerHTML, + ` +
+
+

the promise is pending

+ ` + ); + + local.reject(new Error('something broke')); + + try { + await local.promise; + } catch {} + + assert.htmlEqual( + target.innerHTML, + `

oh no! something broke

+
+
` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-no-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-no-expression/main.svelte new file mode 100644 index 000000000000..a48870ae6785 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-no-expression/main.svelte @@ -0,0 +1,23 @@ + + +{#await thePromise then} +

the promise is resolved

+{:catch theError} +

oh no! {theError.message}

+{/await} + +
+ +{#await thePromise then} +

the promise is resolved

+{/await} + +
+ +{#await thePromise} +

the promise is pending

+{:then} +

the promise is resolved

+{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-shadowed/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-shadowed/_config.js new file mode 100644 index 000000000000..08b62d8da8d6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-shadowed/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: '
Loading...
', + + async test({ assert, target }) { + await Promise.resolve(); + assert.htmlEqual(target.innerHTML, '
10
'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-shadowed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-shadowed/main.svelte new file mode 100644 index 000000000000..bb4bdef5fda4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-shadowed/main.svelte @@ -0,0 +1,11 @@ + + +
+ {#await x} + Loading... + {:then x} + {x} + {/await} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/await-then-shorthand/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-then-shorthand/_config.js new file mode 100644 index 000000000000..79e7094c6cdf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-then-shorthand/_config.js @@ -0,0 +1,49 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { thePromise: deferred.promise }; + }, + + html: '', + + async test({ assert, component, target }) { + deferred.resolve(42); + + return deferred.promise + .then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

the value is 42

+ ` + ); + + deferred = create_deferred(); + + component.thePromise = deferred.promise; + + assert.htmlEqual(target.innerHTML, ''); + + deferred.reject(new Error('something broke')); + + return deferred.promise.catch(() => {}); + }) + .then(() => { + assert.htmlEqual( + target.innerHTML, + ` +

oh no! something broke

+ ` + ); + }); + } +}); diff --git a/test/runtime/samples/await-then-shorthand/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-then-shorthand/main.svelte similarity index 100% rename from test/runtime/samples/await-then-shorthand/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-then-shorthand/main.svelte diff --git a/test/runtime/samples/await-with-components/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/await-with-components/Widget.svelte similarity index 100% rename from test/runtime/samples/await-with-components/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-with-components/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-components/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-with-components/_config.js new file mode 100644 index 000000000000..3798e8dc081e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-components/_config.js @@ -0,0 +1,36 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + /** @param {any} value */ + let resolve = (value) => {}; + + /** @param {any} reason */ + let reject = (reason) => {}; + + let promise = new Promise((ok) => (resolve = ok)); + + component.promise = promise; + assert.htmlEqual(target.innerHTML, 'Loading...'); + + resolve(42); + await promise; + assert.htmlEqual(target.innerHTML, '42'); + + promise = new Promise((ok, fail) => (reject = fail)); + component.promise = promise; + assert.htmlEqual(target.innerHTML, 'Loading...'); + + reject(99); + await promise.then(null, () => {}); + assert.htmlEqual(target.innerHTML, '99'); + + promise = new Promise((ok) => (resolve = ok)); + component.promise = promise; + assert.htmlEqual(target.innerHTML, 'Loading...'); + + resolve(1); + await promise; + assert.htmlEqual(target.innerHTML, '1'); + } +}); diff --git a/test/runtime/samples/await-with-components/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-with-components/main.svelte similarity index 100% rename from test/runtime/samples/await-with-components/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/await-with-components/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/Component.svelte new file mode 100644 index 000000000000..1301db3f9908 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/Component.svelte @@ -0,0 +1,7 @@ + + +
count: {count}
+
value: {value}
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/_config.js new file mode 100644 index 000000000000..c091d4fbc860 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/_config.js @@ -0,0 +1,74 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + thePromise: new Promise((_) => {}), + count: 0 + }; + }, + + html: ` +

loading...

+ `, + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve({ + value: 'success', + Component: component.Component + })); + + assert.htmlEqual( + target.innerHTML, + ` +
Resolved: +
count: 0
+
value: success
+
+ ` + ); + + component.count = 5; + + assert.htmlEqual( + target.innerHTML, + ` +
Resolved: +
count: 5
+
value: success
+
+ ` + ); + + try { + await (component.thePromise = Promise.reject({ + value: 'failure', + Component: component.Component + })); + } catch (error) { + // ignore + } + + assert.htmlEqual( + target.innerHTML, + ` +
Rejected: +
count: 5
+
value: failure
+
+ ` + ); + + component.count = 10; + + assert.htmlEqual( + target.innerHTML, + ` +
Rejected: +
count: 10
+
value: failure
+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/main.svelte new file mode 100644 index 000000000000..b29c875f920e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-update-2/main.svelte @@ -0,0 +1,16 @@ + + +
+ {#await thePromise} +

loading...

+ {:then { value: theValue, Component }} + Resolved: + {:catch { value: theError, Component } } + Rejected: + {/await} +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-update-catch-scope/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-with-update-catch-scope/_config.js new file mode 100644 index 000000000000..3f8c2b24a9fd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-update-catch-scope/_config.js @@ -0,0 +1,55 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + thePromise: new Promise((_) => {}) + }; + }, + + html: ` +
error:
+ `, + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve('abc')); + + assert.htmlEqual( + target.innerHTML, + ` +
+ error: + After Resolve: +
+ ` + ); + + component.error = 'external error occurred'; + + assert.htmlEqual( + target.innerHTML, + ` +
+ error: ${component.error} + After Resolve: ${component.error} +
+ ` + ); + + try { + await (component.thePromise = Promise.reject('failure')); + } catch (error) { + // ignore + } + + assert.htmlEqual( + target.innerHTML, + ` +
+ error: ${component.error} + Rejected: failure +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-update-catch-scope/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-with-update-catch-scope/main.svelte new file mode 100644 index 000000000000..4d4eb53f0b63 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-update-catch-scope/main.svelte @@ -0,0 +1,13 @@ + + +
+ error: {error} + {#await thePromise then _} + After Resolve: {error} + {:catch error} + Rejected: {error} + {/await} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-update/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/await-with-update/Component.svelte new file mode 100644 index 000000000000..5f13c80e65f1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-update/Component.svelte @@ -0,0 +1,5 @@ + + +
count: {count}
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-with-update/_config.js new file mode 100644 index 000000000000..cea49559119c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-update/_config.js @@ -0,0 +1,64 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + thePromise: new Promise((_) => {}), + count: 0 + }; + }, + + html: ` +

loading...

+ `, + + async test({ assert, component, target }) { + await (component.thePromise = Promise.resolve(component.Component)); + + assert.htmlEqual( + target.innerHTML, + ` +
Resolved: +
count: 0
+
+ ` + ); + + component.count = 5; + + assert.htmlEqual( + target.innerHTML, + ` +
Resolved: +
count: 5
+
+ ` + ); + + try { + await (component.thePromise = Promise.reject(component.Component)); + } catch (error) { + // ignore + } + + assert.htmlEqual( + target.innerHTML, + ` +
Rejected: +
count: 5
+
+ ` + ); + + component.count = 10; + + assert.htmlEqual( + target.innerHTML, + ` +
Rejected: +
count: 10
+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-with-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-with-update/main.svelte new file mode 100644 index 000000000000..51c5b76a212e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-with-update/main.svelte @@ -0,0 +1,16 @@ + + +
+ {#await thePromise} +

loading...

+ {:then theValue} + Resolved: + {:catch theError} + Rejected: + {/await} +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/await-without-catch/_config.js b/packages/svelte/tests/runtime-legacy/samples/await-without-catch/_config.js new file mode 100644 index 000000000000..a4db703dc4de --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-without-catch/_config.js @@ -0,0 +1,43 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers.js'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { promise: deferred.promise }; + }, + + html: ` +

loading...

+ `, + + expect_unhandled_rejections: true, + test({ assert, component, target }) { + deferred.resolve(42); + + return deferred.promise + .then(() => { + assert.htmlEqual(target.innerHTML, '

loaded

'); + + deferred = create_deferred(); + + component.promise = deferred.promise; + + assert.htmlEqual(target.innerHTML, '

loading...

'); + + deferred.reject(new Error('this error should be thrown')); + + return deferred.promise; + }) + .catch((err) => { + assert.equal(err.message, 'this error should be thrown'); + assert.htmlEqual(target.innerHTML, ''); + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/await-without-catch/main.svelte b/packages/svelte/tests/runtime-legacy/samples/await-without-catch/main.svelte new file mode 100644 index 000000000000..f528a8bf6996 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/await-without-catch/main.svelte @@ -0,0 +1,9 @@ + + +{#await promise} +

loading...

+{:then value} +

loaded

+{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/Item.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/Item.svelte new file mode 100644 index 000000000000..5e747768e912 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/Item.svelte @@ -0,0 +1,24 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/_config.js new file mode 100644 index 000000000000..e71ef468499d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/_config.js @@ -0,0 +1,11 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + const [btn1] = target.querySelectorAll('button'); + flushSync(() => { + // This test would result in an infinite loop, so if this doesn't error, then the test is working. + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/main.svelte new file mode 100644 index 000000000000..908d07f39a03 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain-2/main.svelte @@ -0,0 +1,9 @@ + + +{#each items as item} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain/Item.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/Item.svelte new file mode 100644 index 000000000000..f2568e2652d3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/Item.svelte @@ -0,0 +1,12 @@ + + +{foo} diff --git a/test/runtime/samples/before-render-chain/List.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/List.svelte similarity index 100% rename from test/runtime/samples/before-render-chain/List.svelte rename to packages/svelte/tests/runtime-legacy/samples/before-render-chain/List.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-chain/_config.js b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/_config.js new file mode 100644 index 000000000000..580df5ca8106 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/_config.js @@ -0,0 +1,28 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + + html: ` + 3 + 2 + 1 + `, + + test({ assert, component, target }) { + component.list.update(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + 1 + 2 + 3 + 4 + 5 + ` + ); + } +}); diff --git a/test/runtime/samples/before-render-chain/main.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-chain/main.svelte similarity index 100% rename from test/runtime/samples/before-render-chain/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/before-render-chain/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/_config.js b/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/_config.js new file mode 100644 index 000000000000..39c0ef7f538a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + get props() { + return { value: 'hello!' }; + }, + + html: ` +

hello!

+

hello!

+ `, + + test({ assert, component, target }) { + component.value = 'goodbye!'; + assert.htmlEqual( + target.innerHTML, + ` +

goodbye!

+

goodbye!

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/main.svelte new file mode 100644 index 000000000000..8e86aa77cb51 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/before-render-prevents-loop/main.svelte @@ -0,0 +1,13 @@ + + +

{value}

+

{mirror}

diff --git a/packages/svelte/tests/runtime-legacy/samples/bind-export-const-with-spread/Test.svelte b/packages/svelte/tests/runtime-legacy/samples/bind-export-const-with-spread/Test.svelte new file mode 100644 index 000000000000..1ec90313197f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bind-export-const-with-spread/Test.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bind-export-const-with-spread/_config.js b/packages/svelte/tests/runtime-legacy/samples/bind-export-const-with-spread/_config.js new file mode 100644 index 000000000000..0645e5bc7f7b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bind-export-const-with-spread/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: `

42

`, + async test({ target, assert }) { + const p = target.querySelector('p'); + assert.equal(p?.innerHTML, '42'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bind-export-const-with-spread/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bind-export-const-with-spread/main.svelte new file mode 100644 index 000000000000..8a0a370acbc4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bind-export-const-with-spread/main.svelte @@ -0,0 +1,11 @@ + + + +

{x}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-backflow/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-backflow/Child.svelte new file mode 100644 index 000000000000..e2865f96626d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-backflow/Child.svelte @@ -0,0 +1,20 @@ + + +
child: {value?.foo} | updates: {updates.length}
diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-backflow/Parent.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-backflow/Parent.svelte new file mode 100644 index 000000000000..d987cd109420 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-backflow/Parent.svelte @@ -0,0 +1,11 @@ + + +
parent: {value?.foo} | updates: {updates.length}
+ diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-backflow/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-backflow/_config.js new file mode 100644 index 000000000000..9e1561f40e17 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-backflow/_config.js @@ -0,0 +1,47 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + configs: [ + { testcase: 'parent_override_child_default', value: { foo: 'mon' } }, + { testcase: 'child_default_populate_parent', value: undefined }, + { testcase: 'reactive_update', value: { foo: 'mon' } }, + { testcase: 'reactive_mutate', value: { foo: 'mon' } }, + { testcase: 'init_update', value: { foo: 'mon' } }, + { testcase: 'init_mutate', value: { foo: 'mon' } } + ] + }; + }, + + async test({ assert, component }) { + const parents = component.parents; + + // first testcase should update once + // the rest should update twice + let p; + p = parents['parent_override_child_default']; + assert.deepEqual(p.value, { foo: 'mon' }); + assert.equal(p.updates.length, 1); + + p = parents['child_default_populate_parent']; + assert.deepEqual(p.value, { foo: 'kid' }); + assert.equal(p.updates.length, 2); + + p = parents['reactive_update']; + assert.deepEqual(p.value, { foo: 'kid' }); + assert.equal(p.updates.length, 2); + + p = parents['reactive_mutate']; + assert.deepEqual(p.value, { foo: 'kid' }); + assert.equal(p.updates.length, 2); + + p = parents['init_update']; + assert.deepEqual(p.value, { foo: 'kid' }); + assert.equal(p.updates.length, 2); + + p = parents['init_mutate']; + assert.deepEqual(p.value, { foo: 'kid' }); + assert.equal(p.updates.length, 2); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-backflow/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-backflow/main.svelte new file mode 100644 index 000000000000..f7cfd4472d17 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-backflow/main.svelte @@ -0,0 +1,9 @@ + + +{#each configs as config} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-circular/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-circular/_config.js new file mode 100644 index 000000000000..29ddac16ad89 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-circular/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + ` +}); diff --git a/test/runtime/samples/binding-circular/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-circular/main.svelte similarity index 100% rename from test/runtime/samples/binding-circular/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-circular/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html-initial/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html-initial/_config.js new file mode 100644 index 000000000000..46984df0c252 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html-initial/_config.js @@ -0,0 +1,59 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {string | null} */ + name: null + }; + }, + + html: ` + world +

hello world

+ `, + + ssrHtml: ` + world +

hello

+ `, + + async test({ assert, component, target, window }) { + assert.equal(component.name, 'world'); + + const el = target.querySelector('editor'); + ok(el); + + el.innerHTML = 'everybody'; + + // No updates to data yet + assert.htmlEqual( + target.innerHTML, + ` + everybody +

hello world

+ ` + ); + + // Handle user input + const event = new window.Event('input'); + await el.dispatchEvent(event); + assert.htmlEqual( + target.innerHTML, + ` + everybody +

hello everybody

+ ` + ); + + component.name = 'goodbye'; + assert.equal(el.innerHTML, 'goodbye'); + assert.htmlEqual( + target.innerHTML, + ` + goodbye +

hello goodbye

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-contenteditable-html-initial/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html-initial/main.svelte similarity index 100% rename from test/runtime/samples/binding-contenteditable-html-initial/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html-initial/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html/_config.js new file mode 100644 index 000000000000..8c6d36b0bb29 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html/_config.js @@ -0,0 +1,50 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { name: 'world' }; + }, + + html: ` + world +

hello world

+ `, + + async test({ assert, component, target, window }) { + const el = target.querySelector('editor'); + ok(el); + assert.equal(el.innerHTML, 'world'); + + el.innerHTML = 'everybody'; + + // No updates to data yet + assert.htmlEqual( + target.innerHTML, + ` + everybody +

hello world

+ ` + ); + + // Handle user input + const event = new window.Event('input'); + await el.dispatchEvent(event); + assert.htmlEqual( + target.innerHTML, + ` + everybody +

hello everybody

+ ` + ); + + component.name = 'goodbye'; + assert.equal(el.innerHTML, 'goodbye'); + assert.htmlEqual( + target.innerHTML, + ` + goodbye +

hello goodbye

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html/main.svelte new file mode 100644 index 000000000000..4446bdabe05d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-html/main.svelte @@ -0,0 +1,6 @@ + + + +

hello {@html name}

diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-innertext/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-innertext/_config.js new file mode 100644 index 000000000000..08e0438a753e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-innertext/_config.js @@ -0,0 +1,34 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { name: 'world' }; + }, + + ssrHtml: ` + world +

hello world

+ `, + + async test({ assert, component, target, window }) { + // JSDom doesn't support innerText yet, so the test is not ideal + // https://github.com/jsdom/jsdom/issues/1245 + const el = target.querySelector('editor'); + ok(el); + + // @ts-expect-error + assert.equal(el.innerText, 'world'); + + const event = new window.Event('input'); + + // @ts-expect-error + el.innerText = 'everybody'; + await el.dispatchEvent(event); + assert.equal(component.name, 'everybody'); + + component.name = 'goodbye'; + + // @ts-expect-error + assert.equal(el.innerText, 'goodbye'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-innertext/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-innertext/main.svelte new file mode 100644 index 000000000000..d65350d1a85b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-innertext/main.svelte @@ -0,0 +1,6 @@ + + + +

hello {name}

diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text-initial/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text-initial/_config.js new file mode 100644 index 000000000000..83ad9c2558d8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text-initial/_config.js @@ -0,0 +1,52 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {string | null} */ + name: null + }; + }, + + html: ` + world +

hello world

+ `, + + ssrHtml: ` + world +

hello

+ `, + + test({ assert, component, target, window }) { + assert.equal(component.name, 'world'); + + const el = target.querySelector('editor'); + ok(el); + + const event = new window.Event('input'); + + el.textContent = 'everybody'; + el.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + everybody +

hello everybody

+ ` + ); + + component.name = 'goodbye'; + assert.equal(el.textContent, 'goodbye'); + assert.htmlEqual( + target.innerHTML, + ` + goodbye +

hello goodbye

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-contenteditable-text-initial/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text-initial/main.svelte similarity index 100% rename from test/runtime/samples/binding-contenteditable-text-initial/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text-initial/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text/_config.js new file mode 100644 index 000000000000..494c338bfe8b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text/_config.js @@ -0,0 +1,43 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { name: 'world' }; + }, + + html: ` + world +

hello world

+ `, + + test({ assert, component, target, window }) { + const el = target.querySelector('editor'); + ok(el); + assert.equal(el.textContent, 'world'); + + const event = new window.Event('input'); + + el.textContent = 'everybody'; + el.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + everybody +

hello everybody

+ ` + ); + + component.name = 'goodbye'; + assert.equal(el.textContent, 'goodbye'); + assert.htmlEqual( + target.innerHTML, + ` + goodbye +

hello goodbye

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-contenteditable-text/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text/main.svelte similarity index 100% rename from test/runtime/samples/binding-contenteditable-text/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-contenteditable-text/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-details-open/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-details-open/_config.js new file mode 100644 index 000000000000..188ac00d3c4c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-details-open/_config.js @@ -0,0 +1,34 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +
toggle
+ `, + + async test({ assert, component, target, window }) { + const details = target.querySelector('details'); + ok(details); + const event = new window.Event('toggle'); + + details.open = true; + await details.dispatchEvent(event); + assert.equal(component.visible, true); + assert.htmlEqual( + target.innerHTML, + ` +
toggle
+

hello!

+ ` + ); + + details.open = false; + await details.dispatchEvent(event); + assert.equal(component.visible, false); + assert.htmlEqual( + target.innerHTML, + ` +
toggle
+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-details-open/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-details-open/main.svelte similarity index 100% rename from test/runtime/samples/binding-details-open/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-details-open/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-focused/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-focused/_config.js new file mode 100644 index 000000000000..02f2574f340e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-focused/_config.js @@ -0,0 +1,19 @@ +import { flushSync } from 'svelte'; + +import { test } from '../../test'; + +export default test({ + async test({ assert, component, target, window }) { + const [in1, in2] = target.querySelectorAll('input'); + + flushSync(() => in1.focus()); + assert.equal(window.document.activeElement, in1); + assert.equal(component.a, true); + assert.equal(component.b, false); + + flushSync(() => in2.focus()); + assert.equal(window.document.activeElement, in2); + assert.equal(component.a, false); + assert.equal(component.b, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-focused/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-focused/main.svelte new file mode 100644 index 000000000000..7ba892393dc7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-focused/main.svelte @@ -0,0 +1,7 @@ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-indirect-computed/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-computed/_config.js new file mode 100644 index 000000000000..d6ad6203560b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-computed/_config.js @@ -0,0 +1,42 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + html: ` + + `, + + test({ assert, component, target, window }) { + const select = target.querySelector('select'); + ok(select); + const options = target.querySelectorAll('option'); + + const change = new window.Event('change'); + + options[1].selected = true; + select.dispatchEvent(change); + flushSync(); + + assert.equal(component.selected.letter, 'B'); + assert.htmlEqual( + target.innerHTML, + ` + + + B + ` + ); + } +}); diff --git a/test/runtime/samples/binding-indirect-computed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-computed/main.svelte similarity index 100% rename from test/runtime/samples/binding-indirect-computed/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-indirect-computed/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-indirect-spread/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-spread/_config.js new file mode 100644 index 000000000000..35dfb6b7a9a5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-spread/_config.js @@ -0,0 +1,58 @@ +import { test } from '../../test'; + +export default test({ + ssrHtml: ` + + + + + + + + `, + async test({ assert, component, target, window }) { + const event = new window.MouseEvent('click'); + + const [radio1, radio2, radio3] = /** @type {NodeListOf} */ ( + target.querySelectorAll('input[type=radio]') + ); + + assert.ok(!radio1.checked); + assert.ok(radio2.checked); + assert.ok(!radio3.checked); + + component.radio = 'radio1'; + + assert.ok(radio1.checked); + assert.ok(!radio2.checked); + assert.ok(!radio3.checked); + + await radio3.dispatchEvent(event); + + assert.equal(component.radio, 'radio3'); + assert.ok(!radio1.checked); + assert.ok(!radio2.checked); + assert.ok(radio3.checked); + + const [check1, check2, check3] = /** @type {NodeListOf} */ ( + target.querySelectorAll('input[type=checkbox]') + ); + + assert.ok(!check1.checked); + assert.ok(check2.checked); + assert.ok(!check3.checked); + + component.check = ['check1', 'check2']; + + assert.ok(check1.checked); + assert.ok(check2.checked); + assert.ok(!check3.checked); + + await check3.dispatchEvent(event); + + assert.deepEqual(component.check, ['check1', 'check2', 'check3']); + assert.ok(check1.checked); + assert.ok(check2.checked); + assert.ok(check3.checked); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-indirect-spread/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-spread/main.svelte new file mode 100644 index 000000000000..43129b08b7d6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-spread/main.svelte @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-indirect-value/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-value/Component.svelte new file mode 100644 index 000000000000..25bf0d6758c6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-value/Component.svelte @@ -0,0 +1,6 @@ + + +Child component "{value}"
diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-indirect-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-value/_config.js new file mode 100644 index 000000000000..b88da28facb1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-value/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + assert.htmlEqual( + target.innerHTML, + ` + Parent component "bar"
+ Child component "bar"
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-indirect-value/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-value/main.svelte new file mode 100644 index 000000000000..db2734c89091 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-indirect-value/main.svelte @@ -0,0 +1,8 @@ + + +Parent component "{value}"
+ diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js new file mode 100644 index 000000000000..d0b46cffa6d5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-indirect/_config.js @@ -0,0 +1,113 @@ +import { ok, test } from '../../test'; +import { flushSync } from 'svelte'; + +/** @type {Array<{ description: string, done: boolean }>} */ +let tasks = []; + +export default test({ + mode: ['client', 'hydrate'], // unnecessary to test this in ssr mode + + get props() { + tasks = [ + { description: 'put your left leg in', done: false }, + { description: 'your left leg out', done: false }, + { description: 'in, out, in, out', done: false }, + { description: 'shake it all about', done: false } + ]; + return { tasks, selected: tasks[0] }; + }, + + html: ` + + + + +

Pending tasks

+

put your left leg in

+

your left leg out

+

in, out, in, out

+

shake it all about

+ `, + + async test({ assert, component, target, window }) { + const input = target.querySelector('input'); + const select = target.querySelector('select'); + const options = target.querySelectorAll('option'); + ok(input); + ok(select); + + const change = new window.Event('change'); + + input.checked = true; + + flushSync(() => { + input.dispatchEvent(change); + }); + + assert.ok(component.tasks[0].done); + + assert.htmlEqual( + target.innerHTML, + ` + + + + +

Pending tasks

+

your left leg out

+

in, out, in, out

+

shake it all about

+ ` + ); + + options[1].selected = true; + + flushSync(() => { + select.dispatchEvent(change); + }); + + assert.deepEqual(component.selected, tasks[1]); // TODO this should be assert.equal, but that crashes the entire test suite in mysterious ways... something to do with proxies not being reused? + assert.ok(!input.checked); + + input.checked = true; + + flushSync(() => { + input.dispatchEvent(change); + }); + + assert.ok(component.tasks[1].done); + assert.htmlEqual( + target.innerHTML, + ` + + + + +

Pending tasks

+

in, out, in, out

+

shake it all about

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-indirect/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-indirect/main.svelte similarity index 100% rename from test/runtime/samples/binding-indirect/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-indirect/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual-b/_config.js new file mode 100644 index 000000000000..ceb6c8b72eb6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual-b/_config.js @@ -0,0 +1,62 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
+

one

+
+
+

two

+
+
+

three

+
+ `, + + ssrHtml: ` +
+

one

+
+
+

two

+
+
+

three

+
+ `, + + test({ assert, component, target, window }) { + const inputs = [...target.querySelectorAll('input')]; + + const event = new window.Event('change'); + + inputs[1].checked = true; + inputs[1].dispatchEvent(event); + flushSync(); + + component.clear(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

one

+

three

+ ` + ); + + inputs[2].checked = true; + inputs[2].dispatchEvent(event); + flushSync(); + component.clear(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

one

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-checkbox-deep-contextual-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual-b/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-checkbox-deep-contextual-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual-b/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual/_config.js new file mode 100644 index 000000000000..c5fd2f7b4995 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual/_config.js @@ -0,0 +1,76 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { + items: [ + { description: 'one', completed: true }, + { description: 'two', completed: false }, + { description: 'three', completed: false } + ] + }; + }, + + html: ` +
+

one

+
+
+

two

+
+
+

three

+
+

1 completed

+ `, + + ssrHtml: ` +
+

one

+
+
+

two

+
+
+

three

+
+

1 completed

+ `, + + test({ assert, component, target, window }) { + const inputs = [...target.querySelectorAll('input')]; + + assert.ok(inputs[0].checked); + assert.ok(!inputs[1].checked); + assert.ok(!inputs[2].checked); + + const event = new window.Event('change'); + + inputs[1].checked = true; + inputs[1].dispatchEvent(event); + flushSync(); + + assert.equal(component.numCompleted, 2); + assert.htmlEqual( + target.innerHTML, + ` +

one

two

three

+

2 completed

+ ` + ); + + const items = component.items; + items[2].completed = true; + + component.items = items; + assert.ok(inputs[2].checked); + assert.htmlEqual( + target.innerHTML, + ` +

one

two

three

+

3 completed

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual/main.svelte new file mode 100644 index 000000000000..e092430b2bb3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-deep-contextual/main.svelte @@ -0,0 +1,14 @@ + + +{#each items as item} +

{item.description}

+{/each} + +

{numCompleted} completed

diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-group-outside-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-group-outside-each/_config.js new file mode 100644 index 000000000000..489584127d9c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-group-outside-each/_config.js @@ -0,0 +1,96 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +const values = [{ name: 'Alpha' }, { name: 'Beta' }, { name: 'Gamma' }]; + +export default test({ + get props() { + return { values, selected: [values[1]] }; + }, + + html: ` + + + + + + +

Beta

`, + + ssrHtml: ` + + + + + + +

Beta

`, + + test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, false); + + const event = new window.Event('change'); + + inputs[0].checked = true; + inputs[0].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + + + + +

Alpha, Beta

+ ` + ); + + component.selected = [component.values[1], component.values[2]]; + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, true); + + assert.htmlEqual( + target.innerHTML, + ` + + + + + + +

Beta, Gamma

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-checkbox-group-outside-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-group-outside-each/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-checkbox-group-outside-each/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-group-outside-each/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-group/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-group/_config.js new file mode 100644 index 000000000000..c669bbb21d50 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-group/_config.js @@ -0,0 +1,96 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +const values = [{ name: 'Alpha' }, { name: 'Beta' }, { name: 'Gamma' }]; + +export default test({ + get props() { + return { values, selected: [values[1]] }; + }, + + html: ` + + + + + + +

Beta

`, + + ssrHtml: ` + + + + + + +

Beta

`, + + test({ assert, component, target, window }) { + let inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, false); + + const event = new window.Event('change'); + + inputs[0].checked = true; + inputs[0].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + + + + +

Alpha, Beta

+ ` + ); + + component.selected = [component.values[1], component.values[2]]; + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, true); + + assert.htmlEqual( + target.innerHTML, + ` + + + + + + +

Beta, Gamma

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-checkbox-group/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-group/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-checkbox-group/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-group/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-indeterminate/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-indeterminate/_config.js new file mode 100644 index 000000000000..eba77322a1b9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-indeterminate/_config.js @@ -0,0 +1,58 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { indeterminate: true }; + }, + + html: ` + +

checked? false

+

indeterminate? true

+ `, + + ssrHtml: ` + +

checked?

+

indeterminate? true

+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + + assert.equal(input.checked, false); + assert.equal(input.indeterminate, true); + + const event = new window.Event('change'); + + input.checked = true; + input.indeterminate = false; + input.dispatchEvent(event); + flushSync(); + + assert.equal(component.indeterminate, false); + assert.equal(component.checked, true); + assert.htmlEqual( + target.innerHTML, + ` + +

checked? true

+

indeterminate? false

+ ` + ); + + component.indeterminate = true; + assert.equal(input.indeterminate, true); + assert.equal(input.checked, true); + assert.htmlEqual( + target.innerHTML, + ` + +

checked? true

+

indeterminate? true

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-checkbox-indeterminate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-indeterminate/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-checkbox-indeterminate/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-indeterminate/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-with-event-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-with-event-in-each/_config.js new file mode 100644 index 000000000000..58cb5109b811 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-with-event-in-each/_config.js @@ -0,0 +1,37 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + cats: [ + { name: 'cat 0', checked: false }, + { name: 'cat 1', checked: false } + ] + }; + }, + + html: ` + + + `, + + test({ assert, component, target, window }) { + const { cats } = component; + const newCats = cats.slice(); + newCats.push({ + name: 'cat ' + cats.length, + checked: false + }); + component.cats = newCats; + + let inputs = target.querySelectorAll('input'); + assert.equal(inputs.length, 3); + + const event = new window.Event('change'); + inputs[0].checked = true; + inputs[0].dispatchEvent(event); + + inputs = target.querySelectorAll('input'); + assert.equal(inputs.length, 3); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-with-event-in-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-with-event-in-each/main.svelte new file mode 100644 index 000000000000..97bb546bcc9e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox-with-event-in-each/main.svelte @@ -0,0 +1,11 @@ + + +{#each cats as cat (cat.name)} + +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox/_config.js new file mode 100644 index 000000000000..1d8a20868206 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox/_config.js @@ -0,0 +1,49 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { foo: true }; + }, + + html: ` + +

true

+ `, + + ssrHtml: ` + +

true

+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + + assert.equal(input.checked, true); + + const event = new window.Event('change'); + + input.checked = false; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

false

+ ` + ); + + component.foo = true; + assert.equal(input.checked, true); + assert.htmlEqual( + target.innerHTML, + ` + +

true

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-checkbox/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-checkbox/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-checkbox/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-duplicate-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-duplicate-value/_config.js new file mode 100644 index 000000000000..6d3c494d0d67 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-duplicate-value/_config.js @@ -0,0 +1,88 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` +

Checked:

+ +
+ + a
+ b
+ c
+ d
+ +
+ + a
+ b
+ c
+ d
+ `, + + test({ assert, target, window }) { + const inputs = target.querySelectorAll('input'); + const p = target.querySelector('p'); + ok(p); + + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + assert.equal(inputs[3].checked, false); + + assert.equal(inputs[4].checked, false); + assert.equal(inputs[5].checked, false); + assert.equal(inputs[6].checked, false); + assert.equal(inputs[7].checked, false); + + const event = new window.Event('change'); + + inputs[0].checked = true; + inputs[0].dispatchEvent(event); + flushSync(); + + assert.htmlEqual(p.innerHTML, 'Checked: a'); + + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + assert.equal(inputs[3].checked, false); + + assert.equal(inputs[4].checked, true); + assert.equal(inputs[5].checked, false); + assert.equal(inputs[6].checked, false); + assert.equal(inputs[7].checked, false); + + inputs[3].checked = true; + inputs[3].dispatchEvent(event); + flushSync(); + + assert.htmlEqual(p.innerHTML, 'Checked: a,d'); + + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + assert.equal(inputs[3].checked, true); + + assert.equal(inputs[4].checked, true); + assert.equal(inputs[5].checked, false); + assert.equal(inputs[6].checked, false); + assert.equal(inputs[7].checked, true); + + inputs[4].checked = false; + inputs[4].dispatchEvent(event); + flushSync(); + + assert.htmlEqual(p.innerHTML, 'Checked: d'); + + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + assert.equal(inputs[3].checked, true); + + assert.equal(inputs[4].checked, false); + assert.equal(inputs[5].checked, false); + assert.equal(inputs[6].checked, false); + assert.equal(inputs[7].checked, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-duplicate-value/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-duplicate-value/main.svelte new file mode 100644 index 000000000000..153e559d239a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-duplicate-value/main.svelte @@ -0,0 +1,19 @@ + + +

Checked: {foo}

+ +
+ +a
+b
+c
+d
+ +
+ +a
+b
+c
+d
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-1/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-1/_config.js new file mode 100644 index 000000000000..924072373872 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-1/_config.js @@ -0,0 +1,339 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +/** @type {Array<{ name: string }>} */ +let values = []; + +/** @type {Array>} */ +let selected_array = []; + +export default test({ + before_test() { + values = [{ name: 'Alpha' }, { name: 'Beta' }, { name: 'Gamma' }]; + selected_array = [[values[1]], [], [values[2]]]; + }, + + get props() { + return { values, selected_array }; + }, + + html: ` +
+ + + + + + +

Beta

+
+
+ + + + + + +

+
+
+ + + + + + +

Gamma

+
+ `, + + ssrHtml: ` +
+ + + + + + +

Beta

+
+
+ + + + + + +

+
+
+ + + + + + +

Gamma

+
+ `, + + test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, false); + assert.equal(inputs[3].checked, false); + assert.equal(inputs[4].checked, false); + assert.equal(inputs[5].checked, false); + assert.equal(inputs[6].checked, false); + assert.equal(inputs[7].checked, false); + assert.equal(inputs[8].checked, true); + + const event = new window.Event('change'); + + inputs[0].checked = true; + inputs[0].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+ + + + + + +

Alpha, Beta

+
+
+ + + + + + +

+
+
+ + + + + + +

Gamma

+
+ ` + ); + inputs[3].checked = true; + inputs[3].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+ + + + + + +

Alpha, Beta

+
+
+ + + + + + +

Alpha

+
+
+ + + + + + +

Gamma

+
+ ` + ); + + inputs[8].checked = false; + inputs[8].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+ + + + + + +

Alpha, Beta

+
+
+ + + + + + +

Alpha

+
+
+ + + + + + +

+
+ ` + ); + + component.selected_array = [[component.values[1], component.values[2]], [component.values[2]]]; + + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, true); + assert.equal(inputs[3].checked, false); + assert.equal(inputs[4].checked, false); + assert.equal(inputs[5].checked, true); + + assert.htmlEqual( + target.innerHTML, + ` +
+ + + + + + +

Beta, Gamma

+
+
+ + + + + + +

Gamma

+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-1/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-1/main.svelte new file mode 100644 index 000000000000..5ed255c83a87 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-1/main.svelte @@ -0,0 +1,15 @@ + + +{#each selected_array as selected} +
+ {#each values as value} + + {/each} +

{selected.map(v => v.name).join(', ')}

+
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-10/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-10/_config.js new file mode 100644 index 000000000000..4b573e2527ef --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-10/_config.js @@ -0,0 +1,54 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +// https://github.com/sveltejs/svelte/issues/7633 +export default test({ + test({ assert, target, component }) { + let inputs = target.querySelectorAll('input'); + + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + + component.moveDown(0); + flushSync(); + component.moveDown(1); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+ b +
+
+ c +
+
+ a +
+ ` + ); + + // after shifting order, should still keep the correct radio checked + inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, true); + + component.current = 'b'; + + inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + + component.moveDown(1); + + // after shifting order, should still keep the correct radio checked + inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-10/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-10/main.svelte new file mode 100644 index 000000000000..7c81cada9a00 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-10/main.svelte @@ -0,0 +1,36 @@ + + +{#each list as item (item.name)} +
+ {item.name} + {#if true} + + {/if} +
+{/each} + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-11/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-11/_config.js new file mode 100644 index 000000000000..64d0fd8f9389 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-11/_config.js @@ -0,0 +1,93 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +// https://github.com/sveltejs/svelte/issues/6112 +export default test({ + test({ assert, target, component, window }) { + let inputs = target.querySelectorAll('input'); + + /** @param {Set} set */ + const check = (set) => { + for (let i = 0; i < inputs.length; i++) { + assert.equal(inputs[i].checked, set.has(i)); + } + }; + + assert.htmlEqual( + target.innerHTML, + ` +
1
+
2 +
+ + +
+
+ + +
+
+
3 +
+ + +
+
+ + +
+
+ ` + ); + + check(new Set([0, 2, 5, 6])); + + const event = new window.Event('change'); + + // dom to value + inputs[3].checked = true; + inputs[3].dispatchEvent(event); + flushSync(); + + check(new Set([0, 3, 5, 6])); + assert.equal(component.pipelineOperations[1].operation.args[1].value, 'd'); + + // remove item + component.pipelineOperations = component.pipelineOperations.slice(1); + + assert.htmlEqual( + target.innerHTML, + ` +
2 +
+ + +
+
+ + +
+
+
3 +
+ + +
+
+ + +
+
+ ` + ); + + inputs = target.querySelectorAll('input'); + check(new Set([0, 3, 5, 6])); + + inputs[2].checked = true; + inputs[2].dispatchEvent(event); + flushSync(); + + check(new Set([0, 2, 5, 6])); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-11/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-11/main.svelte new file mode 100644 index 000000000000..7c759b5bb4ab --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-11/main.svelte @@ -0,0 +1,60 @@ + + +{#each pipelineOperations as { operation, id } (id)} +
+ {id} + {#each operation.args as arg} +
+ {#each arg.options as { value }} + + {/each} +
+ {/each} +
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-12/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-12/_config.js new file mode 100644 index 000000000000..14b8030d8995 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-12/_config.js @@ -0,0 +1,94 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +// https://github.com/sveltejs/svelte/issues/6112 +export default test({ + test({ assert, target, component, window }) { + let inputs = target.querySelectorAll('input'); + + /** @param {Set} set */ + const check = (set) => { + for (let i = 0; i < inputs.length; i++) { + assert.equal(inputs[i].checked, set.has(i)); + } + }; + + assert.htmlEqual( + target.innerHTML, + ` +
1
+
2 +
+ + +
+
+ + +
+
+
3 +
+ + +
+
+ + +
+
+ ` + ); + + check(new Set([0, 2])); + + const event = new window.Event('change'); + + // dom to value + inputs[3].checked = true; + inputs[3].dispatchEvent(event); + flushSync(); + + check(new Set([0, 2, 3])); + assert.deepEqual(component.pipelineOperations[1].operation.args[1].value, ['c', 'd']); + + // remove item + component.pipelineOperations = component.pipelineOperations.slice(1); + + assert.htmlEqual( + target.innerHTML, + ` +
2 +
+ + +
+
+ + +
+
+
3 +
+ + +
+
+ + +
+
+ ` + ); + + inputs = target.querySelectorAll('input'); + check(new Set([0, 2, 3])); + + inputs[5].checked = true; + inputs[5].dispatchEvent(event); + flushSync(); + + check(new Set([0, 2, 3, 5])); + assert.deepEqual(component.pipelineOperations[1].operation.args[0].value, ['b']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-12/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-12/main.svelte new file mode 100644 index 000000000000..289353778ae7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-12/main.svelte @@ -0,0 +1,60 @@ + + +{#each pipelineOperations as { operation, id } (id)} +
+ {id} + {#each operation.args as arg} +
+ {#each arg.options as { value }} + + {/each} +
+ {/each} +
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-13/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-13/_config.js new file mode 100644 index 000000000000..7fba86ef347a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-13/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const [input1, input2] = /** @type {NodeListOf} */ ( + target.querySelectorAll('input[type=text]') + ); + const radio = /** @type {HTMLInputElement} */ (target.querySelector('input[type=radio]')); + + assert.equal(radio.checked, false); + + const event = new window.Event('input'); + + input1.value = 'world'; + input1.dispatchEvent(event); + flushSync(); + assert.equal(radio.checked, true); + + input2.value = 'foo'; + input2.dispatchEvent(event); + flushSync(); + assert.equal(radio.checked, false); + + input1.value = 'foo'; + input1.dispatchEvent(event); + flushSync(); + assert.equal(radio.checked, true); + + input1.value = 'bar'; + input1.dispatchEvent(event); + flushSync(); + assert.equal(radio.checked, false); + + input2.value = 'bar'; + input2.dispatchEvent(event); + flushSync(); + assert.equal(radio.checked, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-13/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-13/main.svelte new file mode 100644 index 000000000000..592be2ae9d31 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-13/main.svelte @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-14/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-14/_config.js new file mode 100644 index 000000000000..a0649c44de45 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-14/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const [input1, input2, input3, input4] = target.querySelectorAll('input'); + const [p] = target.querySelectorAll('p'); + const event = new window.Event('change'); + + input1.checked = true; + input1.dispatchEvent(event); + flushSync(); + assert.htmlEqual(p.innerHTML, '["1a"]'); + + input2.checked = true; + input1.dispatchEvent(event); + flushSync(); + assert.htmlEqual(p.innerHTML, '["1a","1b"]'); + + input3.checked = true; + input1.dispatchEvent(event); + flushSync(); + assert.htmlEqual(p.innerHTML, '["1a","1b","2a"]'); + + input4.checked = true; + input1.dispatchEvent(event); + flushSync(); + assert.htmlEqual(p.innerHTML, '["1a","1b","2a","2b"]'); + + input1.checked = false; + input1.dispatchEvent(event); + flushSync(); + assert.htmlEqual(p.innerHTML, '["1b","2a","2b"]'); + + input3.checked = false; + input1.dispatchEvent(event); + flushSync(); + assert.htmlEqual(p.innerHTML, '["1b","2b"]'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-14/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-14/main.svelte new file mode 100644 index 000000000000..5df442c6ec9e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-14/main.svelte @@ -0,0 +1,26 @@ + + +{#each options as [prefix, arr]} + {prefix} +
+ {#each arr as item} + + {/each} +
+{/each} + +

{JSON.stringify(group)}

diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-15/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-15/_config.js new file mode 100644 index 000000000000..a7996e46ff68 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-15/_config.js @@ -0,0 +1,26 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const checkboxes = /** @type {NodeListOf} */ ( + target.querySelectorAll('input[type="checkbox"]') + ); + + assert.isFalse(checkboxes[0].checked); + assert.isTrue(checkboxes[1].checked); + assert.isFalse(checkboxes[2].checked); + + checkboxes[1].click(); + flushSync(); + + const noChecked = target.querySelector('#output')?.innerHTML; + assert.equal(noChecked, ''); + + checkboxes[1].click(); + flushSync(); + + const oneChecked = target.querySelector('#output')?.innerHTML; + assert.equal(oneChecked, 'Mint choc chip'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-15/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-15/main.svelte new file mode 100644 index 000000000000..0b666295a2fe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-15/main.svelte @@ -0,0 +1,18 @@ + + +
+ One scoop + Two scoops + Three scoops + + {#each menu as flavour} + {flavour} + {/each} +
+ +
{$order.iceCream[index].flavours.join('+')}
diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-16/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-16/_config.js new file mode 100644 index 000000000000..a7996e46ff68 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-16/_config.js @@ -0,0 +1,26 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const checkboxes = /** @type {NodeListOf} */ ( + target.querySelectorAll('input[type="checkbox"]') + ); + + assert.isFalse(checkboxes[0].checked); + assert.isTrue(checkboxes[1].checked); + assert.isFalse(checkboxes[2].checked); + + checkboxes[1].click(); + flushSync(); + + const noChecked = target.querySelector('#output')?.innerHTML; + assert.equal(noChecked, ''); + + checkboxes[1].click(); + flushSync(); + + const oneChecked = target.querySelector('#output')?.innerHTML; + assert.equal(oneChecked, 'Mint choc chip'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-16/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-16/main.svelte new file mode 100644 index 000000000000..f9aed83ed245 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-16/main.svelte @@ -0,0 +1,17 @@ + + +
+ One scoop + Two scoops + Three scoops + + {#each menu as flavour} + {flavour} + {/each} +
+ +
{$order.flavours.join('+')}
diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-2/_config.js new file mode 100644 index 000000000000..ad5b33fef43b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-2/_config.js @@ -0,0 +1,82 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + + +

1, 2, 3

`, + + ssrHtml: ` + + + + +

1, 2, 3

`, + + test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, true); + + const event = new window.Event('change'); + + inputs[0].checked = false; + inputs[0].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + + +

2, 3

+ ` + ); + + component.selected = [[1, 3]]; + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, true); + + assert.htmlEqual( + target.innerHTML, + ` + + + + +

1, 3

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-2/main.svelte new file mode 100644 index 000000000000..46f7e9e69858 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-2/main.svelte @@ -0,0 +1,17 @@ + + +{#each options as value} + +{/each} + +

{selected[0].join(', ')}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-3/_config.js new file mode 100644 index 000000000000..84b783df75f6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-3/_config.js @@ -0,0 +1,338 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +/** @type {Array<{ name: string }>} */ +let values = []; + +/** @type {Array>} */ +let selected_array = []; + +export default test({ + before_test() { + values = [{ name: 'Alpha' }, { name: 'Beta' }, { name: 'Gamma' }]; + selected_array = [[values[1]], [], [values[2]]]; + }, + + get props() { + return { values, selected_array }; + }, + + html: ` +
+ + + + + + +

Beta

+
+
+ + + + + + +

+
+
+ + + + + + +

Gamma

+
+ `, + ssrHtml: ` +
+ + + + + + +

Beta

+
+
+ + + + + + +

+
+
+ + + + + + +

Gamma

+
+ `, + test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, false); + assert.equal(inputs[3].checked, false); + assert.equal(inputs[4].checked, false); + assert.equal(inputs[5].checked, false); + assert.equal(inputs[6].checked, false); + assert.equal(inputs[7].checked, false); + assert.equal(inputs[8].checked, true); + + const event = new window.Event('change'); + + inputs[0].checked = true; + inputs[0].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+ + + + + + +

Alpha, Beta

+
+
+ + + + + + +

+
+
+ + + + + + +

Gamma

+
+ ` + ); + inputs[3].checked = true; + inputs[3].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+ + + + + + +

Alpha, Beta

+
+
+ + + + + + +

Alpha

+
+
+ + + + + + +

Gamma

+
+ ` + ); + + inputs[8].checked = false; + inputs[8].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+ + + + + + +

Alpha, Beta

+
+
+ + + + + + +

Alpha

+
+
+ + + + + + +

+
+ ` + ); + + component.selected_array = [[component.values[1], component.values[2]], [component.values[2]]]; + + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, true); + assert.equal(inputs[3].checked, false); + assert.equal(inputs[4].checked, false); + assert.equal(inputs[5].checked, true); + + assert.htmlEqual( + target.innerHTML, + ` +
+ + + + + + +

Beta, Gamma

+
+
+ + + + + + +

Gamma

+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-3/main.svelte new file mode 100644 index 000000000000..42a7a1c4e9b9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-3/main.svelte @@ -0,0 +1,15 @@ + + +{#each selected_array as _, index} +
+ {#each values as value} + + {/each} +

{selected_array[index].map(v => v.name).join(', ')}

+
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-4/_config.js new file mode 100644 index 000000000000..1a78e91214f2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-4/_config.js @@ -0,0 +1,196 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + +

1

+ + + +

2

+ + + +

+ + + +

3

+ `, + ssrHtml: ` + + + +

1

+ + + +

2

+ + + +

+ + + +

3

+ `, + test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + + assert.equal(inputs[3].checked, false); + assert.equal(inputs[4].checked, true); + assert.equal(inputs[5].checked, false); + + assert.equal(inputs[6].checked, false); + assert.equal(inputs[7].checked, false); + assert.equal(inputs[8].checked, false); + + assert.equal(inputs[9].checked, false); + assert.equal(inputs[10].checked, false); + assert.equal(inputs[11].checked, true); + + const event = new window.Event('change'); + + inputs[2].checked = true; + inputs[2].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

1, 3

+ + + +

2

+ + + +

+ + + +

3

+ ` + ); + + inputs[9].checked = true; + inputs[9].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

1, 3

+ + + +

2

+ + + +

+ + + +

1, 3

+ ` + ); + + inputs[4].checked = false; + inputs[4].dispatchEvent(event); + flushSync(); + + inputs[5].checked = true; + inputs[5].dispatchEvent(event); + flushSync(); + + inputs[6].checked = true; + inputs[6].dispatchEvent(event); + flushSync(); + + inputs[7].checked = true; + inputs[7].dispatchEvent(event); + flushSync(); + + inputs[11].checked = false; + inputs[11].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

1, 3

+ + + +

3

+ + + +

1, 2

+ + + +

1

+ ` + ); + + component.selected_array_1 = [[3], [1]]; + component.selected_array_2 = [[], [2]]; + + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, true); + + assert.equal(inputs[3].checked, true); + assert.equal(inputs[4].checked, false); + assert.equal(inputs[5].checked, false); + + assert.equal(inputs[6].checked, false); + assert.equal(inputs[7].checked, false); + assert.equal(inputs[8].checked, false); + + assert.equal(inputs[9].checked, false); + assert.equal(inputs[10].checked, true); + assert.equal(inputs[11].checked, false); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

3

+ + + +

1

+ + + +

+ + + +

2

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-4/main.svelte new file mode 100644 index 000000000000..0bbf5ea763c6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-4/main.svelte @@ -0,0 +1,33 @@ + + +{#each selected_array_1 as selected} + {#each options as value} + + {/each} +

{selected.join(', ')}

+{/each} + +{#each selected_array_2 as selected} + {#each options as value} + + {/each} +

{selected.join(', ')}

+{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-5/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-5/_config.js new file mode 100644 index 000000000000..08af96a844fa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-5/_config.js @@ -0,0 +1,195 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + +

1

+ + + +

1, 2, 3

+ + + +

2

+ + + +

1

+ `, + ssrHtml: ` + + + +

1

+ + + +

1, 2, 3

+ + + +

2

+ + + +

1

+ `, + test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + + assert.equal(inputs[3].checked, true); + assert.equal(inputs[4].checked, true); + assert.equal(inputs[5].checked, true); + + assert.equal(inputs[6].checked, false); + assert.equal(inputs[7].checked, true); + assert.equal(inputs[8].checked, false); + + assert.equal(inputs[9].checked, true); + assert.equal(inputs[10].checked, false); + assert.equal(inputs[11].checked, false); + + const event = new window.Event('change'); + + inputs[2].checked = true; + inputs[2].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

1, 3

+ + + +

1, 2, 3

+ + + +

2

+ + + +

1

+ ` + ); + + inputs[8].checked = true; + inputs[8].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

1, 3

+ + + +

1, 2, 3

+ + + +

2, 3

+ + + +

1

+ ` + ); + + component.selected_index = [1, 1]; + + assert.htmlEqual( + target.innerHTML, + ` + + + +

1, 2, 3

+ + + +

1, 2, 3

+ + + +

1

+ + + +

1

+ ` + ); + + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, true); + + assert.equal(inputs[3].checked, true); + assert.equal(inputs[4].checked, true); + assert.equal(inputs[5].checked, true); + + assert.equal(inputs[6].checked, true); + assert.equal(inputs[7].checked, false); + assert.equal(inputs[8].checked, false); + + assert.equal(inputs[9].checked, true); + assert.equal(inputs[10].checked, false); + assert.equal(inputs[11].checked, false); + + inputs[5].checked = false; + inputs[5].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

1, 2

+ + + +

1, 2

+ + + +

1

+ + + +

1

+ ` + ); + + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, false); + + assert.equal(inputs[3].checked, true); + assert.equal(inputs[4].checked, true); + assert.equal(inputs[5].checked, false); + + assert.equal(inputs[6].checked, true); + assert.equal(inputs[7].checked, false); + assert.equal(inputs[8].checked, false); + + assert.equal(inputs[9].checked, true); + assert.equal(inputs[10].checked, false); + assert.equal(inputs[11].checked, false); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-5/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-5/main.svelte new file mode 100644 index 000000000000..93bdce651093 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-5/main.svelte @@ -0,0 +1,24 @@ + + +{#each selected_array as selected} + {#each selected_index as index} + {#each options as value} + + {/each} +

{selected[index].join(', ')}

+ {/each} +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-6/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-6/_config.js new file mode 100644 index 000000000000..b4cf9e7ed6a3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-6/_config.js @@ -0,0 +1,101 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + +

+ + + +

+ + + +

+ `, + test({ assert, target, window }) { + const inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + + assert.equal(inputs[3].checked, false); + assert.equal(inputs[4].checked, false); + assert.equal(inputs[5].checked, false); + + assert.equal(inputs[6].checked, false); + assert.equal(inputs[7].checked, false); + assert.equal(inputs[8].checked, false); + + const event = new window.Event('change'); + + inputs[2].checked = true; + inputs[2].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

z

+ + + +

+ + + +

+ ` + ); + + inputs[4].checked = true; + inputs[4].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

z

+ + + +

y

+ + + +

+ ` + ); + + inputs[5].checked = true; + inputs[5].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

z

+ + + +

y, z

+ + + +

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-6/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-6/main.svelte new file mode 100644 index 000000000000..85be939e8a99 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-6/main.svelte @@ -0,0 +1,22 @@ + + +{#each Object.keys(list) as key} + {#each values as value} + + {/each} +

{list[key].join(', ')}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-7/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-7/_config.js new file mode 100644 index 000000000000..f51154ef0002 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-7/_config.js @@ -0,0 +1,61 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + + + + + + + + + + + + + + + + + `, + + test({ assert, target, window }) { + const inputs = target.querySelectorAll('input'); + const checked = new Set(); + + /** @param {number} i */ + const checkInbox = (i) => { + checked.add(i); + inputs[i].checked = true; + inputs[i].dispatchEvent(event); + }; + + for (let i = 0; i < 18; i++) { + assert.equal(inputs[i].checked, checked.has(i)); + } + + const event = new window.Event('change'); + + checkInbox(2); + flushSync(); + for (let i = 0; i < 18; i++) { + assert.equal(inputs[i].checked, checked.has(i)); + } + + checkInbox(12); + flushSync(); + for (let i = 0; i < 18; i++) { + assert.equal(inputs[i].checked, checked.has(i)); + } + + checkInbox(8); + flushSync(); + for (let i = 0; i < 18; i++) { + assert.equal(inputs[i].checked, checked.has(i)); + } + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-7/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-7/main.svelte new file mode 100644 index 000000000000..6680a49f3294 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-7/main.svelte @@ -0,0 +1,15 @@ + + +{#each list as { id, data }} + {#each data as item} + + + + {/each} +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-8/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-8/_config.js new file mode 100644 index 000000000000..384ca0a20c7f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-8/_config.js @@ -0,0 +1,96 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +// https://github.com/sveltejs/svelte/issues/7884 +export default test({ + test({ assert, target, component, window }) { + let inputs = target.querySelectorAll('input'); + + assert.htmlEqual( + target.innerHTML, + ` +

{"foo":[],"bar":[]}

+

foo

+
    +
  • +
  • +
  • +
+

bar

+
    +
  • +
  • +
  • +
+ ` + ); + + const event = new window.Event('change'); + + inputs[0].checked = true; + inputs[0].dispatchEvent(event); + flushSync(); + inputs[2].checked = true; + inputs[2].dispatchEvent(event); + flushSync(); + inputs[3].checked = true; + inputs[3].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

{"foo":[1,3],"bar":[1]}

+

foo

+
    +
  • +
  • +
  • +
+

bar

+
    +
  • +
  • +
  • +
+ ` + ); + + component.update(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

{"foo":[1,3],"bar":[1],"qux":[]}

+

qux

+
    +
  • +
  • +
  • +
+ ` + ); + + inputs = target.querySelectorAll('input'); + inputs[0].checked = true; + inputs[0].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

{"foo":[1,3],"bar":[1],"qux":[4]}

+

qux

+
    +
  • +
  • +
  • +
+ ` + ); + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-8/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-8/main.svelte new file mode 100644 index 000000000000..135b37bdf0e6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-8/main.svelte @@ -0,0 +1,36 @@ + + +

+ {JSON.stringify(object)} +

+ +{#each keys as key (key)} +

{key}

+
    + {#each values as value (value)} +
  • + +
  • + {/each} +
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-9/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-9/_config.js new file mode 100644 index 000000000000..b566e31cb9e2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-9/_config.js @@ -0,0 +1,54 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +// https://github.com/sveltejs/svelte/issues/7633 +export default test({ + test({ assert, target, component }) { + let inputs = target.querySelectorAll('input'); + + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + + component.moveDown(0); + flushSync(); + component.moveDown(1); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+ b +
+
+ c +
+
+ a +
+ ` + ); + + // after shifting order, should still keep the correct radio checked + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, true); + + component.current = 'b'; + flushSync(); + + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + + component.moveDown(1); + flushSync(); + + // after shifting order, should still keep the correct radio checked + inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-9/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-9/main.svelte new file mode 100644 index 000000000000..ee89123a9a1c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-each-9/main.svelte @@ -0,0 +1,36 @@ + + +{#each list as item} +
+ {item.name} + {#if true} + + {/if} +
+{/each} + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-1/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-1/_config.js new file mode 100644 index 000000000000..d91a7ebadb6c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-1/_config.js @@ -0,0 +1,56 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target, component, window }) { + const button = target.querySelector('button'); + ok(button); + const clickEvent = new window.Event('click', { bubbles: true }); + const changeEvent = new window.Event('change'); + + const [input1, input2] = /** @type {NodeListOf} */ ( + target.querySelectorAll('input[type="checkbox"]') + ); + + /** + * @param {boolean} v1 + * @param {boolean} v2 + */ + function validate_inputs(v1, v2) { + assert.equal(input1.checked, v1); + assert.equal(input2.checked, v2); + } + + assert.deepEqual(component.test, []); + validate_inputs(false, false); + + component.test = ['a', 'b']; + validate_inputs(true, true); + + input1.checked = false; + input1.dispatchEvent(changeEvent); + flushSync(); + assert.deepEqual(component.test, ['b']); + + input2.checked = false; + input2.dispatchEvent(changeEvent); + flushSync(); + assert.deepEqual(component.test, []); + + input1.checked = true; + input2.checked = true; + input1.dispatchEvent(changeEvent); + input2.dispatchEvent(changeEvent); + flushSync(); + assert.deepEqual(component.test, ['a', 'b']); + + button.dispatchEvent(clickEvent); + flushSync(); + assert.deepEqual(component.test, ['a', 'b']); // should it be ['a'] only? valid arguments for both outcomes + + input1.checked = false; + input1.dispatchEvent(changeEvent); + flushSync(); + assert.deepEqual(component.test, []); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-1/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-1/main.svelte new file mode 100644 index 000000000000..e696b3842245 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-1/main.svelte @@ -0,0 +1,14 @@ + + + + + +{#if !hidden} + +{/if} + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-2/_config.js new file mode 100644 index 000000000000..8647d33f0548 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-2/_config.js @@ -0,0 +1,49 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target, component, window }) { + const button = target.querySelector('button'); + ok(button); + const clickEvent = new window.Event('click', { bubbles: true }); + const changeEvent = new window.Event('change'); + + const [input1, input2] = /** @type {NodeListOf} */ ( + target.querySelectorAll('input[type="radio"]') + ); + + /** + * @param {boolean} v1 + * @param {boolean} v2 + */ + function validate_inputs(v1, v2) { + assert.equal(input1.checked, v1); + assert.equal(input2.checked, v2); + } + + component.test = 'a'; + validate_inputs(true, false); + + component.test = 'b'; + validate_inputs(false, true); + + input1.checked = true; + input1.dispatchEvent(changeEvent); + flushSync(); + assert.deepEqual(component.test, 'a'); + + input2.checked = true; + input2.dispatchEvent(changeEvent); + flushSync(); + assert.deepEqual(component.test, 'b'); + + button.dispatchEvent(clickEvent); + flushSync(); + assert.deepEqual(component.test, 'b'); // should it be undefined? valid arguments for both outcomes + + input1.checked = true; + input1.dispatchEvent(changeEvent); + flushSync(); + assert.deepEqual(component.test, 'a'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-2/main.svelte new file mode 100644 index 000000000000..9add22caccfc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-if-gh-8372-2/main.svelte @@ -0,0 +1,14 @@ + + + + + +{#if !hidden} + +{/if} + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-undefined/_config.js new file mode 100644 index 000000000000..11ea3c35aa6b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-undefined/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target, component, window }) { + const [input1, input2, input3] = target.querySelectorAll('input'); + const event = new window.Event('change'); + + /** + * + * @param {boolean} v1 + * @param {boolean} v2 + * @param {boolean} v3 + */ + function validate_inputs(v1, v2, v3) { + assert.equal(input1.checked, v1); + assert.equal(input2.checked, v2); + assert.equal(input3.checked, v3); + } + + assert.deepEqual(component.values.inner, []); + validate_inputs(false, false, false); + + component.values = { inner: undefined }; + assert.deepEqual(component.values.inner, undefined); + validate_inputs(false, false, false); + + input1.checked = true; + await input1.dispatchEvent(event); + assert.deepEqual(component.values.inner, ['first']); + validate_inputs(true, false, false); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-group-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-undefined/main.svelte new file mode 100644 index 000000000000..4dadc84a3106 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-group-undefined/main.svelte @@ -0,0 +1,15 @@ + + + + + + +
+ {#each ['first', 'second', 'third'] as k} + {k} + {/each} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-member-expression-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-member-expression-update/_config.js new file mode 100644 index 000000000000..8b7ae39cd8a0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-member-expression-update/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +// binding member expression shouldn't invalidate the property name +export default test({ + async test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + assert.deepEqual(component.logs.length, 1); + assert.equal(input.value, 'abc'); + + input.value = 'hij'; + await input.dispatchEvent(new window.Event('input')); + + assert.deepEqual(component.values.a, 'hij'); + assert.deepEqual(component.logs.length, 1); + + component.paths = ['b']; + assert.deepEqual(component.logs.length, 2); + assert.equal(input.value, 'def'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-member-expression-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-member-expression-update/main.svelte new file mode 100644 index 000000000000..dc72b229ba86 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-member-expression-update/main.svelte @@ -0,0 +1,9 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-number-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-number-2/_config.js new file mode 100644 index 000000000000..e6b235676d83 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-number-2/_config.js @@ -0,0 +1,44 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {number | undefined} */ + value: undefined + }; + }, + test({ assert, target, window, component }) { + const input = target.querySelector('input'); + ok(input); + const inputEvent = new window.InputEvent('input'); + assert.equal(component.value, 5); + assert.equal(input.value, '5'); + + input.value = '5.'; + input.dispatchEvent(inputEvent); + flushSync(); + + // input type number has value === "" if ends with dot/comma + assert.equal(component.value, undefined); + assert.equal(input.value, ''); + + input.value = '5.5'; + input.dispatchEvent(inputEvent); + flushSync(); + + assert.equal(component.value, 5.5); + assert.equal(input.value, '5.5'); + + input.value = '5.50'; + input.dispatchEvent(inputEvent); + flushSync(); + + assert.equal(component.value, 5.5); + assert.equal(input.value, '5.50'); + + component.value = 1; + assert.equal(component.value, 1); + assert.equal(input.value, '1'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-number-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-number-2/main.svelte new file mode 100644 index 000000000000..62119547a04d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-number-2/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-number/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-number/_config.js new file mode 100644 index 000000000000..4c0b68ecb91c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-number/_config.js @@ -0,0 +1,63 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { count: 42 }; + }, + + html: ` + +

number 42

+ `, + + ssrHtml: ` + +

number 42

+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + assert.equal(input.value, '42'); + + const event = new window.Event('input'); + + input.value = '43'; + input.dispatchEvent(event); + flushSync(); + + assert.equal(component.count, 43); + assert.htmlEqual( + target.innerHTML, + ` + +

number 43

+ ` + ); + + component.count = 44; + assert.equal(input.value, '44'); + assert.htmlEqual( + target.innerHTML, + ` + +

number 44

+ ` + ); + + // empty string should be treated as null + input.value = ''; + input.dispatchEvent(event); + flushSync(); + + assert.equal(component.count, null); + assert.htmlEqual( + target.innerHTML, + ` + +

object

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-number/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-number/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-number/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-number/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-radio-group/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-radio-group/_config.js new file mode 100644 index 000000000000..b0d5064383d7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-radio-group/_config.js @@ -0,0 +1,100 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +const values = [{ name: 'Alpha' }, { name: 'Beta' }, { name: 'Gamma' }]; + +export default test({ + get props() { + return { values, selected: values[1] }; + }, + + html: ` + + + + + + +

Beta

`, + + ssrHtml: ` + + + + + + +

Beta

`, + + test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, true); + assert.equal(inputs[2].checked, false); + + const event = new window.Event('change'); + + inputs[0].checked = true; + inputs[0].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + + + + +

Alpha

+ ` + ); + + assert.equal(inputs[0].checked, true); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, false); + + component.selected = component.values[2]; + assert.equal(inputs[0].checked, false); + assert.equal(inputs[1].checked, false); + assert.equal(inputs[2].checked, true); + + assert.htmlEqual( + target.innerHTML, + ` + + + + + + +

Gamma

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-radio-group/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-radio-group/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-radio-group/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-radio-group/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-range-change-with-max/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-range-change-with-max/_config.js new file mode 100644 index 000000000000..1c5a41ced360 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-range-change-with-max/_config.js @@ -0,0 +1,42 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + + +

10 of 10

+ `, + + ssrHtml: ` + + +

10 of 10

+ `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + assert.equal(input.value, '10'); + + // should not change because max is 10, input range behaviour + // seems there is bug in jsdom (HTMLInputElement-impl) which behaviour is different from real browsers + // input.value = '20'; + // assert.equal(input.value, '10'); + + const button = target.querySelector('button'); + ok(button); + button.dispatchEvent(new window.Event('click', { bubbles: true })); + flushSync(); + + assert.equal(input.value, '20'); + assert.htmlEqual( + target.innerHTML, + ` + + +

20 of 20

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-range-change-with-max/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-range-change-with-max/main.svelte new file mode 100644 index 000000000000..b1f34db437fd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-range-change-with-max/main.svelte @@ -0,0 +1,13 @@ + + + + +

{value} of {max}

diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-range/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-range/_config.js new file mode 100644 index 000000000000..9c3eecf37092 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-range/_config.js @@ -0,0 +1,49 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { count: 42 }; + }, + + html: ` + +

number 42

+ `, + + ssrHtml: ` + +

number 42

+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + assert.equal(input.value, '42'); + + const event = new window.Event('input'); + + input.value = '43'; + input.dispatchEvent(event); + flushSync(); + + assert.equal(component.count, 43); + assert.htmlEqual( + target.innerHTML, + ` + +

number 43

+ ` + ); + + component.count = 44; + assert.equal(input.value, '44'); + assert.htmlEqual( + target.innerHTML, + ` + +

number 44

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-range-change/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-range/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-range-change/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-range/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual-deconflicted/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual-deconflicted/_config.js new file mode 100644 index 000000000000..45403898ae5c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual-deconflicted/_config.js @@ -0,0 +1,43 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: 'a', items: ['x'] }; + }, + + html: ` +

a

+

x

+ `, + + ssrHtml: ` +

a

+

x

+ `, + + test({ assert, component, target, window }) { + const inputs = [...target.querySelectorAll('input')]; + const event = new window.Event('input'); + + assert.equal(inputs[0].value, 'a'); + + inputs[0].value = 'b'; + inputs[1].value = 'y'; + inputs[0].dispatchEvent(event); + flushSync(); + inputs[1].dispatchEvent(event); + flushSync(); + + assert.equal(component.foo, 'b'); + assert.equal(component.items[0], 'y'); + + assert.htmlEqual( + target.innerHTML, + ` +

b

+

y

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-text-contextual-deconflicted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual-deconflicted/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-text-contextual-deconflicted/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual-deconflicted/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual-reactive/_config.js new file mode 100644 index 000000000000..d20e4a1e88d3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual-reactive/_config.js @@ -0,0 +1,156 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { + items: [ + { done: false, text: 'one' }, + { done: true, text: 'two' }, + { done: false, text: 'three' } + ] + }; + }, + + html: ` +
+ +

one

+
+
+ +

two

+
+
+ +

three

+
+ +

remaining:one / done:two / remaining:three

+ `, + + ssrHtml: ` +
+ +

one

+
+
+ +

two

+
+
+ +

three

+
+ +

remaining:one / done:two / remaining:three

+ `, + + test({ assert, component, target, window }) { + /** + * @param {number} i + * @param {string} text + */ + function set_text(i, text) { + const input = /** @type {HTMLInputElement} */ ( + target.querySelectorAll('input[type="text"]')[i] + ); + input.value = text; + input.dispatchEvent(new window.Event('input')); + } + + /** + * @param {number} i + * @param {boolean} done + */ + function set_done(i, done) { + const input = /** @type {HTMLInputElement} */ ( + target.querySelectorAll('input[type="checkbox"]')[i] + ); + input.checked = done; + input.dispatchEvent(new window.Event('change')); + } + + component.filter = 'remaining'; + + assert.htmlEqual( + target.innerHTML, + ` +
+ +

one

+
+
+ +

three

+
+ +

remaining:one / done:two / remaining:three

+ ` + ); + + set_text(1, 'four'); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+ +

one

+
+
+ +

four

+
+ +

remaining:one / done:two / remaining:four

+ ` + ); + + assert.deepEqual(component.items, [ + { done: false, text: 'one' }, + { done: true, text: 'two' }, + { done: false, text: 'four' } + ]); + + set_done(0, true); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+ +

four

+
+ +

done:one / done:two / remaining:four

+ ` + ); + + assert.deepEqual(component.items, [ + { done: true, text: 'one' }, + { done: true, text: 'two' }, + { done: false, text: 'four' } + ]); + + component.filter = 'done'; + + assert.htmlEqual( + target.innerHTML, + ` +
+ +

one

+
+
+ +

two

+
+ +

done:one / done:two / remaining:four

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-text-contextual-reactive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual-reactive/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-text-contextual-reactive/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual-reactive/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual/_config.js new file mode 100644 index 000000000000..9922ce1c7886 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual/_config.js @@ -0,0 +1,79 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { items: ['one', 'two', 'three'] }; + }, + + html: ` +
+

one

+
+
+

two

+
+
+

three

+
+ `, + + ssrHtml: ` +
+

one

+
+
+

two

+
+
+

three

+
+ `, + + test({ assert, component, target, window }) { + const inputs = [...target.querySelectorAll('input')]; + const items = component.items; + const event = new window.Event('input'); + + assert.equal(inputs[0].value, 'one'); + + inputs[1].value = 'four'; + inputs[1].dispatchEvent(event); + flushSync(); + + assert.equal(items[1], 'four'); + assert.htmlEqual( + target.innerHTML, + ` +
+

one

+
+
+

four

+
+
+

three

+
+ ` + ); + + items[2] = 'five'; + + component.items = items; + assert.equal(inputs[2].value, 'five'); + assert.htmlEqual( + target.innerHTML, + ` +
+

one

+
+
+

four

+
+
+

five

+
+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-text-contextual/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-text-contextual/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-text-contextual/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deconflicted/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deconflicted/_config.js new file mode 100644 index 000000000000..43e0eec907d6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deconflicted/_config.js @@ -0,0 +1,49 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { component: { name: 'world' } }; + }, + + html: ` +

Hello world!

+ + `, + + ssrHtml: ` +

Hello world!

+ + `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + assert.equal(input.value, 'world'); + + const event = new window.Event('input'); + + input.value = 'everybody'; + input.dispatchEvent(event); + flushSync(); + + assert.equal(input.value, 'everybody'); + assert.htmlEqual( + target.innerHTML, + ` +

Hello everybody!

+ + ` + ); + + component.component = { name: 'goodbye' }; + assert.equal(input.value, 'goodbye'); + assert.htmlEqual( + target.innerHTML, + ` +

Hello goodbye!

+ + ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-text-deconflicted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deconflicted/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-text-deconflicted/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-text-deconflicted/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-computed-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-computed-dynamic/_config.js new file mode 100644 index 000000000000..77089cd01d47 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-computed-dynamic/_config.js @@ -0,0 +1,74 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { + prop: 'bar', + obj: { foo: 'a', bar: 'b', baz: 'c' } + }; + }, + + html: ` + +
{"foo":"a","bar":"b","baz":"c"}
+ `, + + ssrHtml: ` + +
{"foo":"a","bar":"b","baz":"c"}
+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + const event = new window.Event('input'); + + assert.equal(input.value, 'b'); + + // edit bar + input.value = 'e'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +
{"foo":"a","bar":"e","baz":"c"}
+ ` + ); + + // edit baz + component.prop = 'baz'; + assert.equal(input.value, 'c'); + + input.value = 'f'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +
{"foo":"a","bar":"e","baz":"f"}
+ ` + ); + + // edit foo + component.prop = 'foo'; + assert.equal(input.value, 'a'); + + input.value = 'd'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +
{"foo":"d","bar":"e","baz":"f"}
+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-text-deep-computed-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-computed-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-text-deep-computed-dynamic/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-computed-dynamic/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-computed/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-computed/_config.js new file mode 100644 index 000000000000..188b3360b56e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-computed/_config.js @@ -0,0 +1,52 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { prop: 'name', user: { name: 'alice' } }; + }, + + html: ` + +

hello alice

+ `, + + ssrHtml: ` + +

hello alice

+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + + assert.equal(input.value, 'alice'); + + const event = new window.Event('input'); + + input.value = 'bob'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

hello bob

+ ` + ); + + const user = component.user; + user.name = 'carol'; + + component.user = user; + assert.equal(input.value, 'carol'); + assert.htmlEqual( + target.innerHTML, + ` + +

hello carol

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-text-deep-computed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-computed/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-text-deep-computed/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-computed/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-contextual-computed-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-contextual-computed-dynamic/_config.js new file mode 100644 index 000000000000..51e4e12f5f71 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-contextual-computed-dynamic/_config.js @@ -0,0 +1,74 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { + prop: 'bar', + objects: [{ foo: 'a', bar: 'b', baz: 'c' }] + }; + }, + + html: ` + +
{"foo":"a","bar":"b","baz":"c"}
+ `, + + ssrHtml: ` + +
{"foo":"a","bar":"b","baz":"c"}
+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + const event = new window.Event('input'); + + assert.equal(input.value, 'b'); + + // edit bar + input.value = 'e'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +
{"foo":"a","bar":"e","baz":"c"}
+ ` + ); + + // edit baz + component.prop = 'baz'; + assert.equal(input.value, 'c'); + + input.value = 'f'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +
{"foo":"a","bar":"e","baz":"f"}
+ ` + ); + + // edit foo + component.prop = 'foo'; + assert.equal(input.value, 'a'); + + input.value = 'd'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +
{"foo":"d","bar":"e","baz":"f"}
+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-text-deep-contextual-computed-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-contextual-computed-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-text-deep-contextual-computed-dynamic/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-contextual-computed-dynamic/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-contextual/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-contextual/_config.js new file mode 100644 index 000000000000..fad359625a64 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-contextual/_config.js @@ -0,0 +1,57 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { + items: [{ description: 'one' }, { description: 'two' }, { description: 'three' }] + }; + }, + + html: ` +

one

+

two

+

three

+ `, + + ssrHtml: ` +

one

+

two

+

three

+ `, + + test({ assert, component, target, window }) { + const inputs = [...target.querySelectorAll('input')]; + + assert.equal(inputs[0].value, 'one'); + + const event = new window.Event('input', { bubbles: true }); + + inputs[1].value = 'four'; + inputs[1].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

one

+

four

+

three

+ ` + ); + + const items = component.items; + items[2].description = 'five'; + + component.items = items; + assert.equal(inputs[2].value, 'five'); + assert.htmlEqual( + target.innerHTML, + ` +

one

+

four

+

five

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-text-deep-contextual/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-contextual/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-text-deep-contextual/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep-contextual/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep/_config.js new file mode 100644 index 000000000000..8a4dfc0f78a5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep/_config.js @@ -0,0 +1,52 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { user: { name: 'alice' } }; + }, + + html: ` + +

hello alice

+ `, + + ssrHtml: ` + +

hello alice

+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + + assert.equal(input.value, 'alice'); + + const event = new window.Event('input'); + + input.value = 'bob'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

hello bob

+ ` + ); + + const user = component.user; + user.name = 'carol'; + + component.user = user; + assert.equal(input.value, 'carol'); + assert.htmlEqual( + target.innerHTML, + ` + +

hello carol

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-text-deep/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-text-deep/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-text-deep/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-undefined/_config.js new file mode 100644 index 000000000000..f921a061ddf0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-undefined/_config.js @@ -0,0 +1,33 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + ssrHtml: ` + + `, + + async test({ assert, component, target }) { + const input = target.querySelector('input'); + ok(input); + assert.equal(input.value, ''); + + component.x = null; + assert.equal(input.value, ''); + + component.x = undefined; + assert.equal(input.value, ''); + + component.x = 'string'; + component.x = undefined; + assert.equal(input.value, ''); + + component.x = 0; + assert.equal(input.value, '0'); + + component.x = undefined; + assert.equal(input.value, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-undefined/main.svelte new file mode 100644 index 000000000000..b4c2a84fd21a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text-undefined/main.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-text/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-text/_config.js new file mode 100644 index 000000000000..f59b6d4f1ca8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-text/_config.js @@ -0,0 +1,48 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { name: 'world' }; + }, + + html: ` + +

hello world

+ `, + + ssrHtml: ` + +

hello world

+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + assert.equal(input.value, 'world'); + + const event = new window.Event('input'); + + input.value = 'everybody'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

hello everybody

+ ` + ); + + component.name = 'goodbye'; + assert.equal(input.value, 'goodbye'); + assert.htmlEqual( + target.innerHTML, + ` + +

hello goodbye

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-input-text/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-text/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-text/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-text/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-input-with-event/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-input-with-event/_config.js new file mode 100644 index 000000000000..e926d87ffe5f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-input-with-event/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { a: 42 }; + }, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + assert.equal(input.value, '42'); + + const event = new window.Event('input'); + + input.value = '43'; + input.dispatchEvent(event); + + assert.equal(input.value, '43'); + assert.equal(component.a, 43); + } +}); diff --git a/test/runtime/samples/binding-input-with-event/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-input-with-event/main.svelte similarity index 100% rename from test/runtime/samples/binding-input-with-event/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-input-with-event/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-member-expression-no-warning/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-member-expression-no-warning/_config.js new file mode 100644 index 000000000000..e99efacba85a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-member-expression-no-warning/_config.js @@ -0,0 +1,23 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + test({ assert, target, window }) { + assert.htmlEqual(target.innerHTML, `

hello

`); + + const input = target.querySelector('input'); + ok(input); + + input.value = 'goodbye'; + input.dispatchEvent(new window.Event('input')); + + flushSync(); + assert.htmlEqual(target.innerHTML, `

goodbye

`); + }, + + warnings: [] +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-member-expression-no-warning/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-member-expression-no-warning/main.svelte new file mode 100644 index 000000000000..52773094020a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-member-expression-no-warning/main.svelte @@ -0,0 +1,6 @@ + + + +

{object.value}

diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-no-unnecessary-invalidation/Tab.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-no-unnecessary-invalidation/Tab.svelte new file mode 100644 index 000000000000..86e2413898a9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-no-unnecessary-invalidation/Tab.svelte @@ -0,0 +1,3 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-no-unnecessary-invalidation/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-no-unnecessary-invalidation/_config.js new file mode 100644 index 000000000000..f11ba21fc625 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-no-unnecessary-invalidation/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + assert.htmlEqual( + target.innerHTML, + ` +

0

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-no-unnecessary-invalidation/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-no-unnecessary-invalidation/main.svelte new file mode 100644 index 000000000000..c57781cc9772 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-no-unnecessary-invalidation/main.svelte @@ -0,0 +1,17 @@ + + + +

{i}

diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/Parent.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/Parent.svelte new file mode 100644 index 000000000000..565c3bc6b74b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/Parent.svelte @@ -0,0 +1,6 @@ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/_config.js new file mode 100644 index 000000000000..60c22ebfc7b7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; + +export default test({ + html: ` + +

1

+ `, + + async test({ assert, component, target, window }) { + const select = target.querySelector('select'); + const options = target.querySelectorAll('option'); + + assert.equal(component.tasks_touched, 1); + + const change = new window.Event('change'); + options[1].selected = true; + // @ts-ignore + await select.dispatchEvent(change); + + assert.equal(component.selected, options[1].value); + assert.equal(component.tasks_touched, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/main.svelte new file mode 100644 index 000000000000..3c21eba82934 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let-2/main.svelte @@ -0,0 +1,19 @@ + + + + + +

{tasks_touched}

diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/Parent.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/Parent.svelte new file mode 100644 index 000000000000..565c3bc6b74b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/Parent.svelte @@ -0,0 +1,6 @@ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/_config.js new file mode 100644 index 000000000000..20806b3eeb14 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, component, target, window }) { + const select = target.querySelector('select'); + const options = target.querySelectorAll('option'); + + const change = new window.Event('change'); + options[1].selected = true; + // @ts-ignore + await select.dispatchEvent(change); + + assert.equal(component.selected, options[1].value); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/main.svelte new file mode 100644 index 000000000000..494653bb4cf4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-from-let/main.svelte @@ -0,0 +1,12 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-implicit-option-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-implicit-option-value/_config.js new file mode 100644 index 000000000000..1fea6c08f4f6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-implicit-option-value/_config.js @@ -0,0 +1,47 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { values: [1, 2, 3], foo: 2 }; + }, + + html: ` + + +

foo: 2

+ `, + + test({ assert, component, target, window }) { + const select = target.querySelector('select'); + ok(select); + const options = [...target.querySelectorAll('option')]; + + assert.ok(options[1].selected); + assert.equal(component.foo, 2); + + const change = new window.Event('change'); + + options[2].selected = true; + select.dispatchEvent(change); + flushSync(); + + assert.equal(component.foo, 3); + assert.htmlEqual( + target.innerHTML, + ` + + +

foo: 3

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-select-implicit-option-value/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-implicit-option-value/main.svelte similarity index 100% rename from test/runtime/samples/binding-select-implicit-option-value/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-select-implicit-option-value/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-in-each-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-in-each-block/_config.js new file mode 100644 index 000000000000..9c442aa329a9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-in-each-block/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + + `, + + get props() { + return { + items: [{ value: 'hullo' }, { value: 'world' }] + }; + }, + + test({ assert, component, target, window }) { + const selects = [...target.querySelectorAll('select')]; + + const change = new window.Event('change'); + + selects[1].options[0].selected = true; + selects[1].dispatchEvent(change); + + assert.deepEqual(component.items, [{ value: 'hullo' }, { value: 'hullo' }]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-in-each-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-in-each-block/main.svelte new file mode 100644 index 000000000000..f9d771a8da91 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-in-each-block/main.svelte @@ -0,0 +1,9 @@ + +{#each items as item} + +{/each} \ No newline at end of file diff --git a/test/runtime/samples/binding-select-in-yield/Modal.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/Modal.svelte similarity index 100% rename from test/runtime/samples/binding-select-in-yield/Modal.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/Modal.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/_config.js new file mode 100644 index 000000000000..b8f6a9a74a96 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/_config.js @@ -0,0 +1,80 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: '', + + get props() { + return { letter: 'b' }; + }, + + test({ assert, component, target, window }) { + component.modal.toggle(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + b + + + ` + ); + + let select = target.querySelector('select'); + ok(select); + const change = new window.MouseEvent('change'); + + select.options[2].selected = true; + select.dispatchEvent(change); + flushSync(); + assert.equal(component.letter, 'c'); + + assert.deepEqual( + Array.from(select.options).map((o) => o.selected), + [false, false, true] + ); + + assert.htmlEqual( + target.innerHTML, + ` + c + + + ` + ); + + component.modal.toggle(); + component.modal.toggle(); + flushSync(); + + select = target.querySelector('select'); + ok(select); + + assert.deepEqual( + Array.from(select.options).map((o) => o.selected), + [false, false, true] + ); + + assert.htmlEqual( + target.innerHTML, + ` + c + + + ` + ); + } +}); diff --git a/test/runtime/samples/binding-select-in-yield/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/main.svelte similarity index 100% rename from test/runtime/samples/binding-select-in-yield/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-select-in-yield/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-2/_config.js new file mode 100644 index 000000000000..cb5d26b913f4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-2/_config.js @@ -0,0 +1,28 @@ +import { ok, test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + + html: ` +

selected: b

+ + + +

selected: b

+ `, + + test({ assert, component, target }) { + assert.equal(component.selected, 'b'); + const select = target.querySelector('select'); + ok(select); + const options = [...target.querySelectorAll('option')]; + + // option with selected attribute should be selected + assert.equal(select.value, 'b'); + assert.ok(options[1].selected); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-2/main.svelte new file mode 100644 index 000000000000..0640a9ce2712 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-2/main.svelte @@ -0,0 +1,13 @@ + + +

selected: {selected}

+ + + +

selected: {selected}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-3/_config.js new file mode 100644 index 000000000000..9b25c0bc5883 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-3/_config.js @@ -0,0 +1,27 @@ +import { ok, test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + + html: ` +

selected: a

+ + + `, + + test({ assert, component, target }) { + assert.equal(component.selected, 'a'); + const select = target.querySelector('select'); + ok(select); + const options = [...target.querySelectorAll('option')]; + + // first enabled option should be selected + assert.equal(select.value, 'a'); + assert.ok(options[1].selected); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-3/main.svelte new file mode 100644 index 000000000000..0e2c268631ff --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined-3/main.svelte @@ -0,0 +1,12 @@ + + +

selected: {selected}

+ + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined/_config.js new file mode 100644 index 000000000000..48659c4527e0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined/_config.js @@ -0,0 +1,29 @@ +import { ok, test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + + html: ` +

selected: a

+ + + +

selected: a

+ `, + + test({ assert, component, target }) { + assert.equal(component.selected, 'a'); + const select = target.querySelector('select'); + ok(select); + const options = [...target.querySelectorAll('option')]; + + // first enabled option should be selected + assert.equal(select.value, 'a'); + assert.ok(options[1].selected); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined/main.svelte new file mode 100644 index 000000000000..8c3bd0258f11 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value-undefined/main.svelte @@ -0,0 +1,14 @@ + + +

selected: {selected}

+ + + +

selected: {selected}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value/_config.js new file mode 100644 index 000000000000..176a1e0dfc06 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value/_config.js @@ -0,0 +1,28 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

selected: b

+ + + +

selected: b

+ `, + + get props() { + return { selected: 'b' }; + }, + + test({ assert, target }) { + const select = target.querySelector('select'); + ok(select); + const options = [...target.querySelectorAll('option')]; + + assert.equal(select.value, 'b'); + assert.ok(options[1].selected); + } +}); diff --git a/test/runtime/samples/binding-select-initial-value-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value/main.svelte similarity index 100% rename from test/runtime/samples/binding-select-initial-value-undefined/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-select-initial-value/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-late-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-2/_config.js new file mode 100644 index 000000000000..ab2db4b07da4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-2/_config.js @@ -0,0 +1,39 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {string[]} */ + items: [], + selected: 'two' + }; + }, + + html: ` + +

selected: two

+ `, + + async test({ assert, component, target }) { + component.items = ['one', 'two', 'three']; + + await Promise.resolve(); // mutation observer + + const options = target.querySelectorAll('option'); + assert.ok(!options[0].selected); + assert.ok(options[1].selected); + assert.ok(!options[2].selected); + + assert.htmlEqual( + target.innerHTML, + ` + +

selected: two

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-select-late/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-2/main.svelte similarity index 100% rename from test/runtime/samples/binding-select-late/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-select-late-2/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-late-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-3/_config.js new file mode 100644 index 000000000000..234c2a104000 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-3/_config.js @@ -0,0 +1,39 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {string[]} */ + items: [], + selected: 'two' + }; + }, + + html: ` + +

selected: two

+ `, + + async test({ assert, component, target }) { + component.items = ['one', 'two', 'three']; + + await Promise.resolve(); // mutation observer + + const options = target.querySelectorAll('option'); + assert.ok(!options[0].selected); + assert.ok(options[1].selected); + assert.ok(!options[2].selected); + + assert.htmlEqual( + target.innerHTML, + ` + +

selected: two

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-late-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-3/main.svelte new file mode 100644 index 000000000000..ec9ac8d34511 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-3/main.svelte @@ -0,0 +1,12 @@ + + + + +

selected: {selected || 'nothing'}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/_config.js new file mode 100644 index 000000000000..9893a7c71627 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + await new Promise((r) => setTimeout(r, 200)); // wait for await block to resolve + + const options = target.querySelectorAll('option'); + assert.ok(!options[0].selected); + assert.ok(options[1].selected); + assert.ok(!options[2].selected); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/main.svelte new file mode 100644 index 000000000000..7702927e5b8b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-late-4/main.svelte @@ -0,0 +1,19 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-late/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-late/_config.js new file mode 100644 index 000000000000..9c3cd8765a4a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-late/_config.js @@ -0,0 +1,39 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {string[]} */ + items: [], + /** @type {string | null} */ + selected: null + }; + }, + + html: ` + +

selected: nothing

+ `, + + test({ assert, component, target }) { + component.items = ['one', 'two', 'three']; + component.selected = 'two'; + + const options = target.querySelectorAll('option'); + assert.ok(!options[0].selected); + assert.ok(options[1].selected); + assert.ok(!options[2].selected); + + assert.htmlEqual( + target.innerHTML, + ` + +

selected: two

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-late/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-late/main.svelte new file mode 100644 index 000000000000..52cc14528ae6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-late/main.svelte @@ -0,0 +1,12 @@ + + + + +

selected: {selected || 'nothing'}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-multiple/_config.js new file mode 100644 index 000000000000..42c0e018e516 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-multiple/_config.js @@ -0,0 +1,81 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { selected: ['two', 'three'] }; + }, + + html: ` + + +

selected: two, three

+ `, + + test({ assert, component, target, window }) { + const select = target.querySelector('select'); + ok(select); + const options = [...target.querySelectorAll('option')]; + + const change = new window.Event('change'); + + options[1].selected = false; + select.dispatchEvent(change); + flushSync(); + + assert.deepEqual(component.selected, ['three']); + assert.htmlEqual( + target.innerHTML, + ` + + +

selected: three

+ ` + ); + + options[0].selected = true; + select.dispatchEvent(change); + flushSync(); + + assert.deepEqual(component.selected, ['one', 'three']); + assert.htmlEqual( + target.innerHTML, + ` + + +

selected: one, three

+ ` + ); + + component.selected = ['one', 'two']; + + assert.ok(options[0].selected); + assert.ok(options[1].selected); + assert.ok(!options[2].selected); + + assert.htmlEqual( + target.innerHTML, + ` + + +

selected: one, two

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-select-multiple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-multiple/main.svelte similarity index 100% rename from test/runtime/samples/binding-select-multiple/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-select-multiple/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder-2/_config.js new file mode 100644 index 000000000000..70a17d5cf920 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder-2/_config.js @@ -0,0 +1,34 @@ +import { ok, test } from '../../test'; + +const items = [{ id: 'a' }, { id: 'b' }]; + +export default test({ + get props() { + return { + /** @type {{ id: string } | null} */ + foo: null, + items + }; + }, + + test({ assert, component, target }) { + const select = target.querySelector('select'); + ok(select); + + const options = target.querySelectorAll('option'); + + assert.equal(options[0].selected, true); + assert.equal(options[1].selected, false); + assert.equal(options[0].value, ''); + + component.foo = component.items[0]; + assert.equal(options[0].selected, false); + assert.equal(options[1].selected, true); + + component.foo = { id: 'c' }; // doesn't match an option + assert.equal(select.value, ''); + assert.equal(select.selectedIndex, -1); + assert.equal(options[0].selected, false); + assert.equal(options[1].selected, false); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder-2/main.svelte new file mode 100644 index 000000000000..56219ef28442 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder-2/main.svelte @@ -0,0 +1,11 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder/_config.js new file mode 100644 index 000000000000..955014cf9e04 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder/_config.js @@ -0,0 +1,35 @@ +import { ok, test } from '../../test'; + +const items = [{ id: 'a' }, { id: 'b' }]; + +export default test({ + get props() { + return { + /** @type {{ id: string } | null} */ + foo: null, + items + }; + }, + + test({ assert, component, target }) { + const select = target.querySelector('select'); + ok(select); + + const options = target.querySelectorAll('option'); + + assert.equal(options[0].selected, true); + assert.equal(options[0].disabled, true); + assert.equal(options[1].selected, false); + assert.equal(options[1].disabled, false); + + // placeholder option value must be blank string for native required field validation + assert.equal(options[0].value, ''); + assert.equal(select.checkValidity(), false); + + component.foo = component.items[0]; + + assert.equal(options[0].selected, false); + assert.equal(options[1].selected, true); + assert.equal(select.checkValidity(), true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder/main.svelte new file mode 100644 index 000000000000..65cab994957c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-null-placeholder/main.svelte @@ -0,0 +1,11 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-optgroup/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-optgroup/_config.js new file mode 100644 index 000000000000..d9544b7c4d55 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-optgroup/_config.js @@ -0,0 +1,57 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + ssrHtml: ` +

Hello !

+ + + `, + + html: ` +

Hello Harry!

+ + + `, + + test({ assert, component, target, window }) { + const select = target.querySelector('select'); + ok(select); + + const options = [...target.querySelectorAll('option')]; + + assert.deepEqual(options, [...select.options]); + assert.equal(component.name, 'Harry'); + + const change = new window.Event('change'); + + options[1].selected = true; + select.dispatchEvent(change); + flushSync(); + + assert.equal(component.name, 'World'); + assert.htmlEqual( + target.innerHTML, + ` +

Hello World!

+ + + ` + ); + } +}); diff --git a/test/runtime/samples/binding-select-optgroup/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-optgroup/main.svelte similarity index 100% rename from test/runtime/samples/binding-select-optgroup/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-select-optgroup/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-2/_config.js new file mode 100644 index 000000000000..85d61eeeec8f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-2/_config.js @@ -0,0 +1,112 @@ +import { ok, test } from '../../test'; + +// // same test as the previous one, but with a dynamic each block +export default test({ + html: ` +

selected:

+ + + +

selected:

+ `, + + async test({ assert, component, target }) { + const select = target.querySelector('select'); + ok(select); + + const options = [...target.querySelectorAll('option')]; + + assert.equal(component.selected, null); + + // no option should be selected since none of the options matches the bound value + assert.equal(select.value, ''); + assert.equal(select.selectedIndex, -1); + assert.ok(!options[0].selected); + + component.selected = 'a'; // first option should now be selected + assert.equal(select.value, 'a'); + assert.ok(options[0].selected); + + assert.htmlEqual( + target.innerHTML, + ` +

selected: a

+ + + +

selected: a

+ ` + ); + + component.selected = 'd'; // doesn't match an option + + // now no option should be selected again + assert.equal(select.value, ''); + assert.equal(select.selectedIndex, -1); + assert.ok(!options[0].selected); + + assert.htmlEqual( + target.innerHTML, + ` +

selected: d

+ + + +

selected: d

+ ` + ); + + component.selected = 'b'; // second option should now be selected + assert.equal(select.value, 'b'); + assert.ok(options[1].selected); + + assert.htmlEqual( + target.innerHTML, + ` +

selected: b

+ + + +

selected: b

+ ` + ); + + component.selected = undefined; // also doesn't match an option + + // now no option should be selected again + assert.equal(select.value, ''); + assert.equal(select.selectedIndex, -1); + assert.ok(!options[0].selected); + + assert.htmlEqual( + target.innerHTML, + ` +

selected:

+ + + +

selected:

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-2/main.svelte new file mode 100644 index 000000000000..8acdb5ddaeb0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-2/main.svelte @@ -0,0 +1,14 @@ + + +

selected: {selected}

+ + + +

selected: {selected}

diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-3/_config.js new file mode 100644 index 000000000000..c0e64521d10f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-3/_config.js @@ -0,0 +1,35 @@ +import { ok, test } from '../../test'; + +// test select binding behavior when a selected option is removed +export default test({ + mode: ['client', 'hydrate'], + + html: `

selected: a

`, + + async test({ assert, component, target }) { + const select = target.querySelector('select'); + ok(select); + const options = target.querySelectorAll('option'); + + // first option should be selected by default since no value was bound + assert.equal(component.selected, 'a'); + assert.equal(select.value, 'a'); + assert.ok(options[0].selected); + + // remove the selected item, so the bound value no longer matches anything + component.items = ['b', 'c']; + + // There's a MutationObserver + await Promise.resolve(); + + // now no option should be selected + assert.equal(select.value, ''); + assert.equal(select.selectedIndex, -1); + + // model of selected value should be kept around, even if it is not in the list + assert.htmlEqual( + target.innerHTML, + `

selected: a

` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-3/main.svelte new file mode 100644 index 000000000000..9cc18fa83b20 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched-3/main.svelte @@ -0,0 +1,12 @@ + + +

selected: {selected}

+ + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched/_config.js new file mode 100644 index 000000000000..0c19ed0020b7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched/_config.js @@ -0,0 +1,111 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

selected:

+ + + +

selected:

+ `, + + async test({ assert, component, target }) { + const select = target.querySelector('select'); + ok(select); + + const options = [...target.querySelectorAll('option')]; + + assert.equal(component.selected, null); + + // no option should be selected since none of the options matches the bound value + assert.equal(select.value, ''); + assert.equal(select.selectedIndex, -1); + assert.ok(!options[0].selected); + + component.selected = 'a'; // first option should now be selected + assert.equal(select.value, 'a'); + assert.ok(options[0].selected); + + assert.htmlEqual( + target.innerHTML, + ` +

selected: a

+ + + +

selected: a

+ ` + ); + + component.selected = 'd'; // doesn't match an option + + // now no option should be selected again + assert.equal(select.value, ''); + assert.equal(select.selectedIndex, -1); + assert.ok(!options[0].selected); + + assert.htmlEqual( + target.innerHTML, + ` +

selected: d

+ + + +

selected: d

+ ` + ); + + component.selected = 'b'; // second option should now be selected + assert.equal(select.value, 'b'); + assert.ok(options[1].selected); + + assert.htmlEqual( + target.innerHTML, + ` +

selected: b

+ + + +

selected: b

+ ` + ); + + component.selected = undefined; // also doesn't match an option + + // now no option should be selected again + assert.equal(select.value, ''); + assert.equal(select.selectedIndex, -1); + assert.ok(!options[0].selected); + + assert.htmlEqual( + target.innerHTML, + ` +

selected:

+ + + +

selected:

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched/main.svelte new file mode 100644 index 000000000000..20e13f47659d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select-unmatched/main.svelte @@ -0,0 +1,14 @@ + + +

selected: {selected}

+ + + +

selected: {selected}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-select/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-select/_config.js new file mode 100644 index 000000000000..5577ec239326 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-select/_config.js @@ -0,0 +1,54 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` +

selected: one

+ + + +

selected: one

+ `, + + get props() { + return { selected: 'one' }; + }, + + test({ assert, component, target, window }) { + const select = target.querySelector('select'); + ok(select); + + const options = [...target.querySelectorAll('option')]; + + assert.deepEqual(options, [...select.options]); + assert.equal(component.selected, 'one'); + + const change = new window.Event('change'); + + options[1].selected = true; + select.dispatchEvent(change); + flushSync(); + + assert.equal(component.selected, 'two'); + assert.htmlEqual( + target.innerHTML, + ` +

selected: two

+ + + +

selected: two

+ ` + ); + + component.selected = 'three'; + } +}); diff --git a/test/runtime/samples/binding-select/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-select/main.svelte similarity index 100% rename from test/runtime/samples/binding-select/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-select/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-store-deep/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-store-deep/_config.js new file mode 100644 index 000000000000..4854d6dec653 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-store-deep/_config.js @@ -0,0 +1,59 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

hello world

+ `, + + ssrHtml: ` + +

hello world

+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + + assert.equal(input.value, 'world'); + + const event = new window.Event('input'); + + /** @type {string[]} */ + const names = []; + + // @ts-ignore + const unsubscribe = component.user.subscribe((user) => { + if (!names.includes(user.name)) { + names.push(user.name); + } + }); + + input.value = 'everybody'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

hello everybody

+ ` + ); + + component.user.set({ name: 'goodbye' }); + flushSync(); + assert.equal(input.value, 'goodbye'); + assert.htmlEqual( + target.innerHTML, + ` + +

hello goodbye

+ ` + ); + + assert.deepEqual(names, ['world', 'everybody', 'goodbye']); + unsubscribe(); + } +}); diff --git a/test/runtime/samples/binding-store-deep/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-store-deep/main.svelte similarity index 100% rename from test/runtime/samples/binding-store-deep/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-store-deep/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-store-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-store-each/_config.js new file mode 100644 index 000000000000..d2df354ea69b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-store-each/_config.js @@ -0,0 +1,31 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + html: ` + + + + 0 + `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + input.checked = true; + input.dispatchEvent(new window.Event('change', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + + 1 + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-store-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-store-each/main.svelte new file mode 100644 index 000000000000..e15cc3f6fff0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-store-each/main.svelte @@ -0,0 +1,12 @@ + + +{#each $checks as checked} + +{/each} + +{$countChecked} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-store/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-store/_config.js new file mode 100644 index 000000000000..a8ab3430023a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-store/_config.js @@ -0,0 +1,64 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

hello world

+ +
world
+ `, + + ssrHtml: ` + +

hello world

+ +
world
+ `, + + test({ assert, component, target, window }) { + const input = target.querySelector('input'); + ok(input); + assert.equal(input.value, 'world'); + + const event = new window.Event('input'); + + /** @type {string[]} */ + const names = []; + + // @ts-ignore + const unsubscribe = component.name.subscribe((name) => { + names.push(name); + }); + + input.value = 'everybody'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

hello everybody

+ +
everybody
+ ` + ); + + component.name.set('goodbye'); + flushSync(); + assert.equal(input.value, 'goodbye'); + assert.htmlEqual( + target.innerHTML, + ` + +

hello goodbye

+ +
goodbye
+ ` + ); + + assert.deepEqual(names, ['world', 'everybody', 'goodbye']); + unsubscribe(); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-store/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-store/main.svelte new file mode 100644 index 000000000000..2bcf939af5d5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-store/main.svelte @@ -0,0 +1,11 @@ + + + +

hello {$name}

+ +

some text

+ `, + + ssrHtml: ` + +

some text

+ `, + + test({ assert, component, target, window }) { + const textarea = target.querySelector('textarea'); + ok(textarea); + assert.equal(textarea.value, 'some text'); + + const event = new window.Event('input'); + + textarea.value = 'hello'; + textarea.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

hello

+ ` + ); + + component.value = 'goodbye'; + assert.equal(textarea.value, 'goodbye'); + assert.htmlEqual( + target.innerHTML, + ` + +

goodbye

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-textarea/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-textarea/main.svelte similarity index 100% rename from test/runtime/samples/binding-textarea/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-textarea/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-and-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-and-value/_config.js new file mode 100644 index 000000000000..6bffe1b4697d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-and-value/_config.js @@ -0,0 +1,32 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

value: initial

+ `, + + ssrHtml: ` + +

value: initial

+ `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + const event = new window.Event('input'); + + input.value = 'changed'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

value: changed

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-this-and-value/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-and-value/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-and-value/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-and-value/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/Foo.svelte new file mode 100644 index 000000000000..2f647b83ddda --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/Foo.svelte @@ -0,0 +1,4 @@ + +
foo
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/_config.js new file mode 100644 index 000000000000..ff7d99e2e4f7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode + + html: ` +
foo
+
has foo: true
+ ` +}); diff --git a/test/runtime/samples/binding-this-component-computed-key/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-component-computed-key/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-component-computed-key/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/Foo.svelte new file mode 100644 index 000000000000..4246268767df --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/Foo.svelte @@ -0,0 +1,5 @@ + + +
foo
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/_config.js new file mode 100644 index 000000000000..7e624e3a2fec --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode + html: ` +
foo
+
first has foo: true
+
foo
+
second has foo: true
+
foo
+
third has foo: true
+ ` +}); diff --git a/test/runtime/samples/binding-this-component-each-block-value/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-component-each-block-value/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block-value/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/Foo.svelte new file mode 100644 index 000000000000..4246268767df --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/Foo.svelte @@ -0,0 +1,5 @@ + + +
foo
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/_config.js new file mode 100644 index 000000000000..1f42696432e4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode + + html: ` +
foo
+
0 has foo: true
+
foo
+
1 has foo: true
+
foo
+
2 has foo: true
+ ` +}); diff --git a/test/runtime/samples/binding-this-component-each-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-component-each-block/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-component-each-block/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/Foo.svelte new file mode 100644 index 000000000000..4246268767df --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/Foo.svelte @@ -0,0 +1,5 @@ + + +
foo
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/_config.js new file mode 100644 index 000000000000..ff7d99e2e4f7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode + + html: ` +
foo
+
has foo: true
+ ` +}); diff --git a/test/runtime/samples/binding-this-component-reactive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-component-reactive/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-component-reactive/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-2/_config.js new file mode 100644 index 000000000000..9d2e07bbd249 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-2/_config.js @@ -0,0 +1,59 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +/** @type {Array>} */ +let calls = []; + +/** @param {Array<{ ref: HTMLElement }>} refs */ +function callback(refs) { + calls.push(refs.map(({ ref }) => ({ ref }))); +} +export default test({ + html: '', + get props() { + return { callback }; + }, + before_test() { + calls = []; + }, + test({ assert, component, target }) { + assert.equal(calls.length, 1); + assert.equal(calls[0].length, 0); + + flushSync(() => component.addItem()); + + let divs = target.querySelectorAll('div'); + + assert.equal(calls.length, 3); + assert.equal(calls[1].length, 1); + assert.equal(calls[1][0].ref, null); + assert.equal(calls[2].length, 1); + assert.equal(calls[2][0].ref, divs[0]); + + flushSync(() => component.addItem()); + + divs = target.querySelectorAll('div'); + + assert.equal(calls.length, 5); + assert.equal(calls[3].length, 2); + assert.equal(calls[3][0].ref, divs[0]); + assert.equal(calls[3][1].ref, null); + assert.equal(calls[4].length, 2); + assert.equal(calls[4][0].ref, divs[0]); + assert.equal(calls[4][1].ref, divs[1]); + + flushSync(() => component.addItem()); + + divs = target.querySelectorAll('div'); + + assert.equal(calls.length, 7); + assert.equal(calls[5].length, 3); + assert.equal(calls[5][0].ref, divs[0]); + assert.equal(calls[5][1].ref, divs[1]); + assert.equal(calls[5][2].ref, null); + assert.equal(calls[6].length, 3); + assert.equal(calls[6][0].ref, divs[0]); + assert.equal(calls[6][1].ref, divs[1]); + assert.equal(calls[6][2].ref, divs[2]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-2/main.svelte new file mode 100644 index 000000000000..7bf286c5ebbe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-2/main.svelte @@ -0,0 +1,17 @@ + + +{#each refs as xxx} +
+{/each} diff --git a/test/runtime/samples/binding-this-each-block-property-component/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-component/Foo.svelte similarity index 100% rename from test/runtime/samples/binding-this-each-block-property-component/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-component/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-component/_config.js new file mode 100644 index 000000000000..c82c3e55cc68 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-component/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + async test({ assert, component, target }) { + component.visible = true; + assert.htmlEqual( + target.innerHTML, + ` +

a

+ ` + ); + + assert.ok(component.items[0].ref.isFoo()); + } +}); diff --git a/test/runtime/samples/binding-this-each-block-property-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-component/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-each-block-property-component/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property-component/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property/_config.js new file mode 100644 index 000000000000..39d54dbd2d53 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + async test({ assert, component, target }) { + component.visible = true; + assert.htmlEqual( + target.innerHTML, + ` +
a
+ ` + ); + + assert.equal(component.items[0].ref, target.querySelector('div')); + } +}); diff --git a/test/runtime/samples/binding-this-each-block-property/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-each-block-property/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-each-block-property/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-each-key/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-key/_config.js new file mode 100644 index 000000000000..ae8601ed6a78 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-key/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + html: '
content 0 3 3
content 1 2 2
content 2 1 1
', + + test({ assert, target, component }) { + const divs = target.querySelectorAll('div'); + assert.equal(component.refs[0], divs[0]); + assert.equal(component.refs[1], divs[1]); + assert.equal(component.refs[2], divs[2]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-each-key/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-key/main.svelte new file mode 100644 index 000000000000..8ae4542e3a73 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-key/main.svelte @@ -0,0 +1,15 @@ + + +{#each list as { id }, index (id)} +
+ content {index} {id} {data[index].id} +
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-props/_config.js new file mode 100644 index 000000000000..1b5ff67f4867 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-props/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + async test({ assert, component, target }) { + component.visible = true; + assert.htmlEqual( + target.innerHTML, + ` +
b
b
c
c
+ ` + ); + assert.equal(component.items1[1], target.querySelector('div')); + assert.equal(component.items2[1], target.querySelector('div:nth-child(2)')); + assert.equal(component.items1[2], target.querySelector('div:nth-child(3)')); + assert.equal(component.items2[2], target.querySelector('div:last-child')); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-props/main.svelte new file mode 100644 index 000000000000..9654a5841818 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-props/main.svelte @@ -0,0 +1,13 @@ + + +{#each data as item (item.id)} +
{item.text}
+
{item.text}
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-spread/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-spread/_config.js new file mode 100644 index 000000000000..44b138fb7de2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-spread/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, component, target }) { + assert.htmlEqual( + target.innerHTML, + ` +
a
a
b
b
+ ` + ); + assert.equal(component.items1[1], target.querySelector('div')); + assert.equal(component.items2[1], target.querySelector('div:nth-child(2)')); + assert.equal(component.items1[2], target.querySelector('div:nth-child(3)')); + assert.equal(component.items2[2], target.querySelector('div:last-child')); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-spread/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-spread/main.svelte new file mode 100644 index 000000000000..7b998c340d65 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-each-object-spread/main.svelte @@ -0,0 +1,13 @@ + + +{#each data as {id, text} (id)} +
{text}
+
{text}
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive-b/_config.js new file mode 100644 index 000000000000..a10ea16843df --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive-b/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode + get props() { + return { visible: true }; + }, + + html: ` +
The text is hello
+

hello

+ `, + + async test({ assert, component, target }) { + component.visible = false; + assert.htmlEqual( + target.innerHTML, + ` +
The text is missing
+ ` + ); + + component.visible = true; + assert.htmlEqual( + target.innerHTML, + ` +
The text is hello
+

hello

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-this-element-reactive-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive-b/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-element-reactive-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive-b/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive/_config.js new file mode 100644 index 000000000000..151f389f673c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // there's no class instance to retrieve in SSR mode + + html: '
has div: true
' +}); diff --git a/test/runtime/samples/binding-this-element-reactive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-element-reactive/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-element-reactive/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-legacy-component-api/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-legacy-component-api/_config.js new file mode 100644 index 000000000000..c3ba2559302a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-legacy-component-api/_config.js @@ -0,0 +1,17 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + compileOptions: { + compatibility: { + componentApi: 4 + } + }, + html: '', + async test({ assert, target }) { + const button = target.querySelector('button'); + await button?.click(); + await tick(); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-legacy-component-api/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-legacy-component-api/main.svelte new file mode 100644 index 000000000000..f3f19f60f544 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-legacy-component-api/main.svelte @@ -0,0 +1,16 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-legacy-component-api/sub.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-legacy-component-api/sub.svelte new file mode 100644 index 000000000000..b1a6201a56dc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-legacy-component-api/sub.svelte @@ -0,0 +1,8 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-member-expression-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-member-expression-update/_config.js new file mode 100644 index 000000000000..c0c6ffa5e68a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-member-expression-update/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +// binding member expression shouldn't invalidate the property name +export default test({ + test({ assert, component, target }) { + const div = target.querySelector('div'); + assert.equal(div, component.container.a); + assert.deepEqual(component.logs.length, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-member-expression-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-member-expression-update/main.svelte new file mode 100644 index 000000000000..a35144b3ac82 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-member-expression-update/main.svelte @@ -0,0 +1,9 @@ + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-multiple/_config.js new file mode 100644 index 000000000000..88b0ff31e3b3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-multiple/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target, logs }) { + const [b1, b2, b3] = target.querySelectorAll('button'); + const first_h1 = target.querySelector('h1'); + + assert.deepEqual(logs, [undefined, first_h1]); + + flushSync(() => { + b3.click(); + }); + + const third_h1 = target.querySelector('h1'); + + assert.deepEqual(logs, [undefined, first_h1, third_h1]); + + flushSync(() => { + b1.click(); + }); + + assert.deepEqual(logs, [undefined, first_h1, third_h1, target.querySelector('h1')]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-multiple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-multiple/main.svelte new file mode 100644 index 000000000000..2fb062c2ee8c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-multiple/main.svelte @@ -0,0 +1,26 @@ + + +
+
+ + + +
+
+ {#if activeTab === 0} +

Tab 1

+ {/if} + {#if activeTab === 1} +

Tab 2

+ {/if} + {#if activeTab === 2} +

Tab 3

+ {/if} +
+ +
diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-no-innerhtml/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-no-innerhtml/_config.js new file mode 100644 index 000000000000..06127b157098 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-no-innerhtml/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: '
', + + test({ assert, component, target }) { + const canvas = target.querySelector('canvas'); + assert.equal(canvas, component.foo); + } +}); diff --git a/test/runtime/samples/binding-this-no-innerhtml/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-no-innerhtml/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-no-innerhtml/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-no-innerhtml/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-store/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-store/_config.js new file mode 100644 index 000000000000..db21b69d2f65 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-store/_config.js @@ -0,0 +1,6 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // doesn't work in SSR + html: '
object
' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-store/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-store/main.svelte new file mode 100644 index 000000000000..7958dfa2d817 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-store/main.svelte @@ -0,0 +1,6 @@ + + +
{typeof $foo}
diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-unset/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-unset/_config.js new file mode 100644 index 000000000000..7edea707a610 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-unset/_config.js @@ -0,0 +1,29 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { x: true }; + }, + + html: '', + + test({ assert, component, target }) { + let canvas = target.querySelector('canvas'); + ok(canvas); + + assert.equal(canvas, component.foo); + assert.equal(canvas.getAttribute('data-x'), 'true'); + + component.x = false; + canvas = target.querySelector('canvas'); + ok(canvas); + assert.equal(canvas, component.foo); + assert.equal(canvas.getAttribute('data-x'), 'false'); + + component.x = true; + canvas = target.querySelector('canvas'); + ok(canvas); + assert.equal(canvas, component.foo); + assert.equal(canvas.getAttribute('data-x'), 'true'); + } +}); diff --git a/test/runtime/samples/binding-this-unset/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-unset/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-unset/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-unset/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this-with-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this-with-context/_config.js new file mode 100644 index 000000000000..1688d1526015 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this-with-context/_config.js @@ -0,0 +1,77 @@ +import { test } from '../../test'; + +export default test({ + html: `
foo
bar
baz
+ foobarbaz +
  • foo

  • bar

  • baz

+



`, + + test({ assert, component, target }) { + let divs = target.querySelectorAll('div'); + assert.equal(component.divs.length, 3, 'three divs are registered (unkeyed array)'); + // @ts-ignore + component.divs.forEach((e, i) => { + assert.equal(e, divs[i], `div ${i} is correct (unkeyed array)`); + }); + + let spans = target.querySelectorAll('span'); + assert.equal( + Object.keys(component.spans).length, + 3, + 'three spans are registered (unkeyed object)' + ); + // @ts-ignore + component.items.forEach((e, i) => { + assert.equal( + component.spans[`-${e}${i}`], + spans[i], + `span -${e}${i} is correct (unkeyed object)` + ); + }); + + let ps = target.querySelectorAll('p'); + assert.equal(component.ps.length, 3, 'three ps are registered (keyed array)'); + // @ts-ignore + component.ps.forEach((e, i) => { + assert.equal(e, ps[i], `p ${i} is correct (keyed array)`); + }); + + let hrs = target.querySelectorAll('hr'); + assert.equal(Object.keys(component.hrs).length, 3, 'three hrs are registered (keyed object)'); + // @ts-ignore + component.items.forEach((e, i) => { + assert.equal(component.hrs[e], hrs[i], `hr ${e} is correct (keyed object)`); + }); + + component.items = ['foo', 'baz']; + assert.equal(component.divs.length, 3, 'the divs array is still 3 long'); + assert.equal(component.divs[2], null, 'the last div is unregistered'); + assert.equal(component.ps[2], null, 'the last p is unregistered'); + assert.equal(component.spans['-bar1'], null, 'the bar span is unregistered'); + assert.equal(component.hrs.bar, null, 'the bar hr is unregistered'); + + divs = target.querySelectorAll('div'); + // @ts-ignore + component.divs.forEach((e, i) => { + assert.equal(e, divs[i], `div ${i} is still correct`); + }); + + spans = target.querySelectorAll('span'); + // @ts-ignore + component.items.forEach((e, i) => { + assert.equal(component.spans[`-${e}${i}`], spans[i], `span -${e}${i} is still correct`); + }); + + ps = target.querySelectorAll('p'); + // @ts-ignore + component.ps.forEach((e, i) => { + assert.equal(e, ps[i], `p ${i} is still correct`); + }); + + hrs = target.querySelectorAll('hr'); + // @ts-ignore + component.items.forEach((e, i) => { + assert.equal(component.hrs[e], hrs[i], `hr ${e} is still correct`); + }); + } +}); diff --git a/test/runtime/samples/binding-this-with-context/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this-with-context/main.svelte similarity index 100% rename from test/runtime/samples/binding-this-with-context/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this-with-context/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-this/_config.js new file mode 100644 index 000000000000..52384112e92f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-this/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, component, target }) { + const canvas = target.querySelector('canvas'); + assert.equal(canvas, component.foo); + } +}); diff --git a/test/runtime/samples/binding-this/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-this/main.svelte similarity index 100% rename from test/runtime/samples/binding-this/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-this/main.svelte diff --git a/test/runtime/samples/binding-using-props/TextInput.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-using-props/TextInput.svelte similarity index 100% rename from test/runtime/samples/binding-using-props/TextInput.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-using-props/TextInput.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-using-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-using-props/_config.js new file mode 100644 index 000000000000..1134b20d0c5b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-using-props/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + const event = new window.Event('input'); + input.value = 'changed'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

changed

+ ` + ); + } +}); diff --git a/test/runtime/samples/binding-using-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-using-props/main.svelte similarity index 100% rename from test/runtime/samples/binding-using-props/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/binding-using-props/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-value-prop/Field.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-value-prop/Field.svelte new file mode 100644 index 000000000000..b3bfeab84fed --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-value-prop/Field.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-value-prop/_config.js b/packages/svelte/tests/runtime-legacy/samples/binding-value-prop/_config.js new file mode 100644 index 000000000000..11ff60ca1ebe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-value-prop/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + accessors: false, + html: `\naaa`, + ssrHtml: `\naaa`, + + test({ assert, target }) { + const input = target.querySelector('input'); + ok(input); + + const event = new window.Event('input'); + + input.value = 'aaa2'; + input.dispatchEvent(event); + + flushSync(); + + assert.htmlEqual(target.innerHTML, `\naaa2`); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/binding-value-prop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/binding-value-prop/main.svelte new file mode 100644 index 000000000000..4352cb65cd3e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/binding-value-prop/main.svelte @@ -0,0 +1,9 @@ + + + {$value} diff --git a/packages/svelte/tests/runtime-legacy/samples/bindings-before-onmount/One.svelte b/packages/svelte/tests/runtime-legacy/samples/bindings-before-onmount/One.svelte new file mode 100644 index 000000000000..e9a0b5158c54 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bindings-before-onmount/One.svelte @@ -0,0 +1,13 @@ + + + diff --git a/test/runtime/samples/bindings-before-onmount/Two.svelte b/packages/svelte/tests/runtime-legacy/samples/bindings-before-onmount/Two.svelte similarity index 100% rename from test/runtime/samples/bindings-before-onmount/Two.svelte rename to packages/svelte/tests/runtime-legacy/samples/bindings-before-onmount/Two.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/bindings-before-onmount/_config.js b/packages/svelte/tests/runtime-legacy/samples/bindings-before-onmount/_config.js new file mode 100644 index 000000000000..1a97e967139f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bindings-before-onmount/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, component }) { + assert.equal(component.one.snapshot, 2); + } +}); diff --git a/test/runtime/samples/bindings-before-onmount/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bindings-before-onmount/main.svelte similarity index 100% rename from test/runtime/samples/bindings-before-onmount/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/bindings-before-onmount/main.svelte diff --git a/test/runtime/samples/bindings-coalesced/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/Foo.svelte similarity index 100% rename from test/runtime/samples/bindings-coalesced/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/_config.js b/packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/_config.js new file mode 100644 index 000000000000..3bc5d845a1c3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, component }) { + const { foo, p } = component; + + /** @type {string[]} */ + const values = []; + + Object.defineProperty(p.childNodes[0], 'nodeValue', { + set(value) { + values.push('' + value); + } + }); + + foo.double(); + flushSync(); + + assert.deepEqual(values, ['6']); + } +}); diff --git a/test/runtime/samples/bindings-coalesced/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/main.svelte similarity index 100% rename from test/runtime/samples/bindings-coalesced/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/bindings-coalesced/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/bindings-global-dependency/_config.js b/packages/svelte/tests/runtime-legacy/samples/bindings-global-dependency/_config.js new file mode 100644 index 000000000000..3c266a18f051 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bindings-global-dependency/_config.js @@ -0,0 +1,6 @@ +import { test } from '../../test'; + +export default test({ + html: '', + ssrHtml: '' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bindings-global-dependency/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bindings-global-dependency/main.svelte new file mode 100644 index 000000000000..15a4381a06b8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bindings-global-dependency/main.svelte @@ -0,0 +1,9 @@ + + +{#each Object.values(data) as object} + +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-2/_config.js new file mode 100644 index 000000000000..99e883d61bb6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-2/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + error: 'potato is not defined' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-2/main.svelte new file mode 100644 index 000000000000..10fa1bd5e258 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-2/main.svelte @@ -0,0 +1,35 @@ + +

{x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + x19 + x20 + x21 + x22 + x23 + x24 + x25 + x26 + x27 + x28 + x29 + x30 + x31 + x32}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-3/_config.js new file mode 100644 index 000000000000..a0b2f79c4c3d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-3/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + error: 'A is not defined' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-3/main.svelte new file mode 100644 index 000000000000..aa2c56a14759 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-3/main.svelte @@ -0,0 +1,4 @@ + +foo diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if-2/_config.js new file mode 100644 index 000000000000..692f6e0bb48f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if-2/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +// `bitmask-overflow-if` tests the case where the if condition is made of first 32 variables +// this tests the case where the if condition is made of the next 32 variables +export default test({ + html: ` + 012345678910111213141516171819202122232425262728293031323334353637383940 + expected: true + if: true + `, + + async test({ assert, component, target }) { + component._40 = '-'; + + assert.htmlEqual( + target.innerHTML, + ` + 0123456789101112131415161718192021222324252627282930313233343536373839- + expected: false + if: false +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if-2/main.svelte new file mode 100644 index 000000000000..f2a461b5b452 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if-2/main.svelte @@ -0,0 +1,56 @@ + + + +{_0}{_1}{_2}{_3}{_4}{_5}{_6}{_7}{_8}{_9}{_10}{_11}{_12}{_13}{_14}{_15}{_16}{_17}{_18}{_19}{_20}{_21}{_22}{_23}{_24}{_25}{_26}{_27}{_28}{_29}{_30}{_31}{_32}{_33}{_34}{_35}{_36}{_37}{_38}{_39}{_40} + +expected: {_a.indexOf(_40) > -1 && _40 === '40' && _39 === '39'} +{#if _a.indexOf(_40) > -1 && _40 === '40' && _39 === '39'} +if: true +{:else} +if: false +
+{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if/_config.js new file mode 100644 index 000000000000..d6e04b8fa41c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if/_config.js @@ -0,0 +1,28 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + 012345678910111213141516171819202122232425262728293031323334353637383940 + expected: true + if: true + + `, + + async test({ assert, target, window }) { + const button = target.querySelector('button'); + button?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + 112345678910111213141516171819202122232425262728293031323334353637383940 + expected: false + if: false +
+ + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if/main.svelte new file mode 100644 index 000000000000..2c1c4530914f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-if/main.svelte @@ -0,0 +1,62 @@ + + + +{_0}{_1}{_2}{_3}{_4}{_5}{_6}{_7}{_8}{_9}{_10}{_11}{_12}{_13}{_14}{_15}{_16}{_17}{_18}{_19}{_20}{_21}{_22}{_23}{_24}{_25}{_26}{_27}{_28}{_29}{_30}{_31}{_32}{_33}{_34}{_35}{_36}{_37}{_38}{_39}{_40} + +expected: {_a.indexOf(_0) && _0 === '0' && _1 === '1'} +{#if _a.indexOf(_0) && _0 === '0' && _1 === '1'} +if: true +{:else} +if: false +
+{/if} + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-2/Echo.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-2/Echo.svelte new file mode 100644 index 000000000000..c8905184dc1b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-2/Echo.svelte @@ -0,0 +1,73 @@ + + +

{d1}

+

{d2}

+

{d3}

+

{d4}

+

{d5}

+

{d6}

+

{d7}

+

{d8}

+

{d9}

+

{d10}

+

{d11}

+

{d12}

+

{d13}

+

{d14}

+

{d15}

+

{d16}

+

{d17}

+

{d18}

+

{d19}

+

{d20}

+

{d21}

+

{d22}

+

{d23}

+

{d24}

+

{d25}

+

{d26}

+

{d27}

+

{d28}

+

{d29}

+

{d30}

+

{d31}

+

{d32}

+

{d33}

+ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-2/_config.js new file mode 100644 index 000000000000..aacb55a9bb12 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-2/_config.js @@ -0,0 +1,101 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

d1

+

d2

+

d3

+

d4

+

d5

+

d6

+

d7

+

d8

+

d9

+

d10

+

d11

+

d12

+

d13

+

d14

+

d15

+

d16

+

d17

+

d18

+

d19

+

d20

+

d21

+

d22

+

d23

+

d24

+

d25

+

d26

+

d27

+

d28

+

d29

+

d30

+

d31

+

2

+

1

+

0:1

+

2:1

+

0

+

1

+

2

+ `, + + test({ assert, component, target }) { + component.reads = {}; + + component._0 = 'a'; + component._1 = 'b'; + component._2 = 'c'; + + assert.htmlEqual( + target.innerHTML, + ` +

d1

+

d2

+

d3

+

d4

+

d5

+

d6

+

d7

+

d8

+

d9

+

d10

+

d11

+

d12

+

d13

+

d14

+

d15

+

d16

+

d17

+

d18

+

d19

+

d20

+

d21

+

d22

+

d23

+

d24

+

d25

+

d26

+

d27

+

d28

+

d29

+

d30

+

d31

+

c

+

b

+

a:b

+

c:b

+

a

+

b

+

c

+ ` + ); + + assert.deepEqual(component.reads, { + _0: 2, + _1: 2 + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-2/main.svelte new file mode 100644 index 000000000000..55773e1c5f9c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-2/main.svelte @@ -0,0 +1,33 @@ + + + +

{bar}

+

{dummy}

+

{_0}

+

{_1}

+

{_2}

+
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-3/Echo.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-3/Echo.svelte new file mode 100644 index 000000000000..d3ecf142c924 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-3/Echo.svelte @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-3/_config.js new file mode 100644 index 000000000000..c2f0e69ef56a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-3/_config.js @@ -0,0 +1,39 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40

+

0

+ + `, + + test({ assert, component, target, window }) { + // change from inside + const button = target.querySelector('button'); + button?.dispatchEvent(new window.Event('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40

+

1

+ + ` + ); + + // change from outside + component._0 = 'a'; + component._40 = 'b'; + + assert.htmlEqual( + target.innerHTML, + ` +

a_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39b

+

1

+ + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-3/main.svelte new file mode 100644 index 000000000000..ae798e4aeeb5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-3/main.svelte @@ -0,0 +1,11 @@ + + + +

{_0}{_1}{_2}{_3}{_4}{_5}{_6}{_7}{_8}{_9}{_10}{_11}{_12}{_13}{_14}{_15}{_16}{_17}{_18}{_19}{_20}{_21}{_22}{_23}{_24}{_25}{_26}{_27}{_28}{_29}{_30}{_31}{_32}{_33}{_34}{_35}{_36}{_37}{_38}{_39}{_40}

+

{dummy}

+
+ diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-4/Echo.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-4/Echo.svelte new file mode 100644 index 000000000000..2e1beda492d9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-4/Echo.svelte @@ -0,0 +1,11 @@ + + +

{_0}{_1}{_2}{_3}{_4}{_5}{_6}{_7}{_8}{_9}{_10}{_11}{_12}{_13}{_14}{_15}{_16}{_17}{_18}{_19}{_20}{_21}{_22}{_23}{_24}{_25}{_26}{_27}{_28}{_29}{_30}{_31}{_32}{_33}{_34}{_35}{_36}{_37}{_38}{_39}{_40}

+ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-4/_config.js new file mode 100644 index 000000000000..51e9d53ef0fc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-4/_config.js @@ -0,0 +1,54 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40

+

0

+

0

+ + `, + + test({ assert, component, target, window }) { + // change from inside + const button = target.querySelector('button'); + button?.dispatchEvent(new window.Event('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40

+

0

+

1

+ + ` + ); + + // change from outside + component._0 = 'a'; + + assert.htmlEqual( + target.innerHTML, + ` +

_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40

+

a

+

1

+ + ` + ); + + // change from outside through props + component._40 = 'b'; + + assert.htmlEqual( + target.innerHTML, + ` +

_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39b

+

a

+

1

+ + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-4/main.svelte new file mode 100644 index 000000000000..7e02487a305d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-4/main.svelte @@ -0,0 +1,12 @@ + + + +

{_0}

+

{dummy}

+
+ diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-5/Echo.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-5/Echo.svelte new file mode 100644 index 000000000000..dddb3f76428f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-5/Echo.svelte @@ -0,0 +1,13 @@ + + +

{_0}{_1}{_2}{_3}{_4}{_5}{_6}{_7}{_8}{_9}{_10}{_11}{_12}{_13}{_14}{_15}{_16}{_17}{_18}{_19}{_20}{_21}{_22}{_23}{_24}{_25}{_26}{_27}{_28}{_29}{_30}{_31}{_32}{_33}{_34}{_35}{_36}{_37}{_38}{_39}{_40}

+

{b}

+ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-5/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-5/_config.js new file mode 100644 index 000000000000..768af95193a6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-5/_config.js @@ -0,0 +1,62 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40

+

b

+

-0-1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40

+

0

+

0

+ + `, + + test({ assert, component, target, window }) { + // change from inside + const button = target.querySelector('button'); + button?.dispatchEvent(new window.Event('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40

+

b

+

-0-1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40

+

0

+

1

+ + ` + ); + + // change from outside + component.a = 'AA'; + + assert.htmlEqual( + target.innerHTML, + ` +

_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40

+

b

+

-0-1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40

+

AA

+

1

+ + ` + ); + + // change from outside through props + component.b = 'BB'; + + assert.htmlEqual( + target.innerHTML, + ` +

_0_1_2_3_4_5_6_7_8_9_10_11_12_13_14_15_16_17_18_19_20_21_22_23_24_25_26_27_28_29_30_31_32_33_34_35_36_37_38_39_40

+

BB

+

-0-1-2-3-4-5-6-7-8-9-10-11-12-13-14-15-16-17-18-19-20-21-22-23-24-25-26-27-28-29-30-31-32-33-34-35-36-37-38-39-40

+

AA

+

1

+ + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-5/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-5/main.svelte new file mode 100644 index 000000000000..b17d6f7baef8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-5/main.svelte @@ -0,0 +1,13 @@ + + + +

{_0}{_1}{_2}{_3}{_4}{_5}{_6}{_7}{_8}{_9}{_10}{_11}{_12}{_13}{_14}{_15}{_16}{_17}{_18}{_19}{_20}{_21}{_22}{_23}{_24}{_25}{_26}{_27}{_28}{_29}{_30}{_31}{_32}{_33}{_34}{_35}{_36}{_37}{_38}{_39}{_40}

+

{a}

+

{dummy}

+
+ diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-6/Slotted.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-6/Slotted.svelte new file mode 100644 index 000000000000..322a31359ecf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-6/Slotted.svelte @@ -0,0 +1,15 @@ + + +
+ + + + {#if open} + + {/if} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-6/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-6/_config.js new file mode 100644 index 000000000000..a905589f526b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-6/_config.js @@ -0,0 +1,42 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +// overflow bitmask + slot missing `let:` +export default test({ + html: ` +
+ +
+ + `, + + test({ assert, target, window }) { + const button = target.querySelectorAll('button')[1]; + const div = target.querySelector('div'); + div?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +
+ +
Open
+
+ + ` + ); + + button.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +
+ +
Open
+
+ + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-6/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-6/main.svelte new file mode 100644 index 000000000000..8845cb2ef59d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot-6/main.svelte @@ -0,0 +1,23 @@ + + + + + +
+ Open +
+
+ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot/Echo.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot/Echo.svelte new file mode 100644 index 000000000000..28eaa54060a3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot/Echo.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot/_config.js new file mode 100644 index 000000000000..78e6a73f50c9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot/_config.js @@ -0,0 +1,129 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

0

+

1

+

2

+

3

+

4

+

5

+

6

+

7

+

8

+

9

+

10

+

11

+

12

+

13

+

14

+

15

+

16

+

17

+

18

+

19

+

20

+

21

+

22

+

23

+

24

+

25

+

26

+

27

+

28

+

29

+

30

+

31

+

32

+

33

+

34

+

35

+

36

+

37

+

38

+

39

+

40

+

5:36

+

6:37

+

38

+

0

+ `, + + async test({ assert, component, target }) { + component.reads = {}; + + component._0 = 'a'; + component._30 = 'b'; + component._31 = 'c'; + component._32 = 'd'; + component._40 = 'e'; + + component._5 = 'f'; + component._6 = 'g'; + component._36 = 'h'; + component._37 = 'i'; + + assert.htmlEqual( + target.innerHTML, + ` +

a

+

1

+

2

+

3

+

4

+

f

+

g

+

7

+

8

+

9

+

10

+

11

+

12

+

13

+

14

+

15

+

16

+

17

+

18

+

19

+

20

+

21

+

22

+

23

+

24

+

25

+

26

+

27

+

28

+

29

+

b

+

c

+

d

+

33

+

34

+

35

+

h

+

i

+

38

+

39

+

e

+

f:h

+

g:i

+

38

+

a

+ ` + ); + + assert.deepEqual(component.reads, { + _0: 1, + _5: 3, + _6: 3, + _30: 1, + _31: 1, + _32: 1, + _36: 3, + _37: 3, + _40: 1 + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot/main.svelte new file mode 100644 index 000000000000..0b85ef8ee249 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow-slot/main.svelte @@ -0,0 +1,110 @@ + + + +

{read(_0, '_0')}

+

{read(_1, '_1')}

+

{read(_2, '_2')}

+

{read(_3, '_3')}

+

{read(_4, '_4')}

+

{read(_5, '_5')}

+

{read(_6, '_6')}

+

{read(_7, '_7')}

+

{read(_8, '_8')}

+

{read(_9, '_9')}

+

{read(_10, '_10')}

+

{read(_11, '_11')}

+

{read(_12, '_12')}

+

{read(_13, '_13')}

+

{read(_14, '_14')}

+

{read(_15, '_15')}

+

{read(_16, '_16')}

+

{read(_17, '_17')}

+

{read(_18, '_18')}

+

{read(_19, '_19')}

+

{read(_20, '_20')}

+

{read(_21, '_21')}

+

{read(_22, '_22')}

+

{read(_23, '_23')}

+

{read(_24, '_24')}

+

{read(_25, '_25')}

+

{read(_26, '_26')}

+

{read(_27, '_27')}

+

{read(_28, '_28')}

+

{read(_29, '_29')}

+

{read(_30, '_30')}

+

{read(_31, '_31')}

+

{read(_32, '_32')}

+

{read(_33, '_33')}

+

{read(_34, '_34')}

+

{read(_35, '_35')}

+

{read(_36, '_36')}

+

{read(_37, '_37')}

+

{read(_38, '_38')}

+

{read(_39, '_39')}

+

{read(_40, '_40')}

+ +

{read(_5, '_5') + ':' + read(_36, '_36')}

+

{foo}

+

{bar}

+ +

{dummy}

+
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow/_config.js b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow/_config.js new file mode 100644 index 000000000000..45ad900545de --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow/_config.js @@ -0,0 +1,127 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

0

+

1

+

2

+

3

+

4

+

5

+

6

+

7

+

8

+

9

+

10

+

11

+

12

+

13

+

14

+

15

+

16

+

17

+

18

+

19

+

20

+

21

+

22

+

23

+

24

+

25

+

26

+

27

+

28

+

29

+

30

+

31

+

32

+

33

+

34

+

35

+

36

+

37

+

38

+

39

+

40

+

5:36

+

6:37

+

38

+ `, + + test({ assert, component, target }) { + component.reads = {}; + + component._0 = 'a'; + component._30 = 'b'; + component._31 = 'c'; + component._32 = 'd'; + component._40 = 'e'; + + component._5 = 'f'; + component._6 = 'g'; + component._36 = 'h'; + component._37 = 'i'; + + assert.htmlEqual( + target.innerHTML, + ` +

a

+

1

+

2

+

3

+

4

+

f

+

g

+

7

+

8

+

9

+

10

+

11

+

12

+

13

+

14

+

15

+

16

+

17

+

18

+

19

+

20

+

21

+

22

+

23

+

24

+

25

+

26

+

27

+

28

+

29

+

b

+

c

+

d

+

33

+

34

+

35

+

h

+

i

+

38

+

39

+

e

+

f:h

+

g:i

+

38

+ ` + ); + + assert.deepEqual(component.reads, { + _0: 1, + _5: 3, + _6: 3, + _30: 1, + _31: 1, + _32: 1, + _36: 3, + _37: 3, + _40: 1 + }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow/main.svelte b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow/main.svelte new file mode 100644 index 000000000000..962c4cec23d5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/bitmask-overflow/main.svelte @@ -0,0 +1,105 @@ + + +

{read(_0, '_0')}

+

{read(_1, '_1')}

+

{read(_2, '_2')}

+

{read(_3, '_3')}

+

{read(_4, '_4')}

+

{read(_5, '_5')}

+

{read(_6, '_6')}

+

{read(_7, '_7')}

+

{read(_8, '_8')}

+

{read(_9, '_9')}

+

{read(_10, '_10')}

+

{read(_11, '_11')}

+

{read(_12, '_12')}

+

{read(_13, '_13')}

+

{read(_14, '_14')}

+

{read(_15, '_15')}

+

{read(_16, '_16')}

+

{read(_17, '_17')}

+

{read(_18, '_18')}

+

{read(_19, '_19')}

+

{read(_20, '_20')}

+

{read(_21, '_21')}

+

{read(_22, '_22')}

+

{read(_23, '_23')}

+

{read(_24, '_24')}

+

{read(_25, '_25')}

+

{read(_26, '_26')}

+

{read(_27, '_27')}

+

{read(_28, '_28')}

+

{read(_29, '_29')}

+

{read(_30, '_30')}

+

{read(_31, '_31')}

+

{read(_32, '_32')}

+

{read(_33, '_33')}

+

{read(_34, '_34')}

+

{read(_35, '_35')}

+

{read(_36, '_36')}

+

{read(_37, '_37')}

+

{read(_38, '_38')}

+

{read(_39, '_39')}

+

{read(_40, '_40')}

+ +

{read(_5, '_5') + ':' + read(_36, '_36')}

+

{foo}

+

{bar}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/class-boolean/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-boolean/_config.js new file mode 100644 index 000000000000..cc8e59197d25 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-boolean/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
' +}); diff --git a/test/runtime/samples/class-boolean/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-boolean/main.svelte similarity index 100% rename from test/runtime/samples/class-boolean/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/class-boolean/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/class-helper/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-helper/_config.js new file mode 100644 index 000000000000..b4733a622982 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-helper/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { user: { active: true } }; + }, + + html: '
', + + test({ assert, component, target }) { + component.user = { active: false }; + + assert.htmlEqual(target.innerHTML, `
`); + } +}); diff --git a/test/runtime/samples/class-helper/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-helper/main.svelte similarity index 100% rename from test/runtime/samples/class-helper/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/class-helper/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/class-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-in-each/_config.js new file mode 100644 index 000000000000..4a2b4f97f6be --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-in-each/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + things: ['one', 'two', 'three'], + selected: 'two' + }; + }, + + html: ` +
+
+
+ `, + + test({ assert, component, target }) { + component.selected = 'three'; + assert.htmlEqual( + target.innerHTML, + ` +
+
+
+ ` + ); + } +}); diff --git a/test/runtime/samples/class-in-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-in-each/main.svelte similarity index 100% rename from test/runtime/samples/class-in-each/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/class-in-each/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-class/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-class/_config.js new file mode 100644 index 000000000000..428f7bde89c0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-class/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: true, bar: true, myClass: 'one two' }; + }, + + html: '
', + + test({ assert, component, target }) { + component.foo = false; + + assert.htmlEqual( + target.innerHTML, + ` +
+ ` + ); + } +}); diff --git a/test/runtime/samples/class-shortcut-with-class/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-class/main.svelte similarity index 100% rename from test/runtime/samples/class-shortcut-with-class/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-class/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-transition/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-transition/_config.js new file mode 100644 index 000000000000..e58e8c53c5ba --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-transition/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { open: false, border: true }; + }, + html: '

foo

', + + test({ assert, component, target, raf }) { + component.open = true; + raf.tick(100); + assert.htmlEqual( + target.innerHTML, + '

foo

bar

' + ); + + component.open = false; + raf.tick(150); + assert.htmlEqual( + target.innerHTML, + '

foo

bar

' + ); + component.open = true; + raf.tick(250); + assert.htmlEqual( + target.innerHTML, + '

foo

bar

' + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-transition/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-transition/main.svelte new file mode 100644 index 000000000000..3291ec4a1070 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-shortcut-with-transition/main.svelte @@ -0,0 +1,17 @@ + + +

foo

+{#if open} +

bar

+{/if} + + diff --git a/packages/svelte/tests/runtime-legacy/samples/class-shortcut/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-shortcut/_config.js new file mode 100644 index 000000000000..7069b4245c29 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-shortcut/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: true, bar: true }; + }, + + html: '
', + + test({ assert, component, target }) { + component.foo = false; + + assert.htmlEqual( + target.innerHTML, + ` +
+ ` + ); + } +}); diff --git a/test/runtime/samples/class-shortcut/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-shortcut/main.svelte similarity index 100% rename from test/runtime/samples/class-shortcut/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/class-shortcut/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/class-with-attribute/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-with-attribute/_config.js new file mode 100644 index 000000000000..ee3a258dde11 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-with-attribute/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
' +}); diff --git a/test/runtime/samples/class-with-attribute/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-with-attribute/main.svelte similarity index 100% rename from test/runtime/samples/class-with-attribute/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/class-with-attribute/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute-and-spread/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute-and-spread/_config.js new file mode 100644 index 000000000000..6dfd2decaa92 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute-and-spread/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + myClass: 'one two', + /** @type {Record} */ + attributes: { role: 'button' } + }; + }, + + html: '
', + + test({ assert, component, target }) { + component.myClass = 'one'; + component.attributes = { + 'aria-label': 'Test' + }; + + assert.htmlEqual( + target.innerHTML, + ` +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute-and-spread/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute-and-spread/main.svelte new file mode 100644 index 000000000000..95825c777bed --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute-and-spread/main.svelte @@ -0,0 +1,6 @@ + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute/_config.js new file mode 100644 index 000000000000..ee983af2552b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { myClass: 'one two' }; + }, + + html: '
', + + test({ assert, component, target }) { + component.myClass = 'one'; + + assert.htmlEqual( + target.innerHTML, + ` +
+ ` + ); + } +}); diff --git a/test/runtime/samples/class-with-dynamic-attribute/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute/main.svelte similarity index 100% rename from test/runtime/samples/class-with-dynamic-attribute/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/class-with-dynamic-attribute/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/class-with-spread-and-bind/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-with-spread-and-bind/_config.js new file mode 100644 index 000000000000..ff1da0a9abdb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-with-spread-and-bind/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { primary: true }; + }, + + html: '
', + + test({ assert, component, target }) { + component.primary = true; + + assert.htmlEqual( + target.innerHTML, + ` +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/class-with-spread-and-bind/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-with-spread-and-bind/main.svelte new file mode 100644 index 000000000000..6efedef0797d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-with-spread-and-bind/main.svelte @@ -0,0 +1,11 @@ + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/class-with-spread/_config.js b/packages/svelte/tests/runtime-legacy/samples/class-with-spread/_config.js new file mode 100644 index 000000000000..49f77b33341a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-with-spread/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + myClass: 'one two', + /** @type {Record} */ + attributes: { role: 'button' } + }; + }, + + html: '
', + + test({ assert, component, target }) { + component.myClass = 'one'; + component.attributes = { + 'aria-label': 'Test' + }; + + assert.htmlEqual( + target.innerHTML, + ` +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/class-with-spread/main.svelte b/packages/svelte/tests/runtime-legacy/samples/class-with-spread/main.svelte new file mode 100644 index 000000000000..54d8088581c5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/class-with-spread/main.svelte @@ -0,0 +1,6 @@ + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-accessors/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-accessors/Nested.svelte new file mode 100644 index 000000000000..a3ce2afd9f4a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-accessors/Nested.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-accessors/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-accessors/_config.js new file mode 100644 index 000000000000..1a6c9039a702 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-accessors/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const [input1, input2] = target.querySelectorAll('input'); + assert.equal(input1.value, 'something'); + assert.equal(input2.value, 'something'); + + input1.value = 'abc'; + + input1.dispatchEvent(new window.Event('input')); + flushSync(); + assert.equal(input1.value, 'abc'); + assert.equal(input2.value, 'abc'); + + target + .querySelector('button') + ?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + + assert.equal(input1.value, 'Reset'); + assert.equal(input2.value, 'Reset'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-accessors/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-accessors/main.svelte new file mode 100644 index 000000000000..1d8576643d64 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-accessors/main.svelte @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-aliased/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-aliased/Widget.svelte new file mode 100644 index 000000000000..7d173df21045 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-aliased/Widget.svelte @@ -0,0 +1,4 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-aliased/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-aliased/_config.js new file mode 100644 index 000000000000..9292ce73db1b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-aliased/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
42
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-aliased/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-aliased/main.svelte new file mode 100644 index 000000000000..a262c675ea7f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-aliased/main.svelte @@ -0,0 +1,8 @@ + + + + +
{bar}
diff --git a/test/runtime/samples/component-binding-blowback-b/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/Nested.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-b/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/_config.js new file mode 100644 index 000000000000..f9427690ae73 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/_config.js @@ -0,0 +1,40 @@ +import { ok, test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + mode: ['client', 'hydrate'], // relies on onMount firing, which does not happen in SSR mode + + get props() { + return { count: 3 }; + }, + + html: ` + +
    +
  1. id-0: value is zero
  2. +
  3. id-1: value is one
  4. +
  5. id-2: value is two
  6. +
+ `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + input.value = '4'; + flushSync(() => input.dispatchEvent(new window.Event('input'))); + + assert.htmlEqual( + target.innerHTML, + ` + +
    +
  1. id-0: value is zero
  2. +
  3. id-1: value is one
  4. +
  5. id-2: value is two
  6. +
  7. id-3: value is three
  8. +
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-blowback-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-b/main.svelte diff --git a/test/runtime/samples/component-binding-blowback-c/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/Nested.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-c/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/_config.js new file mode 100644 index 000000000000..b866160fb023 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/_config.js @@ -0,0 +1,40 @@ +import { ok, test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + mode: ['client', 'hydrate'], // relies on onMount firing, which does not happen in SSR mode + + get props() { + return { count: 3 }; + }, + + html: ` + +
    +
  1. id-2: value is two
  2. +
  3. id-1: value is one
  4. +
  5. id-0: value is zero
  6. +
+ `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + input.value = '4'; + flushSync(() => input.dispatchEvent(new window.Event('input'))); + + assert.htmlEqual( + target.innerHTML, + ` + +
    +
  1. id-3: value is three
  2. +
  3. id-2: value is two
  4. +
  5. id-1: value is one
  6. +
  7. id-0: value is zero
  8. +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/main.svelte new file mode 100644 index 000000000000..75552bf358d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-c/main.svelte @@ -0,0 +1,23 @@ + + + + +
    + {#each ids(count) as object (object.id)} + + {object.id}: value is {idToValue[object.id]} + + {/each} +
\ No newline at end of file diff --git a/test/runtime/samples/component-binding-blowback-d/One.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-d/One.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-d/One.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-d/One.svelte diff --git a/test/runtime/samples/component-binding-blowback-d/Two.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-d/Two.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-d/Two.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-d/Two.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-d/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-d/_config.js new file mode 100644 index 000000000000..aafce8633659 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-d/_config.js @@ -0,0 +1,30 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + +

{"value":"0:0"}

+

+ `, + + test({ assert, target, window }) { + const button = target.querySelectorAll('button')[1]; + + button.dispatchEvent(new window.Event('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

{"value":"0:0"}

+

{"value":"1:0"}

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-blowback-d/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-d/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-d/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-d/main.svelte diff --git a/test/runtime/samples/component-binding-blowback-e/One.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-e/One.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-e/One.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-e/One.svelte diff --git a/test/runtime/samples/component-binding-blowback-e/Two.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-e/Two.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-e/Two.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-e/Two.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-e/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-e/_config.js new file mode 100644 index 000000000000..1d5ead8b7233 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-e/_config.js @@ -0,0 +1,30 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + +

{"value":{"i":0,"j":0}}

+

+ `, + + test({ assert, target, window }) { + const button = target.querySelectorAll('button')[1]; + + button.dispatchEvent(new window.Event('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

{"value":{"i":0,"j":0}}

+

{"value":{"i":1,"j":0}}

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-blowback-e/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-e/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-e/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-e/main.svelte diff --git a/test/runtime/samples/component-binding-blowback-f/One.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-f/One.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-f/One.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-f/One.svelte diff --git a/test/runtime/samples/component-binding-blowback-f/Two.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-f/Two.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-f/Two.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-f/Two.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-f/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-f/_config.js new file mode 100644 index 000000000000..82a6dcefeade --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-f/_config.js @@ -0,0 +1,38 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + +

{"value":{"i":0,"j":0}}

+

+ `, + + ssrHtml: ` + + + +

{}

+

+ `, + + test({ assert, target, window }) { + const button = target.querySelectorAll('button')[1]; + + button.dispatchEvent(new window.Event('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

{"value":{"i":0,"j":0}}

+

{"value":{"i":1,"j":0}}

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-blowback-f/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-f/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-blowback-f/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-blowback-f/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/Widget.svelte new file mode 100644 index 000000000000..cc77c331fa6d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/Widget.svelte @@ -0,0 +1 @@ +

does nothing

diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/_config.js new file mode 100644 index 000000000000..6012649c5f3e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; +// @ts-nocheck + +export default test({ + test({ assert, component }) { + let count = 0; + + // @ts-ignore + component.$on('state', ({ changed }) => { + if (changed.bar) count += 1; + }); + + component.x = true; + assert.equal(count, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/main.svelte new file mode 100644 index 000000000000..f77bc8c2ad47 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-blowback/main.svelte @@ -0,0 +1,12 @@ + + +{#if x} + +{/if} diff --git a/test/runtime/samples/component-binding-computed/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-computed/Nested.svelte similarity index 100% rename from test/runtime/samples/component-binding-computed/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-computed/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-computed/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-computed/_config.js new file mode 100644 index 000000000000..e823cf91b289 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-computed/_config.js @@ -0,0 +1,40 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + `, + ssrHtml: ` + + + `, + + async test({ assert, component, target, window }) { + const input = new window.Event('input'); + const inputs = target.querySelectorAll('input'); + + inputs[0].value = 'Ada'; + await inputs[0].dispatchEvent(input); + await Promise.resolve(); + assert.deepEqual(component.values, { + firstname: 'Ada', + lastname: '' + }); + + inputs[1].value = 'Lovelace'; + await inputs[1].dispatchEvent(input); + await Promise.resolve(); + assert.deepEqual(component.values, { + firstname: 'Ada', + lastname: 'Lovelace' + }); + + component.values = { + firstname: 'Grace', + lastname: 'Hopper' + }; + assert.equal(inputs[0].value, 'Grace'); + assert.equal(inputs[1].value, 'Hopper'); + } +}); diff --git a/test/runtime/samples/component-binding-computed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-computed/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-computed/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-computed/main.svelte diff --git a/test/runtime/samples/component-binding-conditional-b/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/Bar.svelte similarity index 100% rename from test/runtime/samples/component-binding-conditional-b/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/Bar.svelte diff --git a/test/runtime/samples/component-binding-conditional-b/Baz.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/Baz.svelte similarity index 100% rename from test/runtime/samples/component-binding-conditional-b/Baz.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/Baz.svelte diff --git a/test/runtime/samples/component-binding-conditional-b/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/Foo.svelte similarity index 100% rename from test/runtime/samples/component-binding-conditional-b/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/_config.js new file mode 100644 index 000000000000..56f4070de815 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/_config.js @@ -0,0 +1,26 @@ +import { test } from '../../test'; + +export default test({ + // This test failed in Svelte 4, because the Bar y binding is activated before the + // Baz x binding, meaning that by the time Foo is created, we already + // have a value for y which Foo won't override. Easily worked around, + // probably impossible to 'fix', so this test is left here for info + // purposes but will probably remain skipped indefinitely - or rather, + // it's okay if it needs to be skipped again sometime in the future. + html: ` +

y: foo

+

y: foo

+ `, + + test({ assert, component, target }) { + component.x = false; + + assert.htmlEqual( + target.innerHTML, + ` +

y: foo

+

y: foo

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-conditional-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-conditional-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-conditional-b/main.svelte diff --git a/test/runtime/samples/component-binding-conditional/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/Bar.svelte similarity index 100% rename from test/runtime/samples/component-binding-conditional/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/Bar.svelte diff --git a/test/runtime/samples/component-binding-conditional/Baz.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/Baz.svelte similarity index 100% rename from test/runtime/samples/component-binding-conditional/Baz.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/Baz.svelte diff --git a/test/runtime/samples/component-binding-conditional/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/Foo.svelte similarity index 100% rename from test/runtime/samples/component-binding-conditional/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/_config.js new file mode 100644 index 000000000000..5c96bbf869a0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

y: bar

+

y: bar

+ `, + + test({ assert, component, target }) { + component.x = false; + + assert.htmlEqual( + target.innerHTML, + ` +

y: bar

+

y: bar

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-conditional/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-conditional/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-conditional/main.svelte diff --git a/test/runtime/samples/component-binding-deep/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-deep/Widget.svelte similarity index 100% rename from test/runtime/samples/component-binding-deep/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-deep/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-deep/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-deep/_config.js new file mode 100644 index 000000000000..a8881cb1ed3a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-deep/_config.js @@ -0,0 +1,33 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

foo

+ `, + + ssrHtml: ` + +

foo

+ `, + + test({ assert, component, target, window }) { + const event = new window.MouseEvent('input'); + const input = target.querySelector('input'); + ok(input); + + input.value = 'blah'; + input.dispatchEvent(event); + flushSync(); + + assert.deepEqual(component.deep, { name: 'blah' }); + assert.htmlEqual( + target.innerHTML, + ` + +

blah

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-deep/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-deep/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-deep/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-deep/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-deep2/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-deep2/Widget.svelte new file mode 100644 index 000000000000..c28dfbda901e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-deep2/Widget.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-deep2/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-deep2/_config.js new file mode 100644 index 000000000000..a8881cb1ed3a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-deep2/_config.js @@ -0,0 +1,33 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

foo

+ `, + + ssrHtml: ` + +

foo

+ `, + + test({ assert, component, target, window }) { + const event = new window.MouseEvent('input'); + const input = target.querySelector('input'); + ok(input); + + input.value = 'blah'; + input.dispatchEvent(event); + flushSync(); + + assert.deepEqual(component.deep, { name: 'blah' }); + assert.htmlEqual( + target.innerHTML, + ` + +

blah

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-deep2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-deep2/main.svelte new file mode 100644 index 000000000000..db8cd83b91b3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-deep2/main.svelte @@ -0,0 +1,11 @@ + + + + +

{deep.name}

\ No newline at end of file diff --git a/test/runtime/samples/component-binding-each-nested/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-nested/Widget.svelte similarity index 100% rename from test/runtime/samples/component-binding-each-nested/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-each-nested/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-nested/_config.js new file mode 100644 index 000000000000..1826f969138f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-nested/_config.js @@ -0,0 +1,34 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +

foo, bar, baz

+ `, + + ssrHtml: ` + + + +

foo, bar, baz

+ `, + + test({ assert, component, target, window }) { + const event = new window.MouseEvent('input'); + const inputs = target.querySelectorAll('input'); + + inputs[0].value = 'blah'; + inputs[0].dispatchEvent(event); + flushSync(); + + assert.deepEqual(component.a, [{ name: 'blah' }, { name: 'bar' }, { name: 'baz' }]); + assert.htmlEqual( + target.innerHTML, + ` + +

blah, bar, baz

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-each-nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-nested/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-each-nested/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-each-nested/main.svelte diff --git a/test/runtime/samples/component-binding-each-object/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-object/Widget.svelte similarity index 100% rename from test/runtime/samples/component-binding-each-object/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-each-object/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-object/_config.js new file mode 100644 index 000000000000..cbc63a0b777a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-object/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + a: [{ id: 'foo' }, { id: 'bar' }, { id: 'baz' }] + }; + }, + + html: ` + foobarbaz + `, + + test({ assert, component, target }) { + component.a = [{ id: 'yep' }, { id: 'nope' }]; + + assert.htmlEqual( + target.innerHTML, + ` + yepnope + ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-each-object/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-object/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-each-object/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-each-object/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-reassigned/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-reassigned/Child.svelte new file mode 100644 index 000000000000..75d673156921 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-reassigned/Child.svelte @@ -0,0 +1,7 @@ + + +

{value}

diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-reassigned/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-reassigned/_config.js new file mode 100644 index 000000000000..83937ea5c2b2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-reassigned/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

2, 3, 4

+

2

+

3

+

4

+

2, 3, 4

+ `, + + ssrHtml: ` +

1, 2, 3

+

2

+

3

+

4

+

1, 2, 3

+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-reassigned/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-reassigned/main.svelte new file mode 100644 index 000000000000..193723817e32 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-reassigned/main.svelte @@ -0,0 +1,13 @@ + + +

{numbers.join(', ')}

+ +{#each numbers as n} + +{/each} + +

{numbers.join(', ')}

diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/Child.svelte new file mode 100644 index 000000000000..e6cbf9d1d0ab --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/Child.svelte @@ -0,0 +1,21 @@ + + +
+ {#each list as item (item)} + + {/each} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/InnerChild.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/InnerChild.svelte new file mode 100644 index 000000000000..09a2c2911302 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/InnerChild.svelte @@ -0,0 +1,12 @@ + + + + {val} + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/_config.js new file mode 100644 index 000000000000..331a8e988a4c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/_config.js @@ -0,0 +1,60 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+ 0 + 1 +
+
+ 0 + 1 +
+
+ 0 + 1 +
+ `, + + ssrHtml: ` +
+ 0 + 1 + 2 +
+
+ 0 + 1 + 2 +
+
+ 0 + 1 + 2 +
+ `, + + async test({ assert, component, target }) { + await component.done; + // In Svelte 4 this was 14, but in Svelte 5, the timing differences + // because of async mean it's now 9. + assert.equal(component.getCounter(), 9); + assert.htmlEqual( + target.innerHTML, + ` +
+ 0 + 1 +
+
+ 0 + 1 +
+
+ 0 + 1 +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/main.svelte new file mode 100644 index 000000000000..7f4c448d8fd8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-keyed/main.svelte @@ -0,0 +1,35 @@ + + +{#each vals as val, index (val)} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/Child.svelte new file mode 100644 index 000000000000..8b7edc10f48c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/Child.svelte @@ -0,0 +1,21 @@ + + +
+ {#each list as item} + + {/each} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/InnerChild.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/InnerChild.svelte new file mode 100644 index 000000000000..09a2c2911302 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/InnerChild.svelte @@ -0,0 +1,12 @@ + + + + {val} + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/_config.js new file mode 100644 index 000000000000..82f620d1f145 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/_config.js @@ -0,0 +1,59 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+ 0 + 1 +
+
+ 0 + 1 +
+
+ 0 + 1 +
+ `, + + ssrHtml: ` +
+ 0 + 1 + 2 +
+
+ 0 + 1 + 2 +
+
+ 0 + 1 + 2 +
+ `, + + async test({ assert, component, target }) { + await component.done; + // With Svelte 5, this is 9. With Svelte 4 it was 13. + assert.equal(component.getCounter(), 9); + assert.htmlEqual( + target.innerHTML, + ` +
+ 0 + 1 +
+
+ 0 + 1 +
+
+ 0 + 1 +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/main.svelte new file mode 100644 index 000000000000..7f4c448d8fd8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each-remount-unkeyed/main.svelte @@ -0,0 +1,35 @@ + + +{#each vals as val, index (val)} + +{/each} diff --git a/test/runtime/samples/component-binding-each/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each/Widget.svelte similarity index 100% rename from test/runtime/samples/component-binding-each/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-each/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-each/_config.js new file mode 100644 index 000000000000..5242488d1fe2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-each/_config.js @@ -0,0 +1,34 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +

foo, bar, baz

+ `, + + ssrHtml: ` + + + +

foo, bar, baz

+ `, + + test({ assert, component, target, window }) { + const event = new window.MouseEvent('input'); + const inputs = target.querySelectorAll('input'); + + inputs[0].value = 'blah'; + inputs[0].dispatchEvent(event); + flushSync(); + + assert.deepEqual(component.a, ['blah', 'bar', 'baz']); + assert.htmlEqual( + target.innerHTML, + ` + +

blah, bar, baz

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-each/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-each/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-each/main.svelte diff --git a/test/runtime/samples/component-binding-infinite-loop/A.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/A.svelte similarity index 100% rename from test/runtime/samples/component-binding-infinite-loop/A.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/A.svelte diff --git a/test/runtime/samples/component-binding-infinite-loop/B.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/B.svelte similarity index 100% rename from test/runtime/samples/component-binding-infinite-loop/B.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/B.svelte diff --git a/test/runtime/samples/component-binding-infinite-loop/C.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/C.svelte similarity index 83% rename from test/runtime/samples/component-binding-infinite-loop/C.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/C.svelte index 0bfc2f1d4e9f..8226de6d71d3 100644 --- a/test/runtime/samples/component-binding-infinite-loop/C.svelte +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/C.svelte @@ -13,7 +13,7 @@ - \ No newline at end of file + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/_config.js new file mode 100644 index 000000000000..e7759ccc8763 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/_config.js @@ -0,0 +1,102 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + // Svelte 4/5 difference: The empty class strings are not added to the class attribute in this situation + html: ` +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ `, + + test({ assert, component, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + const spans = target.querySelectorAll('span'); + + spans[0].dispatchEvent(click); + flushSync(); + + assert.equal(component.currentIdentifier, 1); + assert.htmlEqual( + target.innerHTML, + ` +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ ` + ); + + spans[0].dispatchEvent(click); + flushSync(); + + assert.equal(component.currentIdentifier, null); + assert.htmlEqual( + target.innerHTML, + ` +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ +

1

+

2

+

3

+

2

+

1

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-infinite-loop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-infinite-loop/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-infinite-loop/main.svelte diff --git a/test/runtime/samples/component-binding-nested/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-nested/Bar.svelte similarity index 100% rename from test/runtime/samples/component-binding-nested/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-nested/Bar.svelte diff --git a/test/runtime/samples/component-binding-nested/Baz.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-nested/Baz.svelte similarity index 100% rename from test/runtime/samples/component-binding-nested/Baz.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-nested/Baz.svelte diff --git a/test/runtime/samples/component-binding-nested/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-nested/Foo.svelte similarity index 100% rename from test/runtime/samples/component-binding-nested/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-nested/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-nested/_config.js new file mode 100644 index 000000000000..630ddef5dc4b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-nested/_config.js @@ -0,0 +1,74 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 'initial' }; + }, + + html: ` +

x: initial

+ +

foo x: initial

+ +

bar x: initial

+ +

baz x: initial

+ `, + + test({ assert, component, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + const buttons = [...target.querySelectorAll('button')]; + + buttons[0].dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 'p'); + assert.htmlEqual( + target.innerHTML, + ` +

x: p

+ +

foo x: p

+ +

bar x: p

+ +

baz x: p

+ ` + ); + + buttons[1].dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 'q'); + assert.htmlEqual( + target.innerHTML, + ` +

x: q

+ +

foo x: q

+ +

bar x: q

+ +

baz x: q

+ ` + ); + + buttons[2].dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 'r'); + assert.htmlEqual( + target.innerHTML, + ` +

x: r

+ +

foo x: r

+ +

bar x: r

+ +

baz x: r

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-nested/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-nested/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-nested/main.svelte diff --git a/test/runtime/samples/component-binding-non-leaky/Counter.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-non-leaky/Counter.svelte similarity index 100% rename from test/runtime/samples/component-binding-non-leaky/Counter.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-non-leaky/Counter.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-non-leaky/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-non-leaky/_config.js new file mode 100644 index 000000000000..4a079d6fc6b8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-non-leaky/_config.js @@ -0,0 +1,39 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

count:

+ `, + + async test({ assert, component, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + const button = target.querySelector('button'); + ok(button); + + button.dispatchEvent(click); + flushSync(); + + assert.equal(component.x, undefined); + assert.htmlEqual( + target.innerHTML, + ` + +

count:

+ ` + ); + + button.dispatchEvent(click); + flushSync(); + + assert.equal(component.x, undefined); + assert.htmlEqual( + target.innerHTML, + ` + +

count:

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-non-leaky/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-non-leaky/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-non-leaky/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-non-leaky/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-onMount/Mount.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-onMount/Mount.svelte new file mode 100644 index 000000000000..ce3b0c48f806 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-onMount/Mount.svelte @@ -0,0 +1,15 @@ + + +
+

+ Bound? {bound} +

diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-onMount/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-onMount/_config.js new file mode 100644 index 000000000000..5de4cf67a224 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-onMount/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + assert.htmlEqual( + target.innerHTML, + ` +
+

+ Bound? true +

+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-onMount/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-onMount/main.svelte new file mode 100644 index 000000000000..6c9ef0d325a9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-onMount/main.svelte @@ -0,0 +1,11 @@ + + +
diff --git a/test/runtime/samples/component-binding-parent-supercedes-child-b/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-b/Bar.svelte similarity index 100% rename from test/runtime/samples/component-binding-parent-supercedes-child-b/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-b/Bar.svelte diff --git a/test/runtime/samples/component-binding-parent-supercedes-child-b/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-b/Foo.svelte similarity index 100% rename from test/runtime/samples/component-binding-parent-supercedes-child-b/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-b/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-b/_config.js new file mode 100644 index 000000000000..19f837942515 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-b/_config.js @@ -0,0 +1,42 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

Foo: yes

+

x in parent: yes

+ `, + + async test({ assert, component, target }) { + component.a = false; + + assert.htmlEqual( + target.innerHTML, + ` +

Bar: yes

+

x in parent: yes

+ ` + ); + + component.a = true; + assert.equal(component.x, 'yes'); + component.x = undefined; + + assert.htmlEqual( + target.innerHTML, + ` +

Foo:

+

x in parent:

+ ` + ); + + component.a = false; + + assert.htmlEqual( + target.innerHTML, + ` +

Bar: no

+

x in parent: no

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-parent-supercedes-child-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-b/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-parent-supercedes-child-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-b/main.svelte diff --git a/test/runtime/samples/component-binding-parent-supercedes-child-c/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-c/Bar.svelte similarity index 100% rename from test/runtime/samples/component-binding-parent-supercedes-child-c/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-c/Bar.svelte diff --git a/test/runtime/samples/component-binding-parent-supercedes-child-c/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-c/Foo.svelte similarity index 100% rename from test/runtime/samples/component-binding-parent-supercedes-child-c/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-c/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-c/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-c/_config.js new file mode 100644 index 000000000000..19f837942515 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-c/_config.js @@ -0,0 +1,42 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

Foo: yes

+

x in parent: yes

+ `, + + async test({ assert, component, target }) { + component.a = false; + + assert.htmlEqual( + target.innerHTML, + ` +

Bar: yes

+

x in parent: yes

+ ` + ); + + component.a = true; + assert.equal(component.x, 'yes'); + component.x = undefined; + + assert.htmlEqual( + target.innerHTML, + ` +

Foo:

+

x in parent:

+ ` + ); + + component.a = false; + + assert.htmlEqual( + target.innerHTML, + ` +

Bar: no

+

x in parent: no

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-parent-supercedes-child-c/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-c/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-parent-supercedes-child-c/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child-c/main.svelte diff --git a/test/runtime/samples/component-binding-parent-supercedes-child/Counter.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child/Counter.svelte similarity index 100% rename from test/runtime/samples/component-binding-parent-supercedes-child/Counter.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child/Counter.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child/_config.js new file mode 100644 index 000000000000..fa20032eb074 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child/_config.js @@ -0,0 +1,39 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

count: 10

+ `, + + test({ assert, component, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + const button = target.querySelector('button'); + ok(button); + + button.dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 11); + assert.htmlEqual( + target.innerHTML, + ` + +

count: 11

+ ` + ); + + button.dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 12); + assert.htmlEqual( + target.innerHTML, + ` + +

count: 12

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-parent-supercedes-child/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-parent-supercedes-child/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-parent-supercedes-child/main.svelte diff --git a/test/runtime/samples/component-binding-private-state/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-private-state/Bar.svelte similarity index 100% rename from test/runtime/samples/component-binding-private-state/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-private-state/Bar.svelte diff --git a/test/runtime/samples/component-binding-private-state/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-private-state/Foo.svelte similarity index 100% rename from test/runtime/samples/component-binding-private-state/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-private-state/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-private-state/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-private-state/_config.js new file mode 100644 index 000000000000..7c140020a72e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-private-state/_config.js @@ -0,0 +1,42 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

Foo: yes

+

x in parent:

+ `, + + async test({ assert, component, target }) { + component.a = false; + + assert.htmlEqual( + target.innerHTML, + ` +

Bar: no

+

x in parent:

+ ` + ); + + component.a = true; + assert.equal(component.x, undefined); + component.x = 'maybe'; + + assert.htmlEqual( + target.innerHTML, + ` +

Foo: yes

+

x in parent: maybe

+ ` + ); + + component.a = false; + + assert.htmlEqual( + target.innerHTML, + ` +

Bar: no

+

x in parent: maybe

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-private-state/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-private-state/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-private-state/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-private-state/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-property-no-extra-call/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-property-no-extra-call/Component.svelte new file mode 100644 index 000000000000..f180f10cd848 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-property-no-extra-call/Component.svelte @@ -0,0 +1,6 @@ + + +{value}{value2} diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-property-no-extra-call/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-property-no-extra-call/_config.js new file mode 100644 index 000000000000..84b46c8d8208 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-property-no-extra-call/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, component }) { + assert.equal(component.object_updates, component.primitive_updates); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-property-no-extra-call/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-property-no-extra-call/main.svelte new file mode 100644 index 000000000000..8da96efa70dd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-property-no-extra-call/main.svelte @@ -0,0 +1,13 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-statement/Button.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-statement/Button.svelte new file mode 100644 index 000000000000..289ec42fabdc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-statement/Button.svelte @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-statement/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-statement/_config.js new file mode 100644 index 000000000000..dbd8a5d1a572 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-statement/_config.js @@ -0,0 +1,57 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + `, + + test({ assert, target, window }) { + const event = new window.MouseEvent('click', { bubbles: true }); + + const buttons = target.querySelectorAll('button'); + + buttons[0].dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + + buttons[1].dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + + // reactive update, reset to 2 + buttons[0].dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + + // bound to main, reset to 2 + buttons[1].dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-statement/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-statement/main.svelte new file mode 100644 index 000000000000..4253c6127e81 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-reactive-statement/main.svelte @@ -0,0 +1,19 @@ + + + + + + `, + + test({ assert, component, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + + target.querySelector('button')?.dispatchEvent(click); + flushSync(); + + assert.equal(component.show, false); + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + + target.querySelector('button')?.dispatchEvent(click); + flushSync(); + + assert.equal(component.show, true); + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/component-binding-self-destroying/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-self-destroying/main.svelte similarity index 100% rename from test/runtime/samples/component-binding-self-destroying/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding-self-destroying/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-store/Input.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-store/Input.svelte new file mode 100644 index 000000000000..792104bec8c0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-store/Input.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-store/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding-store/_config.js new file mode 100644 index 000000000000..dfa86868ffce --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-store/_config.js @@ -0,0 +1,72 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + +
+ `, + ssrHtml: ` + + +
+ `, + + test({ assert, component, target, window }) { + let count = 0; + component.callback = () => { + count++; + }; + + const [input1, input2] = target.querySelectorAll('input'); + + input1.value = '1'; + input1.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + +
1
+ ` + ); + assert.equal(input1.value, '1'); + assert.equal(input2.value, '1'); + assert.equal(count, 1); + + input2.value = '123'; + input2.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + +
123
+ ` + ); + assert.equal(input1.value, '123'); + assert.equal(input2.value, '123'); + assert.equal(count, 2); + + input1.value = '456'; + input1.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + +
456
+ ` + ); + assert.equal(input1.value, '456'); + assert.equal(input2.value, '456'); + assert.equal(count, 3); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding-store/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding-store/main.svelte new file mode 100644 index 000000000000..dba08e527680 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding-store/main.svelte @@ -0,0 +1,18 @@ + + + + + + +
{$value.value}
\ No newline at end of file diff --git a/test/runtime/samples/component-binding/Counter.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding/Counter.svelte similarity index 100% rename from test/runtime/samples/component-binding/Counter.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding/Counter.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-binding/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-binding/_config.js new file mode 100644 index 000000000000..40eacb5a5d3f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-binding/_config.js @@ -0,0 +1,39 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

count: 0

+ `, + + test({ assert, component, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + const button = target.querySelector('button'); + ok(button); + + button.dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 1); + assert.htmlEqual( + target.innerHTML, + ` + +

count: 1

+ ` + ); + + button.dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 2); + assert.htmlEqual( + target.innerHTML, + ` + +

count: 2

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-binding/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-binding/main.svelte similarity index 100% rename from test/runtime/samples/component-binding/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-binding/main.svelte diff --git a/test/runtime/samples/component-data-dynamic-late/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-late/Widget.svelte similarity index 100% rename from test/runtime/samples/component-data-dynamic-late/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-late/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-late/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-late/_config.js new file mode 100644 index 000000000000..b6f1e79a8716 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-late/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component, target }) { + component.q = 42; + component.foo = true; + + assert.htmlEqual( + target.innerHTML, + ` +

42

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-data-dynamic-late/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-late/main.svelte similarity index 100% rename from test/runtime/samples/component-data-dynamic-late/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-late/main.svelte diff --git a/test/runtime/samples/component-data-dynamic-shorthand/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-shorthand/Widget.svelte similarity index 100% rename from test/runtime/samples/component-data-dynamic-shorthand/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-shorthand/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-shorthand/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-shorthand/_config.js new file mode 100644 index 000000000000..799842f2f345 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-shorthand/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: 42 }; + }, + + html: '

foo: 42

', + + test({ assert, component, target }) { + component.foo = 99; + + assert.htmlEqual(target.innerHTML, '

foo: 99

'); + } +}); diff --git a/test/runtime/samples/component-data-dynamic-shorthand/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-shorthand/main.svelte similarity index 100% rename from test/runtime/samples/component-data-dynamic-shorthand/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-dynamic-shorthand/main.svelte diff --git a/test/runtime/samples/component-data-dynamic/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic/Widget.svelte similarity index 100% rename from test/runtime/samples/component-data-dynamic/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-dynamic/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic/_config.js new file mode 100644 index 000000000000..96c54a0b7854 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic/_config.js @@ -0,0 +1,36 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + bar: 'lol', + x: 2, + compound: 'piece of', + go: { deeper: 'core' } + }; + }, + + html: ` +

foo: lol

+

baz: 42 (number)

+

qux: this is a piece of string

+

quux: core

+ `, + + test({ assert, component, target }) { + component.bar = 'wut'; + component.x = 3; + component.compound = 'rather boring'; + component.go = { deeper: 'heart' }; + + assert.htmlEqual( + target.innerHTML, + ` +

foo: wut

+

baz: 43 (number)

+

qux: this is a rather boring string

+

quux: heart

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-data-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/component-data-dynamic/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-dynamic/main.svelte diff --git a/test/runtime/samples/component-data-empty/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-empty/Widget.svelte similarity index 100% rename from test/runtime/samples/component-data-empty/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-empty/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-data-empty/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-data-empty/_config.js new file mode 100644 index 000000000000..0245f8c18773 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-data-empty/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: "

foo: ''

" +}); diff --git a/test/runtime/samples/component-data-empty/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-empty/main.svelte similarity index 100% rename from test/runtime/samples/component-data-empty/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-empty/main.svelte diff --git a/test/runtime/samples/component-data-static-boolean-regression/Link.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean-regression/Link.svelte similarity index 100% rename from test/runtime/samples/component-data-static-boolean-regression/Link.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean-regression/Link.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean-regression/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean-regression/_config.js new file mode 100644 index 000000000000..80327a1b270f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean-regression/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: "link" +}); diff --git a/test/runtime/samples/component-data-static-boolean-regression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean-regression/main.svelte similarity index 100% rename from test/runtime/samples/component-data-static-boolean-regression/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean-regression/main.svelte diff --git a/test/runtime/samples/component-data-static-boolean/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean/Foo.svelte similarity index 100% rename from test/runtime/samples/component-data-static-boolean/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean/_config.js new file mode 100644 index 000000000000..1882855b027f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

x: true (boolean)

' +}); diff --git a/test/runtime/samples/component-data-static-boolean/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean/main.svelte similarity index 100% rename from test/runtime/samples/component-data-static-boolean/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-static-boolean/main.svelte diff --git a/test/runtime/samples/component-data-static/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-static/Widget.svelte similarity index 100% rename from test/runtime/samples/component-data-static/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-static/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-data-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-data-static/_config.js new file mode 100644 index 000000000000..6369316f9988 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-data-static/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+

foo: bar

+

baz: 42 (number)

+
+ ` +}); diff --git a/test/runtime/samples/component-data-static/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-data-static/main.svelte similarity index 100% rename from test/runtime/samples/component-data-static/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-data-static/main.svelte diff --git a/test/runtime/samples/component-event-handler-modifier-once/Button.svelte b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-dynamic/Button.svelte similarity index 100% rename from test/runtime/samples/component-event-handler-modifier-once/Button.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-event-handler-dynamic/Button.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-event-handler-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-dynamic/_config.js new file mode 100644 index 000000000000..37e05c22ead8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-dynamic/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + `, + + async test({ assert, component, target, window }) { + const [updateButton, button] = target.querySelectorAll('button'); + const event = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(event); + assert.equal(component.count, 1); + + await updateButton.dispatchEvent(event); + await button.dispatchEvent(event); + assert.equal(component.count, 11); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-event-handler-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-dynamic/main.svelte new file mode 100644 index 000000000000..7555ea8c1731 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-dynamic/main.svelte @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once-dynamic/Button.svelte b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once-dynamic/Button.svelte new file mode 100644 index 000000000000..9b5b7a5f671b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once-dynamic/Button.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once-dynamic/_config.js new file mode 100644 index 000000000000..23c3748d597b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once-dynamic/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + `, + + async test({ assert, component, target, window }) { + const [updateButton, button] = target.querySelectorAll('button'); + const event = new window.MouseEvent('click', { bubbles: true }); + + await updateButton.dispatchEvent(event); + await button.dispatchEvent(event); + assert.equal(component.count, 10); + + await button.dispatchEvent(event); + assert.equal(component.count, 10); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once-dynamic/main.svelte new file mode 100644 index 000000000000..93ec90d5cef2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once-dynamic/main.svelte @@ -0,0 +1,11 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once/Button.svelte b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once/Button.svelte new file mode 100644 index 000000000000..9b5b7a5f671b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once/Button.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once/_config.js new file mode 100644 index 000000000000..412839c86dfc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once/_config.js @@ -0,0 +1,20 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(event); + assert.equal(component.count, 1); + + await button.dispatchEvent(event); + assert.equal(component.count, 1); + } +}); diff --git a/test/runtime/samples/component-event-handler-modifier-once/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once/main.svelte similarity index 100% rename from test/runtime/samples/component-event-handler-modifier-once/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-event-handler-modifier-once/main.svelte diff --git a/test/runtime/samples/component-event-not-stale/Button.svelte b/packages/svelte/tests/runtime-legacy/samples/component-event-not-stale/Button.svelte similarity index 100% rename from test/runtime/samples/component-event-not-stale/Button.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-event-not-stale/Button.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-event-not-stale/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-event-not-stale/_config.js new file mode 100644 index 000000000000..4528136839ab --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-event-not-stale/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { value: 1 }; + }, + + test({ assert, component, target, window }) { + const buttons = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + /** @type {Array<{ value: number }>} */ + const events = []; + component.$on('value', (/** @type {CustomEvent} */ event) => { + events.push(event.detail); + }); + + buttons[0].dispatchEvent(click); + buttons[1].dispatchEvent(click); + + component.value = 2; + + buttons[0].dispatchEvent(click); + buttons[1].dispatchEvent(click); + + assert.deepEqual(events, [{ value: 1 }, { value: 1 }, { value: 2 }, { value: 2 }]); + } +}); diff --git a/test/runtime/samples/component-event-not-stale/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-event-not-stale/main.svelte similarity index 100% rename from test/runtime/samples/component-event-not-stale/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-event-not-stale/main.svelte diff --git a/test/runtime/samples/component-events-console/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-console/Widget.svelte similarity index 100% rename from test/runtime/samples/component-events-console/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-events-console/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events-console/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-events-console/_config.js new file mode 100644 index 000000000000..89138a979b86 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events-console/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target }) { + const button = target.querySelector('button'); + + /** @type {string[]} */ + const messages = []; + + const log = console.log; + console.log = (msg) => { + messages.push(msg); + }; + + try { + button?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + assert.deepEqual(messages, ['clicked']); + } catch (err) { + console.log = log; + throw err; + } + + console.log = log; + } +}); diff --git a/test/runtime/samples/component-events-console/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-console/main.svelte similarity index 100% rename from test/runtime/samples/component-events-console/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-events-console/main.svelte diff --git a/test/runtime/samples/component-events-data/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-data/Widget.svelte similarity index 100% rename from test/runtime/samples/component-events-data/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-events-data/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events-data/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-events-data/_config.js new file mode 100644 index 000000000000..3b1dfe445097 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events-data/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component, target, window }) { + const buttons = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + /** @type {string[]} */ + const selected = []; + + component.$on('select', (/** @type {CustomEvent} */ event) => { + selected.push(event.detail); + }); + + buttons[1].dispatchEvent(click); + buttons[2].dispatchEvent(click); + buttons[1].dispatchEvent(click); + buttons[0].dispatchEvent(click); + + assert.deepEqual(selected, ['bar', 'baz', 'bar', 'foo']); + } +}); diff --git a/test/runtime/samples/component-events-data/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-data/main.svelte similarity index 100% rename from test/runtime/samples/component-events-data/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-events-data/main.svelte diff --git a/test/runtime/samples/component-events-each/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-each/Widget.svelte similarity index 100% rename from test/runtime/samples/component-events-each/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-events-each/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-events-each/_config.js new file mode 100644 index 000000000000..19fbc0e22a09 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events-each/_config.js @@ -0,0 +1,33 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { items: ['a', 'b', 'c'] }; + }, + + html: ` +
+ + + +
+ `, + + test({ assert, component, target, window }) { + const buttons = target.querySelectorAll('button'); + + /** @type {string[]} */ + const clicks = []; + + component.$on('foo', (/** @type {CustomEvent} */ event) => { + clicks.push(event.detail); + }); + + const event = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(event); + buttons[2].dispatchEvent(event); + + assert.deepEqual(clicks, ['a', 'c']); + } +}); diff --git a/test/runtime/samples/component-events-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-each/main.svelte similarity index 100% rename from test/runtime/samples/component-events-each/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-events-each/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events-nullish/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-nullish/Widget.svelte new file mode 100644 index 000000000000..4b368a6cddf9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events-nullish/Widget.svelte @@ -0,0 +1,14 @@ + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events-nullish/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-events-nullish/_config.js new file mode 100644 index 000000000000..717b988df10a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events-nullish/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, component, window, target }) { + const event = new window.MouseEvent('click', { bubbles: true }); + const button = target.querySelector('button'); + + await button?.dispatchEvent(event); + assert.equal(component.logs.length, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events-nullish/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-nullish/main.svelte new file mode 100644 index 000000000000..0dee33b5d11a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events-nullish/main.svelte @@ -0,0 +1,6 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events-this/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-this/Inner.svelte new file mode 100644 index 000000000000..0c5e27c76d16 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events-this/Inner.svelte @@ -0,0 +1,8 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events-this/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-this/Widget.svelte new file mode 100644 index 000000000000..30b95e94f16b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events-this/Widget.svelte @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-events-this/_config.js new file mode 100644 index 000000000000..aae633f58423 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events-this/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component, target, window }) { + const [button1, button2] = target.querySelectorAll('button'); + + button1.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + button2.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + + assert.strictEqual(component.logs[0], button1); + assert.ok(component.logs[1]?.exists); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events-this/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events-this/main.svelte new file mode 100644 index 000000000000..328a52436001 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events-this/main.svelte @@ -0,0 +1,16 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/component-events/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events/Widget.svelte similarity index 100% rename from test/runtime/samples/component-events/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-events/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-events/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-events/_config.js new file mode 100644 index 000000000000..b5fe0dfcab6b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-events/_config.js @@ -0,0 +1,26 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { visible: true }; + }, + + html: '

i am a widget

', + + test({ assert, component }) { + let count = 0; + + component.$on('widgetTornDown', function () { + // @ts-expect-error TODO + assert.equal(this, component); + count += 1; + }); + + component.visible = false; + assert.equal(count, 1); + + component.visible = true; + component.visible = false; + assert.equal(count, 2); + } +}); diff --git a/test/runtime/samples/component-events/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-events/main.svelte similarity index 100% rename from test/runtime/samples/component-events/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-events/main.svelte diff --git a/test/runtime/samples/component-if-placement/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/component-if-placement/Component.svelte similarity index 100% rename from test/runtime/samples/component-if-placement/Component.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-if-placement/Component.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-if-placement/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-if-placement/_config.js new file mode 100644 index 000000000000..dfc8eacda677 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-if-placement/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { flag: true }; + }, + + html: ` + Before + Component + After + `, + + test({ assert, component, target }) { + component.flag = false; + assert.htmlEqual( + target.innerHTML, + ` + Before + Component + After + ` + ); + } +}); diff --git a/test/runtime/samples/component-if-placement/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-if-placement/main.svelte similarity index 100% rename from test/runtime/samples/component-if-placement/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-if-placement/main.svelte diff --git a/test/runtime/samples/component-name-deconflicted-globals/Countdown.svelte b/packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted-globals/Countdown.svelte similarity index 100% rename from test/runtime/samples/component-name-deconflicted-globals/Countdown.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted-globals/Countdown.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted-globals/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted-globals/_config.js new file mode 100644 index 000000000000..da4fd19e248a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted-globals/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + error: 'Countdown is not defined' +}); diff --git a/test/runtime/samples/component-name-deconflicted-globals/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted-globals/main.svelte similarity index 100% rename from test/runtime/samples/component-name-deconflicted-globals/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted-globals/main.svelte diff --git a/test/runtime/samples/component-name-deconflicted/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted/Nested.svelte similarity index 100% rename from test/runtime/samples/component-name-deconflicted/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted/_config.js new file mode 100644 index 000000000000..ab78c6abdad6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` + 1 + 2 + `, + + test({ assert, component, target }) { + component.list = [3, 4]; + + assert.htmlEqual( + target.innerHTML, + ` + 3 + 4 + ` + ); + } +}); diff --git a/test/runtime/samples/component-name-deconflicted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted/main.svelte similarity index 100% rename from test/runtime/samples/component-name-deconflicted/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-name-deconflicted/main.svelte diff --git a/test/runtime/samples/component/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-namespace/Tooltip.svelte similarity index 100% rename from test/runtime/samples/component/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-namespace/Tooltip.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-namespace/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-namespace/Widget.svelte new file mode 100644 index 000000000000..d0003f9f3208 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-namespace/Widget.svelte @@ -0,0 +1,5 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-namespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-namespace/_config.js new file mode 100644 index 000000000000..3f15eec31d98 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-namespace/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

i am a widget

' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-namespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-namespace/main.svelte new file mode 100644 index 000000000000..3f53b2b1c815 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-namespace/main.svelte @@ -0,0 +1,8 @@ + + +{#each widgets as LazyWidget} + +{/each} \ No newline at end of file diff --git a/test/runtime/samples/component-namespaced/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-namespaced/Foo.svelte similarity index 100% rename from test/runtime/samples/component-namespaced/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-namespaced/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-namespaced/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-namespaced/_config.js new file mode 100644 index 000000000000..8517023e4a5a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-namespaced/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 1 }; + }, + + html: ` +

foo 1

+ `, + + test({ assert, component, target }) { + component.a = 2; + assert.htmlEqual( + target.innerHTML, + ` +

foo 2

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-namespaced/components.svelte b/packages/svelte/tests/runtime-legacy/samples/component-namespaced/components.svelte new file mode 100644 index 000000000000..3672036a534a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-namespaced/components.svelte @@ -0,0 +1,5 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-namespaced/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-namespaced/main.svelte new file mode 100644 index 000000000000..25862cf6f2b1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-namespaced/main.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/test/runtime/samples/component-nested-deep/Level1.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level1.svelte similarity index 92% rename from test/runtime/samples/component-nested-deep/Level1.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level1.svelte index 1889fa2bd05b..f0aa73f4f516 100644 --- a/test/runtime/samples/component-nested-deep/Level1.svelte +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level1.svelte @@ -5,4 +5,4 @@ - \ No newline at end of file + diff --git a/test/runtime/samples/component-nested-deep/Level2.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level2.svelte similarity index 85% rename from test/runtime/samples/component-nested-deep/Level2.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level2.svelte index 500c4c98874a..e2b38acd879e 100644 --- a/test/runtime/samples/component-nested-deep/Level2.svelte +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level2.svelte @@ -3,4 +3,4 @@ level 2 - \ No newline at end of file + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level3.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level3.svelte new file mode 100644 index 000000000000..f961776bd12a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/Level3.svelte @@ -0,0 +1 @@ +level 3 diff --git a/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/_config.js new file mode 100644 index 000000000000..62685edd8dd6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; +import { unmount } from 'svelte'; + +export default test({ + test({ component }) { + unmount(component.l1); + }, + + warnings: ['Tried to unmount a component that was not mounted'] +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/main.svelte new file mode 100644 index 000000000000..5c2407898e70 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deep/main.svelte @@ -0,0 +1,7 @@ + + + diff --git a/test/runtime/samples/component-nested-deeper/Level1.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/Level1.svelte similarity index 100% rename from test/runtime/samples/component-nested-deeper/Level1.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/Level1.svelte diff --git a/test/runtime/samples/component-nested-deeper/Level2.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/Level2.svelte similarity index 100% rename from test/runtime/samples/component-nested-deeper/Level2.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/Level2.svelte diff --git a/test/runtime/samples/component-nested-deeper/Level3.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/Level3.svelte similarity index 100% rename from test/runtime/samples/component-nested-deeper/Level3.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/Level3.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/_config.js new file mode 100644 index 000000000000..da197b75218e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { values: [1, 2, 3, 4] }; + }, + + test({ component }) { + component.values = [2, 3]; + } +}); diff --git a/test/runtime/samples/component-nested-deeper/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/main.svelte similarity index 100% rename from test/runtime/samples/component-nested-deeper/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-nested-deeper/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/Sub.svelte b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/Sub.svelte new file mode 100644 index 000000000000..dd6d0bb1a959 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/Sub.svelte @@ -0,0 +1 @@ +
Sub
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/_config.js new file mode 100644 index 000000000000..f4edaf522375 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client'], + + get props() { + return { selected: false }; + }, + error: '$$component is not a function' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/main.svelte new file mode 100644 index 000000000000..dec7e2af7918 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor/main.svelte @@ -0,0 +1,9 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-not-constructor2/Sub.svelte b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor2/Sub.svelte new file mode 100644 index 000000000000..dd6d0bb1a959 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor2/Sub.svelte @@ -0,0 +1 @@ +
Sub
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-not-constructor2/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor2/_config.js new file mode 100644 index 000000000000..ce75906162bf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor2/_config.js @@ -0,0 +1,23 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + // override process.env.HMR — this test only passes in prod mode because in dev mode we generate a helpful error + dev: false + }, + + get props() { + return { componentName: 'Sub' }; + }, + html: '
Sub
', + test({ assert, component, target }) { + component.componentName = 'Proxy'; + assert.htmlEqual(target.innerHTML, '
Sub
'); + try { + component.componentName = 'banana'; + throw new Error('Expected an error'); + } catch (err) { + assert.include(/** @type {Error} */ (err).message, '$$component is not a function'); + } + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-not-constructor2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor2/main.svelte new file mode 100644 index 000000000000..331fdfc385a3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-not-constructor2/main.svelte @@ -0,0 +1,14 @@ + + + diff --git a/test/runtime/samples/component-not-void/Link.svelte b/packages/svelte/tests/runtime-legacy/samples/component-not-void/Link.svelte similarity index 100% rename from test/runtime/samples/component-not-void/Link.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-not-void/Link.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-not-void/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-not-void/_config.js new file mode 100644 index 000000000000..a21f191ef0ca --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-not-void/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

Hello

' +}); diff --git a/test/runtime/samples/component-not-void/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-not-void/main.svelte similarity index 100% rename from test/runtime/samples/component-not-void/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-not-void/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-prop-object/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/component-prop-object/Child.svelte new file mode 100644 index 000000000000..fd191fa695e6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-prop-object/Child.svelte @@ -0,0 +1,5 @@ + + +child: {x.y} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-prop-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-prop-object/_config.js new file mode 100644 index 000000000000..96815e80f8a4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-prop-object/_config.js @@ -0,0 +1,12 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: `child: 0 parent: 0 `, + + test({ assert, target }) { + target.querySelector('button')?.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, `child: 1 parent: 1 `); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-prop-object/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-prop-object/main.svelte new file mode 100644 index 000000000000..82aa5864e691 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-prop-object/main.svelte @@ -0,0 +1,11 @@ + + + + +parent: {x.y} + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-props-added/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-props-added/_config.js new file mode 100644 index 000000000000..bed88245777f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-props-added/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return {}; + }, + + html: '', + + async test({ assert, component, target }) { + await component.$set({ message: 'goodbye' }); + + assert.htmlEqual(target.innerHTML, '

goodbye

'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-props-added/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-props-added/main.svelte new file mode 100644 index 000000000000..8ee7f80adffc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-props-added/main.svelte @@ -0,0 +1,3 @@ +{#if 'message' in $$props} +

{$$props.message}

+{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/component-props-mutated/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-props-mutated/_config.js new file mode 100644 index 000000000000..4a5c102ba2fe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-props-mutated/_config.js @@ -0,0 +1,26 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +const data = { + message: 'hello' +}; + +export default test({ + get props() { + data.message = 'hello'; + + return { + data + }; + }, + + html: '

hello

', + + test({ assert, component, target }) { + data.message = 'goodbye'; + component.$set({ data }); + flushSync(); + + assert.htmlEqual(target.innerHTML, '

goodbye

'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-props-mutated/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-props-mutated/main.svelte new file mode 100644 index 000000000000..30195a083646 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-props-mutated/main.svelte @@ -0,0 +1,5 @@ + + +

{data.message}

diff --git a/packages/svelte/tests/runtime-legacy/samples/component-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-props/_config.js new file mode 100644 index 000000000000..016af9b43379 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-props/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + accessors: false, + html: '', + async test({ assert, target, component }) { + component.$set({ + foo: 'bar', + visible: true + }); + await Promise.resolve(); + + assert.htmlEqual(target.innerHTML, '{"foo":"bar","visible":true} {"foo":"bar"}'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-props/main.svelte new file mode 100644 index 000000000000..2de3d4da5091 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-props/main.svelte @@ -0,0 +1,7 @@ + + +{#if visible} + {JSON.stringify($$props)} {JSON.stringify($$restProps)} +{/if} diff --git a/test/runtime/samples/component-ref/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-ref/Widget.svelte similarity index 100% rename from test/runtime/samples/component-ref/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-ref/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-ref/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-ref/_config.js new file mode 100644 index 000000000000..ec7fec32037c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-ref/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: '

i am a widget

', + + test({ assert, component }) { + const { widget } = component; + assert.ok(widget.isWidget); + } +}); diff --git a/test/runtime/samples/component-ref/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-ref/main.svelte similarity index 100% rename from test/runtime/samples/component-ref/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-ref/main.svelte diff --git a/test/runtime/samples/component-shorthand-import/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-shorthand-import/Widget.svelte similarity index 100% rename from test/runtime/samples/component-shorthand-import/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-shorthand-import/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-shorthand-import/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-shorthand-import/_config.js new file mode 100644 index 000000000000..b531a1d80380 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-shorthand-import/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

This is the widget.

' +}); diff --git a/test/runtime/samples/component-shorthand-import/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-shorthand-import/main.svelte similarity index 100% rename from test/runtime/samples/component-shorthand-import/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-shorthand-import/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-attribute-order/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-attribute-order/Component.svelte new file mode 100644 index 000000000000..55c0858fb9ef --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-attribute-order/Component.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-attribute-order/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-attribute-order/_config.js new file mode 100644 index 000000000000..a79720ea3e5e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-attribute-order/_config.js @@ -0,0 +1,19 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + + `, + test({ assert, target, window }) { + const [btn, btn1, btn2] = target.querySelectorAll('button'); + + btn.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + + assert.equal(btn1.disabled, true); + assert.equal(btn2.disabled, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-attribute-order/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-attribute-order/main.svelte new file mode 100644 index 000000000000..85f99d75793d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-attribute-order/main.svelte @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-chained/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-chained/Inner.svelte similarity index 100% rename from test/runtime/samples/component-slot-chained/Inner.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-chained/Inner.svelte diff --git a/test/runtime/samples/component-slot-chained/Outer.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-chained/Outer.svelte similarity index 100% rename from test/runtime/samples/component-slot-chained/Outer.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-chained/Outer.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-chained/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-chained/_config.js new file mode 100644 index 000000000000..3c289a24fd82 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-chained/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: 'one', + + test({ assert, component, target }) { + component.text = 'two'; + assert.htmlEqual(target.innerHTML, 'two'); + } +}); diff --git a/test/runtime/samples/component-slot-chained/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-chained/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-chained/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-chained/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/Hello.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/Hello.svelte new file mode 100644 index 000000000000..ba726f62c986 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/Hello.svelte @@ -0,0 +1,5 @@ + + +Hello {name} \ No newline at end of file diff --git a/test/runtime/samples/component-slot-named-b/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-named-b/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/_config.js new file mode 100644 index 000000000000..2cb64ab6ca8d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` + Hello world + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/main.svelte new file mode 100644 index 000000000000..494a50a86ce7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-b/main.svelte @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/Hello.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/Hello.svelte new file mode 100644 index 000000000000..28a2bb436a09 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/Hello.svelte @@ -0,0 +1 @@ +Hello \ No newline at end of file diff --git a/test/runtime/samples/component-slot-named-c/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-named-c/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/World.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/World.svelte new file mode 100644 index 000000000000..680e6dff5b12 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/World.svelte @@ -0,0 +1 @@ +world \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/_config.js new file mode 100644 index 000000000000..fc3a386827a9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` + Hello + world + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/main.svelte new file mode 100644 index 000000000000..4bf657d9cb80 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named-c/main.svelte @@ -0,0 +1,13 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/Bar.svelte new file mode 100644 index 000000000000..8124337d72c2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/Bar.svelte @@ -0,0 +1 @@ +

bar

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/Foo.svelte new file mode 100644 index 000000000000..998ea4094d49 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/Foo.svelte @@ -0,0 +1 @@ +

foo

\ No newline at end of file diff --git a/test/runtime/samples/component-slot-named/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-named/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/_config.js new file mode 100644 index 000000000000..39a8d592a607 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+ Hello +

bar

+

foo

+
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/main.svelte new file mode 100644 index 000000000000..c16f005d5d0f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-component-named/main.svelte @@ -0,0 +1,12 @@ + + + + Hello + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each-nested/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each-nested/Nested.svelte new file mode 100644 index 000000000000..d6e214a92636 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each-nested/Nested.svelte @@ -0,0 +1,14 @@ + + +{#each items as item (item)} + {#each keys as key (key)} + setKey(key, value, item)} /> + {/each} +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each-nested/_config.js new file mode 100644 index 000000000000..563efe099afe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each-nested/_config.js @@ -0,0 +1,36 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + + + `, + + async test({ assert, target, window, logs }) { + const [btn1, btn2, btn3, btn4] = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + await btn1.dispatchEvent(click); + assert.deepEqual(logs, ['setKey(a, value-a-c, c)']); + + await btn2.dispatchEvent(click); + assert.deepEqual(logs, ['setKey(a, value-a-c, c)', 'setKey(b, value-b-c, c)']); + + await btn3.dispatchEvent(click); + assert.deepEqual(logs, [ + 'setKey(a, value-a-c, c)', + 'setKey(b, value-b-c, c)', + 'setKey(a, value-a-d, d)' + ]); + + await btn4.dispatchEvent(click); + assert.deepEqual(logs, [ + 'setKey(a, value-a-c, c)', + 'setKey(b, value-b-c, c)', + 'setKey(a, value-a-d, d)', + 'setKey(b, value-b-d, d)' + ]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each-nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each-nested/main.svelte new file mode 100644 index 000000000000..187b4167d515 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each-nested/main.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each/Nested.svelte new file mode 100644 index 000000000000..f356bca0796a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each/Nested.svelte @@ -0,0 +1,11 @@ + + +{#each keys as key (key)} + setKey(key, value)} /> +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each/_config.js new file mode 100644 index 000000000000..7a3eec4eeba8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + `, + + async test({ assert, target, window, logs }) { + const [btn1, btn2] = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + await btn1.dispatchEvent(click); + assert.deepEqual(logs, ['setKey(a, value-a)']); + + await btn2.dispatchEvent(click); + assert.deepEqual(logs, ['setKey(a, value-a)', 'setKey(b, value-b)']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each/main.svelte new file mode 100644 index 000000000000..777ad5a0eec2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-each/main.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/Inner.svelte new file mode 100644 index 000000000000..41673867d2bf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/Inner.svelte @@ -0,0 +1,8 @@ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/Nested.svelte new file mode 100644 index 000000000000..4e63d7f3fc86 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/Nested.svelte @@ -0,0 +1,7 @@ + + + + set(key, value)} /> + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/_config.js new file mode 100644 index 000000000000..7a3eec4eeba8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + `, + + async test({ assert, target, window, logs }) { + const [btn1, btn2] = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + await btn1.dispatchEvent(click); + assert.deepEqual(logs, ['setKey(a, value-a)']); + + await btn2.dispatchEvent(click); + assert.deepEqual(logs, ['setKey(a, value-a)', 'setKey(b, value-b)']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/main.svelte new file mode 100644 index 000000000000..777ad5a0eec2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-context-props-let/main.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-default-in-each/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-default-in-each/Nested.svelte new file mode 100644 index 000000000000..d21684310196 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-default-in-each/Nested.svelte @@ -0,0 +1,11 @@ + + +{#each {length: 3} as _, i} + +{/each} + +{#await promise then value} + +{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-default-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-default-in-each/_config.js new file mode 100644 index 000000000000..d37451c4d790 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-default-in-each/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
0 -
+
1 -
+
2 -
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-default-in-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-default-in-each/main.svelte new file mode 100644 index 000000000000..2ff707e04db3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-default-in-each/main.svelte @@ -0,0 +1,7 @@ + + + +
{item} - {value}
+
\ No newline at end of file diff --git a/test/runtime/samples/component-slot-default/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-default/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-default/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-default/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-default/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-default/_config.js new file mode 100644 index 000000000000..a21f191ef0ca --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-default/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

Hello

' +}); diff --git a/test/runtime/samples/component-slot-default/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-default/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-default/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-default/main.svelte diff --git a/test/runtime/samples/component-slot-dynamic/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-dynamic/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-dynamic/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-dynamic/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-dynamic/_config.js new file mode 100644 index 000000000000..283046007acf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-dynamic/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

override default slot

+ `, + + test({ component }) { + component.nested.foo = 'b'; + } +}); diff --git a/test/runtime/samples/component-slot-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-dynamic/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-dynamic/main.svelte diff --git a/test/runtime/samples/component-slot-each-block/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-each-block/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-each-block/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-each-block/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-each-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-each-block/_config.js new file mode 100644 index 000000000000..53bfd5eaf3f0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-each-block/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { things: [1, 2, 3] }; + }, + + html: ` +
+ 1 + 2 + 3 +
`, + + test({ assert, component, target }) { + component.things = [1, 2, 3, 4]; + assert.htmlEqual( + target.innerHTML, + ` +
+ 1 + 2 + 3 + 4 +
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-each-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-each-block/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-each-block/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-each-block/main.svelte diff --git a/test/runtime/samples/component-slot-empty-b/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-empty-b/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-empty-b/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-empty-b/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-empty-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-empty-b/_config.js new file mode 100644 index 000000000000..20befef0b6da --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-empty-b/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
' +}); diff --git a/test/runtime/samples/component-slot-empty-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-empty-b/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-empty-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-empty-b/main.svelte diff --git a/test/runtime/samples/component-slot-empty/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-empty/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-empty/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-empty/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-empty/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-empty/_config.js new file mode 100644 index 000000000000..a0ab0a62a7cd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-empty/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

no slot here

' +}); diff --git a/test/runtime/samples/component-slot-empty/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-empty/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-empty/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-empty/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/Inner.svelte new file mode 100644 index 000000000000..d1c247ad35b0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/Inner.svelte @@ -0,0 +1,7 @@ + + + +{value} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/Outer.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/Outer.svelte new file mode 100644 index 000000000000..1e44ba4db722 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/Outer.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/_config.js new file mode 100644 index 000000000000..cdc011af820c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/_config.js @@ -0,0 +1,45 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ' ', + ssrHtml: ' ', + + test({ assert, target, component, window }) { + const [input1, input2, inputFallback] = target.querySelectorAll('input'); + + // TODO this works differently now, deduplicates to one subscription - ok? + // assert.equal(component.getSubscriberCount(), 3); + + input1.value = 'a'; + input1.dispatchEvent(new window.Event('input')); + flushSync(); + input1.value = 'ab'; + input1.dispatchEvent(new window.Event('input')); + flushSync(); + assert.equal(input1.value, 'ab'); + assert.equal(input2.value, 'ab'); + assert.equal(inputFallback.value, 'ab'); + + component.props = 'hello'; + + assert.htmlEqual( + target.innerHTML, + ` + hello + hello + + ` + ); + + component.fallback = 'world'; + assert.htmlEqual( + target.innerHTML, + ` + hello + hello + world + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/main.svelte new file mode 100644 index 000000000000..458366701534 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/main.svelte @@ -0,0 +1,23 @@ + + + + + + + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/store.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/store.svelte new file mode 100644 index 000000000000..ef5dc7e91ae0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-2/store.svelte @@ -0,0 +1,23 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-3/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-3/Inner.svelte new file mode 100644 index 000000000000..db2af272d2ca --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-3/Inner.svelte @@ -0,0 +1,6 @@ + +
Hello
+
world
+
Bye
+
World
+
diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-3/_config.js new file mode 100644 index 000000000000..2163757abb1a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-3/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
Hello World
+
Hello
world
Bye
World
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-3/main.svelte new file mode 100644 index 000000000000..eda7ea60e4dd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-3/main.svelte @@ -0,0 +1,9 @@ + + + +
Hello World
+
+ + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-4/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-4/Inner.svelte new file mode 100644 index 000000000000..9eb3ef140148 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-4/Inner.svelte @@ -0,0 +1,3 @@ + + + foobar \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-4/_config.js new file mode 100644 index 000000000000..c561492dd461 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-4/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` + foobar + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-4/main.svelte new file mode 100644 index 000000000000..206ce21def76 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-4/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/IconA.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/IconA.svelte new file mode 100644 index 000000000000..8921b6c531df --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/IconA.svelte @@ -0,0 +1 @@ +Icon A \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/IconB.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/IconB.svelte new file mode 100644 index 000000000000..8a1a95ead344 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/IconB.svelte @@ -0,0 +1 @@ +Icon B \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/Inner.svelte new file mode 100644 index 000000000000..bc4b224c234a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/Inner.svelte @@ -0,0 +1,13 @@ + + + +
+ + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/_config.js new file mode 100644 index 000000000000..cd1f446d0cd9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/_config.js @@ -0,0 +1,38 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +
Icon B
+ `, + + test({ assert, target, window }) { + const btn = target.querySelector('button'); + ok(btn); + + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + + btn.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +
Icon A
+ ` + ); + + btn.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +
Icon B
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/main.svelte new file mode 100644 index 000000000000..206ce21def76 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-5/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/Foo.svelte new file mode 100644 index 000000000000..0385342cef1b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/Foo.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/Inner.svelte new file mode 100644 index 000000000000..28f0fdd86944 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/Inner.svelte @@ -0,0 +1,9 @@ + + + + + {JSON.stringify($$props)} + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/_config.js new file mode 100644 index 000000000000..fac8e94fe9b3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/_config.js @@ -0,0 +1,31 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +// $$props reactivity in slot fallback +export default test({ + html: ` + + {"value":""} + `, + ssrHtml: ` + + {"value":""} + `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + input.value = 'abc'; + input.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + {"value":"abc"} + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/main.svelte new file mode 100644 index 000000000000..35abebef1014 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-6/main.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-empty/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-empty/Nested.svelte new file mode 100644 index 000000000000..9e6683feb77a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-empty/Nested.svelte @@ -0,0 +1,4 @@ +
+

default fallback content

+ bar fallback +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-empty/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-empty/_config.js new file mode 100644 index 000000000000..3cfb06129462 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-empty/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+

default fallback content

+ +
+ +
+

default fallback content

+ bar fallback +
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-empty/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-empty/main.svelte new file mode 100644 index 000000000000..7ae5f4c5d778 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback-empty/main.svelte @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/test/runtime/samples/component-slot-fallback/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-fallback/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-fallback/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback/_config.js new file mode 100644 index 000000000000..27879bc8f032 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+

not fallback

+

bar fallback content

+

foo fallback content

+
+ ` +}); diff --git a/test/runtime/samples/component-slot-fallback/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-fallback/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-fallback/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-fallback/main.svelte diff --git a/test/runtime/samples/component-slot-if-block-before-node/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-block-before-node/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-if-block-before-node/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-if-block-before-node/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-if-block-before-node/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-block-before-node/_config.js new file mode 100644 index 000000000000..d250bb639c51 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-block-before-node/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+

unconditional

+
`, + + test({ assert, component, target }) { + component.foo = true; + assert.htmlEqual( + target.innerHTML, + ` +
+

conditional

+

unconditional

+
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-if-block-before-node/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-block-before-node/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-if-block-before-node/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-if-block-before-node/main.svelte diff --git a/test/runtime/samples/component-slot-if-block/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-block/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-if-block/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-if-block/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-if-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-block/_config.js new file mode 100644 index 000000000000..680cc9be8117 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-block/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+

unconditional

+
`, + + test({ assert, component, target }) { + component.foo = true; + assert.htmlEqual( + target.innerHTML, + ` +
+

unconditional

+

conditional

+
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-if-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-block/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-if-block/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-if-block/main.svelte diff --git a/test/runtime/samples/component-slot-if-else-block-before-node/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-else-block-before-node/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-if-else-block-before-node/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-if-else-block-before-node/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-if-else-block-before-node/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-else-block-before-node/_config.js new file mode 100644 index 000000000000..d362aaa63be9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-else-block-before-node/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

disabled

+

unconditional

`, + + test({ assert, component, target }) { + component.enabled = true; + assert.htmlEqual( + target.innerHTML, + ` +

enabled

+

unconditional

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-if-else-block-before-node/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-if-else-block-before-node/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-if-else-block-before-node/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-if-else-block-before-node/main.svelte diff --git a/test/runtime/samples/component-slot-let-aliased/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-aliased/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-aliased/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-aliased/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-aliased/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-aliased/_config.js new file mode 100644 index 000000000000..53bfd5eaf3f0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-aliased/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { things: [1, 2, 3] }; + }, + + html: ` +
+ 1 + 2 + 3 +
`, + + test({ assert, component, target }) { + component.things = [1, 2, 3, 4]; + assert.htmlEqual( + target.innerHTML, + ` +
+ 1 + 2 + 3 + 4 +
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-let-aliased/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-aliased/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-aliased/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-aliased/main.svelte diff --git a/test/runtime/samples/component-slot-let-b/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-b/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-b/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-b/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-b/_config.js new file mode 100644 index 000000000000..bb699d4a9fd6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-b/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + 0 + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + button?.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + 1 + ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-let-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-b/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-b/main.svelte diff --git a/test/runtime/samples/component-slot-let-c/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-c/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-c/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-c/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-c/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-c/_config.js new file mode 100644 index 000000000000..51f2b473f414 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-c/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + 0 () + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + button?.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + 1 () + ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-let-c/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-c/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-c/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-c/main.svelte diff --git a/test/runtime/samples/component-slot-let-d/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-d/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-d/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-d/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-d/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-d/_config.js new file mode 100644 index 000000000000..47e917d43ab8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-d/_config.js @@ -0,0 +1,27 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
+

a

+
+ `, + + test({ assert, target, window }) { + const div = target.querySelector('div'); + const click = new window.MouseEvent('click', { bubbles: true }); + + div?.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+

b

+
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-let-d/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-d/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-d/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-d/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured-2/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured-2/Nested.svelte new file mode 100644 index 000000000000..5dfe32bc7ff6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured-2/Nested.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured-2/_config.js new file mode 100644 index 000000000000..e89458160f92 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured-2/_config.js @@ -0,0 +1,83 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
+ hello world 0 hello + +
+
+ hello world 0 hello + +
+
+ hello world 0 hello + +
+ `, + test({ assert, target, window }) { + const [button1, button2, button3] = target.querySelectorAll('button'); + const event = new window.MouseEvent('click', { bubbles: true }); + + button1.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +
+ hello world 1 hello + +
+
+ hello world 0 hello + +
+
+ hello world 0 hello + +
+ ` + ); + + button2.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +
+ hello world 1 hello + +
+
+ hello world 1 hello + +
+
+ hello world 0 hello + +
+ ` + ); + + button3.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +
+ hello world 1 hello + +
+
+ hello world 1 hello + +
+
+ hello world 1 hello + +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured-2/main.svelte new file mode 100644 index 000000000000..215a1390d90a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured-2/main.svelte @@ -0,0 +1,28 @@ + + +
+ + {pair[0]} {pair[1]} {c} {foo} + + + +
+ +
+ + {a} {b} {d} {foo} + + + +
+ +
+ + {a} {b} {e} {foo} + + + +
\ No newline at end of file diff --git a/test/runtime/samples/component-slot-let-destructured/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-destructured/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured/_config.js new file mode 100644 index 000000000000..018a34914cdb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + things: [{ num: 1 }, { num: 2 }, { num: 3 }] + }; + }, + + html: ` +
+ 1 + 2 + 3 +
`, + + test({ assert, component, target }) { + component.things = [{ num: 1 }, { num: 2 }, { num: 3 }, { num: 4 }]; + + assert.htmlEqual( + target.innerHTML, + ` +
+ 1 + 2 + 3 + 4 +
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-let-destructured/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-destructured/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-destructured/main.svelte diff --git a/test/runtime/samples/component-slot-let-e/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-e/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-e/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-e/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-e/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-e/_config.js new file mode 100644 index 000000000000..ac0b6717f1d5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-e/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+

foo

+
+ `, + + async test({ assert, target, window }) { + const div = target.querySelector('div'); + const click = new window.MouseEvent('click', { bubbles: true }); + + await div?.dispatchEvent(click); + + assert.htmlEqual( + target.innerHTML, + ` +
+

foo

+
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-let-e/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-e/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-e/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-e/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/A.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/A.svelte new file mode 100644 index 000000000000..79428b13ecd8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/A.svelte @@ -0,0 +1,9 @@ + + + + {reflected} + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/B.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/B.svelte new file mode 100644 index 000000000000..7a8dc596ba63 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/B.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/_config.js new file mode 100644 index 000000000000..155953b1bfe8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` + 1 + 1 + `, + + async test({ assert, target, component }) { + component.x = 2; + + assert.htmlEqual( + target.innerHTML, + ` + 2 + 2 + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/main.svelte new file mode 100644 index 000000000000..71362d9b4e2b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-f/main.svelte @@ -0,0 +1,8 @@ + + + + {reflected} + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/A.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/A.svelte new file mode 100644 index 000000000000..4f4ac95014bb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/A.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/_config.js new file mode 100644 index 000000000000..f3f5e04be1b1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/_config.js @@ -0,0 +1,32 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + 1 + 0 + `, + test({ assert, target, component, window }) { + component.x = 2; + + assert.htmlEqual( + target.innerHTML, + ` + 2 + 0 + ` + ); + + const span = target.querySelector('span'); + span?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + 2 + 2 + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/main.svelte new file mode 100644 index 000000000000..e7d4890e6bf0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-g/main.svelte @@ -0,0 +1,17 @@ + + + + y = reflected} + slot="foo" + let:reflected + class={reflected} + > + {reflected} + + +{ y } \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-binding/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-binding/Nested.svelte new file mode 100644 index 000000000000..96f7adcfc6ce --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-binding/Nested.svelte @@ -0,0 +1,9 @@ + + +
+ {#each items as item, index} + + {/each} +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-binding/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-binding/_config.js new file mode 100644 index 000000000000..864366e409b7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-binding/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+ + + +
+ `, + + ssrHtml: ` +
+ + + +
+ `, + + async test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + + inputs[2].value = 'd'; + await inputs[2].dispatchEvent(new window.Event('input')); + + assert.deepEqual(component.letters, ['a', 'b', 'd']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-binding/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-binding/main.svelte new file mode 100644 index 000000000000..89531bf23606 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-binding/main.svelte @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/Inner.svelte new file mode 100644 index 000000000000..d0ea817d547f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/Inner.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/Outer.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/Outer.svelte new file mode 100644 index 000000000000..590a70564a8f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/Outer.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/_config.js new file mode 100644 index 000000000000..7ec1958a764a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/_config.js @@ -0,0 +1,31 @@ +import { ok, test } from '../../test'; + +/** @type {string[]} */ +let logs; + +/** @param {string} value */ +function log(value) { + logs.push(value); +} + +export default test({ + get props() { + return { prop: 'a', log }; + }, + html: '', + before_test() { + logs = []; + }, + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + await button.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + + assert.deepEqual(logs, ['a']); + + component.prop = 'b'; + await button.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + assert.deepEqual(logs, ['a', 'b']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/main.svelte new file mode 100644 index 000000000000..c26c24c937ab --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot-2/main.svelte @@ -0,0 +1,11 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/Inner.svelte new file mode 100644 index 000000000000..d0ea817d547f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/Inner.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/Outer.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/Outer.svelte new file mode 100644 index 000000000000..590a70564a8f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/Outer.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/_config.js new file mode 100644 index 000000000000..8abde3dd3f30 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { prop: 'a' }; + }, + + html: 'a', + + test({ assert, component, target }) { + component.prop = 'b'; + assert.htmlEqual(target.innerHTML, 'b'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/main.svelte new file mode 100644 index 000000000000..7ebb4ebc21c5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-in-slot/main.svelte @@ -0,0 +1,10 @@ + + + + {value} + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/Inner.svelte new file mode 100644 index 000000000000..5a30e1855b69 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/Inner.svelte @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/Outer.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/Outer.svelte new file mode 100644 index 000000000000..40ed99ca63c9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/Outer.svelte @@ -0,0 +1,12 @@ + + + + + innerCall(a)} /> + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/_config.js new file mode 100644 index 000000000000..08aaa1ce4455 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/_config.js @@ -0,0 +1,32 @@ +import { ok, test } from '../../test'; + +/** @type {string[]} */ +let logs; + +/** @param {string} value */ +function log(value) { + logs.push(value); +} + +export default test({ + html: '', + get props() { + return { a: 'a', b: 'b', log }; + }, + before_test() { + logs = []; + }, + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + await button.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + + assert.deepEqual(logs, ['a: a, b: b']); + + component.a = '1'; + component.b = '2'; + await button.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + assert.deepEqual(logs, ['a: a, b: b', 'a: 1, b: 2']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/main.svelte new file mode 100644 index 000000000000..6ea417d0f29e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-inline-function/main.svelte @@ -0,0 +1,12 @@ + + + + + diff --git a/test/runtime/samples/each-block-empty-outro/Thing.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/Bar.svelte similarity index 100% rename from test/runtime/samples/each-block-empty-outro/Thing.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/Bar.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/Foo.svelte new file mode 100644 index 000000000000..49aeb95a1db9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/Foo.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/_config.js new file mode 100644 index 000000000000..04c9868ac378 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/main.svelte new file mode 100644 index 000000000000..3ac3ba53637e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-missing-prop/main.svelte @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-mutated/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-mutated/Nested.svelte new file mode 100644 index 000000000000..e1a46088ef10 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-mutated/Nested.svelte @@ -0,0 +1,9 @@ + + +
+ {#each things as thing} + + {/each} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-mutated/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-mutated/_config.js new file mode 100644 index 000000000000..165bbbf58607 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-mutated/_config.js @@ -0,0 +1,25 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +
+ hello +
+ `, + + async test({ assert, target }) { + target.querySelector('button')?.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + +
+ bye +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-mutated/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-mutated/main.svelte new file mode 100644 index 000000000000..9f9eafcd7e69 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-mutated/main.svelte @@ -0,0 +1,10 @@ + + + + + {thing.text} + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/Nested.svelte new file mode 100644 index 000000000000..a38e459bcdc6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/Nested.svelte @@ -0,0 +1,9 @@ + + +
+ {#each things as thing} + + {/each} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/SlotInner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/SlotInner.svelte new file mode 100644 index 000000000000..3dd035e95b62 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/SlotInner.svelte @@ -0,0 +1,5 @@ + +{thing} + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/_config.js new file mode 100644 index 000000000000..e5518ab8135f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/_config.js @@ -0,0 +1,36 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { things: [1, 2, 3] }; + }, + + html: ` +
+ 1 +
1
+ 2 +
2
+ 3 +
3
+
`, + + test({ assert, component, target }) { + component.things = [1, 2, 3, 4]; + assert.htmlEqual( + target.innerHTML, + ` +
+ 1 +
1
+ 2 +
2
+ 3 +
3
+ 4 +
4
+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/main.svelte new file mode 100644 index 000000000000..1b89f546939c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named-2/main.svelte @@ -0,0 +1,12 @@ + + + + +
{data}
+
+
diff --git a/test/runtime/samples/component-slot-let-named/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-named/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-named/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named/_config.js new file mode 100644 index 000000000000..1261875be307 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { things: [1, 2, 3] }; + }, + + html: ` +
+
1
+
2
+
3
+
`, + + test({ assert, component, target }) { + component.things = [1, 2, 3, 4]; + assert.htmlEqual( + target.innerHTML, + ` +
+
1
+
2
+
3
+
4
+
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-let-named/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-named/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-named/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-named/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-2/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-2/Nested.svelte new file mode 100644 index 000000000000..e231bf1a7feb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-2/Nested.svelte @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-2/_config.js new file mode 100644 index 000000000000..5318961ef0d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-2/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '2' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-2/main.svelte new file mode 100644 index 000000000000..8454c4acd178 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-2/main.svelte @@ -0,0 +1,8 @@ + + + + {thing} + {thing} + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-3/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-3/Nested.svelte new file mode 100644 index 000000000000..cecce8db0196 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-3/Nested.svelte @@ -0,0 +1,15 @@ + + +
+ + + + + +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-3/_config.js new file mode 100644 index 000000000000..44a820edc8fd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-3/_config.js @@ -0,0 +1,33 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` +
+

count in default slot: 0

+

count in foo slot: 0

+

count in bar slot: 42

+ +
+ `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + button.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+

count in default slot: 1

+

count in foo slot: 1

+

count in bar slot: 42

+ +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-3/main.svelte new file mode 100644 index 000000000000..5e7d3def541d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-3/main.svelte @@ -0,0 +1,18 @@ + + + +

+ count in default slot: {count} +

+ +

+ count in foo slot: {count} +

+ +

+ count in bar slot: {count} +

+
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/Nested.svelte new file mode 100644 index 000000000000..5811f40c6aef --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/Nested.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/Nested2.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/Nested2.svelte new file mode 100644 index 000000000000..f4575dc01cbe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/Nested2.svelte @@ -0,0 +1,9 @@ + + +
+ {text} +
+ +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/_config.js new file mode 100644 index 000000000000..18dd268adae2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
hello world
hello world
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/main.svelte new file mode 100644 index 000000000000..12d231dbbed1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-4/main.svelte @@ -0,0 +1,12 @@ + + + + +
+ {text} +
+
+
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/Nested.svelte new file mode 100644 index 000000000000..7e2ade56ef39 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/Nested.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/Nested2.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/Nested2.svelte new file mode 100644 index 000000000000..55c0858fb9ef --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/Nested2.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/_config.js new file mode 100644 index 000000000000..090d8aaf5dcb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
hello hello
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/main.svelte new file mode 100644 index 000000000000..5e78605b4653 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope-5/main.svelte @@ -0,0 +1,13 @@ + + + + +
+ {@const text2 = text} + {text} {text2} +
+
+
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope/Nested.svelte new file mode 100644 index 000000000000..772955e06efa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope/Nested.svelte @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope/_config.js new file mode 100644 index 000000000000..c78900821ac7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + error: 'thing is not defined' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope/main.svelte new file mode 100644 index 000000000000..e10a9a858491 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-scope/main.svelte @@ -0,0 +1,8 @@ + + + + {thing} + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-let-static/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-static/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-static/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-static/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-static/_config.js new file mode 100644 index 000000000000..f533efa06704 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-static/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

Hi

' +}); diff --git a/test/runtime/samples/component-slot-let-static/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let-static/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-let-static/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let-static/main.svelte diff --git a/test/runtime/samples/component-slot-let/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-let/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-let/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-let/_config.js new file mode 100644 index 000000000000..53bfd5eaf3f0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-let/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { things: [1, 2, 3] }; + }, + + html: ` +
+ 1 + 2 + 3 +
`, + + test({ assert, component, target }) { + component.things = [1, 2, 3, 4]; + assert.htmlEqual( + target.innerHTML, + ` +
+ 1 + 2 + 3 + 4 +
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-let/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-let/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-let/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-let/main.svelte diff --git a/test/runtime/samples/component-slot-name-with-hyphen/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-name-with-hyphen/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-name-with-hyphen/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-name-with-hyphen/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-name-with-hyphen/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-name-with-hyphen/_config.js new file mode 100644 index 000000000000..2c0244cb28f9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-name-with-hyphen/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

Hello

' +}); diff --git a/test/runtime/samples/component-slot-name-with-hyphen/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-name-with-hyphen/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-name-with-hyphen/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-name-with-hyphen/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-named-b/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-b/Nested.svelte new file mode 100644 index 000000000000..a94392ce5d82 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-b/Nested.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-named-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-b/_config.js new file mode 100644 index 000000000000..a27bfcbdf7cf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-b/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` + Hello world + ` +}); diff --git a/test/runtime/samples/component-slot-named-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-b/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-named-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-named-b/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-named-c/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-c/Nested.svelte new file mode 100644 index 000000000000..a94392ce5d82 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-c/Nested.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-named-c/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-c/_config.js new file mode 100644 index 000000000000..91d429a70194 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-c/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` + Hello + world + ` +}); diff --git a/test/runtime/samples/component-slot-named-c/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-c/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-named-c/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-named-c/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/Child.svelte new file mode 100644 index 000000000000..c46c742315a1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/Child.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/Parent.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/Parent.svelte new file mode 100644 index 000000000000..1d9ecbcc2dc8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/Parent.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/_config.js new file mode 100644 index 000000000000..f11eb14e71cd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/_config.js @@ -0,0 +1,12 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, logs, target }) { + const btn = target.querySelector('button'); + + btn?.click(); + flushSync(); + assert.deepEqual(logs, [1]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/main.svelte new file mode 100644 index 000000000000..d0a38e4d08e3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-named-scope/main.svelte @@ -0,0 +1,8 @@ + + + + console.log(item)}>asd + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-named/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-named/Nested.svelte new file mode 100644 index 000000000000..665555820a3d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-named/Nested.svelte @@ -0,0 +1,5 @@ +
+ + + +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-named/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-named/_config.js new file mode 100644 index 000000000000..dbb34af8e133 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-named/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+ Hello +

bar

+

foo

+
+ ` +}); diff --git a/test/runtime/samples/component-slot-named/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-named/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-named/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-named/main.svelte diff --git a/test/runtime/samples/component-slot-names-sanitized/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-names-sanitized/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-names-sanitized/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-names-sanitized/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-names-sanitized/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-names-sanitized/_config.js new file mode 100644 index 000000000000..884621a9ee55 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-names-sanitized/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+

Header 1

+

Header 2

+

Header 3

+

Header 4

+
Header 5
+
Header 5b
+
+ ` +}); diff --git a/test/runtime/samples/component-slot-names-sanitized/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-names-sanitized/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-names-sanitized/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-names-sanitized/main.svelte diff --git a/test/runtime/samples/component-slot-nested-component/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-component/Inner.svelte similarity index 100% rename from test/runtime/samples/component-slot-nested-component/Inner.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-nested-component/Inner.svelte diff --git a/test/runtime/samples/component-slot-nested-component/Outer.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-component/Outer.svelte similarity index 100% rename from test/runtime/samples/component-slot-nested-component/Outer.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-nested-component/Outer.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-component/_config.js new file mode 100644 index 000000000000..da28302ea171 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-component/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+
foo
+
` +}); diff --git a/test/runtime/samples/component-slot-nested-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-component/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-nested-component/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-nested-component/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/Display.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/Display.svelte new file mode 100644 index 000000000000..d9034e4be29a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/Display.svelte @@ -0,0 +1,2 @@ +Display: + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/Input.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/Input.svelte new file mode 100644 index 000000000000..fd8f22db004c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/Input.svelte @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/_config.js new file mode 100644 index 000000000000..2ea0504dda93 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/_config.js @@ -0,0 +1,36 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + input.value = 'a'; + input.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + Display: a + ` + ); + + input.value = 'abc'; + input.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + Display: abc + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/main.svelte new file mode 100644 index 000000000000..727927b15714 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-if/main.svelte @@ -0,0 +1,10 @@ + + + + {#if foo} + {foo} + {/if} + diff --git a/test/runtime/samples/component-slot-nested-in-element/One.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-element/One.svelte similarity index 100% rename from test/runtime/samples/component-slot-nested-in-element/One.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-element/One.svelte diff --git a/test/runtime/samples/component-slot-nested-in-element/Two.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-element/Two.svelte similarity index 100% rename from test/runtime/samples/component-slot-nested-in-element/Two.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-element/Two.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-element/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-element/_config.js new file mode 100644 index 000000000000..f7692c52b497 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-element/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+
+
a
+
+
+ ` +}); diff --git a/test/runtime/samples/component-slot-nested-in-element/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-element/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-nested-in-element/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-element/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/One.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/One.svelte new file mode 100644 index 000000000000..acb6a03358be --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/One.svelte @@ -0,0 +1,10 @@ + + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/Two.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/Two.svelte new file mode 100644 index 000000000000..3f21e2d16f21 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/Two.svelte @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/_config.js new file mode 100644 index 000000000000..ba022ffa34d5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/_config.js @@ -0,0 +1,26 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

one: 1 two: 2

+ `, + test({ assert, component, target }) { + component.a = 3; + component.b = 4; + assert.htmlEqual( + target.innerHTML, + ` +

one: 3 two: 4

+ ` + ); + + component.a = 5; + component.b = 6; + assert.htmlEqual( + target.innerHTML, + ` +

one: 5 two: 6

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/main.svelte new file mode 100644 index 000000000000..38a172e6687f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested-in-slot/main.svelte @@ -0,0 +1,9 @@ + + + +

one: {one} two: {two}

+
\ No newline at end of file diff --git a/test/runtime/samples/component-slot-nested/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-nested/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-nested/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested/_config.js new file mode 100644 index 000000000000..c42c205e4213 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+

bar

+
` +}); diff --git a/test/runtime/samples/component-slot-nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-nested/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-nested/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-nested/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/Component.svelte new file mode 100644 index 000000000000..fdcb8e7f2b7d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/Component.svelte @@ -0,0 +1,3 @@ +
+ +
diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/Forward.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/Forward.svelte new file mode 100644 index 000000000000..320be9df2506 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/Forward.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/_config.js new file mode 100644 index 000000000000..bdfb18a5c911 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
lol
' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/main.svelte new file mode 100644 index 000000000000..1718494b16dc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-slot/main.svelte @@ -0,0 +1,9 @@ + + + + + lol + + diff --git a/test/runtime/samples/component-slot-spread-props/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-spread-props/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-spread-props/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-spread-props/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-spread-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-spread-props/_config.js new file mode 100644 index 000000000000..b8116f2fdc98 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-spread-props/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+ +
+
+ `, + ssrHtml: ` +
+ +
+
+ `, + + async test({ assert, component, target }) { + component.value = 'foo'; + + assert.htmlEqual( + target.innerHTML, + ` +
+ +
+
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-spread-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-spread-props/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-spread-props/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-spread-props/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-spread/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-spread/Nested.svelte new file mode 100644 index 000000000000..597f7bbb1b41 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-spread/Nested.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-spread/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-spread/_config.js new file mode 100644 index 000000000000..696a5703d524 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-spread/_config.js @@ -0,0 +1,75 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {Record} */ + obj: { a: 1, b: 42 }, + c: 5, + d: 10 + }; + }, + html: ` +

1

+

42

+

5

+

10

+ `, + + test({ assert, target, component }) { + component.obj = { a: 2, b: 50, c: 30 }; + assert.htmlEqual( + target.innerHTML, + ` +

2

+

50

+

30

+

10

+ ` + ); + + component.c = 22; + assert.htmlEqual( + target.innerHTML, + ` +

2

+

50

+

30

+

10

+ ` + ); + + component.d = 44; + assert.htmlEqual( + target.innerHTML, + ` +

2

+

50

+

30

+

44

+ ` + ); + + component.obj = { a: 9, b: 12 }; + assert.htmlEqual( + target.innerHTML, + ` +

9

+

12

+

22

+

44

+ ` + ); + + component.c = 88; + assert.htmlEqual( + target.innerHTML, + ` +

9

+

12

+

88

+

44

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-spread/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-spread/main.svelte new file mode 100644 index 000000000000..36326dd4ad6d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-spread/main.svelte @@ -0,0 +1,14 @@ + + + +

{a}

+

{b}

+

{c}

+

{d}

+
\ No newline at end of file diff --git a/test/runtime/samples/component-slot-static-and-dynamic/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-static-and-dynamic/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-static-and-dynamic/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-static-and-dynamic/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-static-and-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-static-and-dynamic/_config.js new file mode 100644 index 000000000000..2120bdd0183e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-static-and-dynamic/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+ static + 0 +
+ `, + + test({ assert, component, target }) { + component.dynamic += 1; + + assert.htmlEqual( + target.innerHTML, + ` +
+ static + 1 +
+ ` + ); + } +}); diff --git a/test/runtime/samples/component-slot-static-and-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-static-and-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-static-and-dynamic/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-static-and-dynamic/main.svelte diff --git a/test/runtime/samples/component-slot-used-with-default-event/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-used-with-default-event/Nested.svelte similarity index 100% rename from test/runtime/samples/component-slot-used-with-default-event/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-used-with-default-event/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-slot-used-with-default-event/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-slot-used-with-default-event/_config.js new file mode 100644 index 000000000000..a21f191ef0ca --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-slot-used-with-default-event/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

Hello

' +}); diff --git a/test/runtime/samples/component-slot-used-with-default-event/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-slot-used-with-default-event/main.svelte similarity index 100% rename from test/runtime/samples/component-slot-used-with-default-event/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-slot-used-with-default-event/main.svelte diff --git a/test/runtime/samples/component-static-at-symbol/Email.svelte b/packages/svelte/tests/runtime-legacy/samples/component-static-at-symbol/Email.svelte similarity index 100% rename from test/runtime/samples/component-static-at-symbol/Email.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-static-at-symbol/Email.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-static-at-symbol/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-static-at-symbol/_config.js new file mode 100644 index 000000000000..471c5ea82ee8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-static-at-symbol/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: "email" +}); diff --git a/test/runtime/samples/component-static-at-symbol/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-static-at-symbol/main.svelte similarity index 100% rename from test/runtime/samples/component-static-at-symbol/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-static-at-symbol/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-2/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-2/Nested.svelte new file mode 100644 index 000000000000..a94392ce5d82 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-2/Nested.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-2/_config.js new file mode 100644 index 000000000000..fc3a386827a9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-2/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` + Hello + world + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-2/main.svelte new file mode 100644 index 000000000000..8212f54cf849 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-2/main.svelte @@ -0,0 +1,15 @@ + + + + + Hello + + + + + + world + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-aliased/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-aliased/Nested.svelte new file mode 100644 index 000000000000..6eaf6fe3adcb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-aliased/Nested.svelte @@ -0,0 +1,9 @@ + + +
+ {#each things as thing} + + {/each} +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-aliased/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-aliased/_config.js new file mode 100644 index 000000000000..53bfd5eaf3f0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-aliased/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { things: [1, 2, 3] }; + }, + + html: ` +
+ 1 + 2 + 3 +
`, + + test({ assert, component, target }) { + component.things = [1, 2, 3, 4]; + assert.htmlEqual( + target.innerHTML, + ` +
+ 1 + 2 + 3 + 4 +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-aliased/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-aliased/main.svelte new file mode 100644 index 000000000000..5ca0cbbd100c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-aliased/main.svelte @@ -0,0 +1,11 @@ + + + + + {x} + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-b/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-b/Nested.svelte new file mode 100644 index 000000000000..36c10ecbc215 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-b/Nested.svelte @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-b/_config.js new file mode 100644 index 000000000000..bb699d4a9fd6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-b/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + 0 + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + button?.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + 1 + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-b/main.svelte new file mode 100644 index 000000000000..bb24b97a3b15 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-b/main.svelte @@ -0,0 +1,9 @@ + + + + + {count} + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-c/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-c/Nested.svelte new file mode 100644 index 000000000000..122044059048 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-c/Nested.svelte @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-c/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-c/_config.js new file mode 100644 index 000000000000..51f2b473f414 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-c/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + 0 () + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + button?.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + 1 () + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-c/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-c/main.svelte new file mode 100644 index 000000000000..9753c45075d5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-c/main.svelte @@ -0,0 +1,9 @@ + + + + + {c} ({count}) + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-d/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-d/Nested.svelte new file mode 100644 index 000000000000..9f3a345acdd5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-d/Nested.svelte @@ -0,0 +1,7 @@ + + +
+ +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-d/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-d/_config.js new file mode 100644 index 000000000000..47e917d43ab8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-d/_config.js @@ -0,0 +1,27 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
+

a

+
+ `, + + test({ assert, target, window }) { + const div = target.querySelector('div'); + const click = new window.MouseEvent('click', { bubbles: true }); + + div?.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+

b

+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-d/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-d/main.svelte new file mode 100644 index 000000000000..7ba94c7b8ad7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-d/main.svelte @@ -0,0 +1,9 @@ + + + + +

{bar}

+
+
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured-2/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured-2/Nested.svelte new file mode 100644 index 000000000000..f46046c78e6f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured-2/Nested.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured-2/_config.js new file mode 100644 index 000000000000..e89458160f92 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured-2/_config.js @@ -0,0 +1,83 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
+ hello world 0 hello + +
+
+ hello world 0 hello + +
+
+ hello world 0 hello + +
+ `, + test({ assert, target, window }) { + const [button1, button2, button3] = target.querySelectorAll('button'); + const event = new window.MouseEvent('click', { bubbles: true }); + + button1.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +
+ hello world 1 hello + +
+
+ hello world 0 hello + +
+
+ hello world 0 hello + +
+ ` + ); + + button2.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +
+ hello world 1 hello + +
+
+ hello world 1 hello + +
+
+ hello world 0 hello + +
+ ` + ); + + button3.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +
+ hello world 1 hello + +
+
+ hello world 1 hello + +
+
+ hello world 1 hello + +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured-2/main.svelte new file mode 100644 index 000000000000..d4d399188169 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured-2/main.svelte @@ -0,0 +1,34 @@ + + +
+ + + {pair[0]} {pair[1]} {c} {foo} + + + + +
+ +
+ + + {a} {b} {d} {foo} + + + + +
+ +
+ + + {a} {b} {e} {foo} + + + + +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured/Nested.svelte new file mode 100644 index 000000000000..99afb32aa068 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured/Nested.svelte @@ -0,0 +1,9 @@ + + +
+ {#each things as thing} + + {/each} +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured/_config.js new file mode 100644 index 000000000000..018a34914cdb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + things: [{ num: 1 }, { num: 2 }, { num: 3 }] + }; + }, + + html: ` +
+ 1 + 2 + 3 +
`, + + test({ assert, component, target }) { + component.things = [{ num: 1 }, { num: 2 }, { num: 3 }, { num: 4 }]; + + assert.htmlEqual( + target.innerHTML, + ` +
+ 1 + 2 + 3 + 4 +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured/main.svelte new file mode 100644 index 000000000000..923e96311c0e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-destructured/main.svelte @@ -0,0 +1,11 @@ + + + + + {num} + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/A.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/A.svelte new file mode 100644 index 000000000000..f982aef7b14b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/A.svelte @@ -0,0 +1,11 @@ + + + + + {reflected} + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/B.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/B.svelte new file mode 100644 index 000000000000..352f10a24947 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/B.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/_config.js new file mode 100644 index 000000000000..155953b1bfe8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` + 1 + 1 + `, + + async test({ assert, target, component }) { + component.x = 2; + + assert.htmlEqual( + target.innerHTML, + ` + 2 + 2 + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/main.svelte new file mode 100644 index 000000000000..e95c8d927414 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-e/main.svelte @@ -0,0 +1,10 @@ + + + + + {reflected} + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-f/A.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-f/A.svelte new file mode 100644 index 000000000000..4f4ac95014bb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-f/A.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-f/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-f/_config.js new file mode 100644 index 000000000000..eab91d4b3a45 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-f/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; + +export default test({ + html: ` + 1 + 0 + `, + async test({ assert, target, component, window }) { + component.x = 2; + + assert.htmlEqual( + target.innerHTML, + ` + 2 + 0 + ` + ); + + const span = target.querySelector('span'); + await span?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + + assert.htmlEqual( + target.innerHTML, + ` + 2 + 2 + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-f/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-f/main.svelte new file mode 100644 index 000000000000..a47f1ba6de3b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-f/main.svelte @@ -0,0 +1,17 @@ + + + + + y = reflected} + class={reflected} + > + {reflected} + + + +{ y } \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-binding/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-binding/Nested.svelte new file mode 100644 index 000000000000..95b4842ee6ea --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-binding/Nested.svelte @@ -0,0 +1,9 @@ + + +
+ {#each items as item, index} + + {/each} +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-binding/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-binding/_config.js new file mode 100644 index 000000000000..864366e409b7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-binding/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+ + + +
+ `, + + ssrHtml: ` +
+ + + +
+ `, + + async test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + + inputs[2].value = 'd'; + await inputs[2].dispatchEvent(new window.Event('input')); + + assert.deepEqual(component.letters, ['a', 'b', 'd']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-binding/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-binding/main.svelte new file mode 100644 index 000000000000..c6edd8200359 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-binding/main.svelte @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/Inner.svelte new file mode 100644 index 000000000000..50baf3aa93cd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/Inner.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/Outer.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/Outer.svelte new file mode 100644 index 000000000000..d6c86307a5a4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/Outer.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/_config.js new file mode 100644 index 000000000000..8abde3dd3f30 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { prop: 'a' }; + }, + + html: 'a', + + test({ assert, component, target }) { + component.prop = 'b'; + assert.htmlEqual(target.innerHTML, 'b'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/main.svelte new file mode 100644 index 000000000000..2de0cb11ef44 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-in-slot/main.svelte @@ -0,0 +1,16 @@ + + + + + + + {value} + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-named/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-named/Nested.svelte new file mode 100644 index 000000000000..a3b09ff5b213 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-named/Nested.svelte @@ -0,0 +1,9 @@ + + +
+ {#each things as thing} + + {/each} +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-named/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-named/_config.js new file mode 100644 index 000000000000..1261875be307 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-named/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { things: [1, 2, 3] }; + }, + + html: ` +
+
1
+
2
+
3
+
`, + + test({ assert, component, target }) { + component.things = [1, 2, 3, 4]; + assert.htmlEqual( + target.innerHTML, + ` +
+
1
+
2
+
3
+
4
+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-named/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-named/main.svelte new file mode 100644 index 000000000000..f9e9e3a10fc6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-named/main.svelte @@ -0,0 +1,11 @@ + + + +
+ {thing} +
+
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-static/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-static/Nested.svelte new file mode 100644 index 000000000000..32eee1534acb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-static/Nested.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-static/_config.js new file mode 100644 index 000000000000..f533efa06704 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-static/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

Hi

' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-static/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-static/main.svelte new file mode 100644 index 000000000000..3eeaba976e1b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let-static/main.svelte @@ -0,0 +1,7 @@ + + + +

{value}

+
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let/Nested.svelte new file mode 100644 index 000000000000..3758adbd7ce4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let/Nested.svelte @@ -0,0 +1,9 @@ + + +
+ {#each things as thing} + + {/each} +
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let/_config.js new file mode 100644 index 000000000000..53bfd5eaf3f0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { things: [1, 2, 3] }; + }, + + html: ` +
+ 1 + 2 + 3 +
`, + + test({ assert, component, target }) { + component.things = [1, 2, 3, 4]; + assert.htmlEqual( + target.innerHTML, + ` +
+ 1 + 2 + 3 + 4 +
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let/main.svelte new file mode 100644 index 000000000000..d00bb8e41eed --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-let/main.svelte @@ -0,0 +1,9 @@ + + + + {thing} + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/Child.svelte new file mode 100644 index 000000000000..3f87a7dbf252 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/Child.svelte @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/Nested.svelte new file mode 100644 index 000000000000..a94392ce5d82 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/Nested.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/_config.js new file mode 100644 index 000000000000..a2fb1fe7a033 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` + Default +

B slot

+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/main.svelte new file mode 100644 index 000000000000..e5b3e2f84afb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment-nested/main.svelte @@ -0,0 +1,12 @@ + + + + + Default + + +

B slot

+
+
diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/B.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/B.svelte new file mode 100644 index 000000000000..3bbf00a60ca5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/B.svelte @@ -0,0 +1,6 @@ + + +
Hello
+
{name}
diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/Nested.svelte new file mode 100644 index 000000000000..09cfc5aa394b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/Nested.svelte @@ -0,0 +1,2 @@ +
a:
+
b:
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/_config.js new file mode 100644 index 000000000000..40d9329ef77a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
a: content a
+
b:
Hello
world
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/main.svelte new file mode 100644 index 000000000000..b27c3795ed73 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-svelte-fragment/main.svelte @@ -0,0 +1,13 @@ + + + + content { a } + + + + + diff --git a/test/runtime/samples/component-template-inline-mutation/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-template-inline-mutation/Widget.svelte similarity index 100% rename from test/runtime/samples/component-template-inline-mutation/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-template-inline-mutation/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-template-inline-mutation/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-template-inline-mutation/_config.js new file mode 100644 index 000000000000..1920fe657517 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-template-inline-mutation/_config.js @@ -0,0 +1,18 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const btns = target.querySelectorAll('button'); + const event = new window.MouseEvent('click', { bubbles: true }); + + btns[0].dispatchEvent(event); + btns[0].dispatchEvent(event); + btns[1].dispatchEvent(event); + btns[1].dispatchEvent(event); + btns[1].dispatchEvent(event); + flushSync(); + + assert.equal(btns[1].innerHTML, '3'); + } +}); diff --git a/test/runtime/samples/component-template-inline-mutation/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-template-inline-mutation/main.svelte similarity index 100% rename from test/runtime/samples/component-template-inline-mutation/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-template-inline-mutation/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-transition/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-transition/_config.js new file mode 100644 index 000000000000..c6c36f14c417 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-transition/_config.js @@ -0,0 +1,28 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, target, raf }) { + const button = /** @type {HTMLButtonElement} */ (target.querySelector('#button')); + const container = target.querySelector('#container'); + ok(button); + ok(container); + + // Multiple click on button + button.click(); + button.click(); + button.click(); + button.click(); + button.click(); + button.click(); + button.click(); + + raf.tick(0); + assert.equal(container.children.length, 1); + + flushSync(); + + raf.tick(501); + assert.equal(container.children.length, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/component-transition/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-transition/main.svelte new file mode 100644 index 000000000000..218b303b2128 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-transition/main.svelte @@ -0,0 +1,13 @@ + + + TAG={tag} + +
+ CONTENT +
diff --git a/test/runtime/samples/component-yield-follows-element/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-follows-element/Foo.svelte similarity index 100% rename from test/runtime/samples/component-yield-follows-element/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-follows-element/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-yield-follows-element/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-yield-follows-element/_config.js new file mode 100644 index 000000000000..9555ca329824 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-yield-follows-element/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
before
+ test + ` +}); diff --git a/test/runtime/samples/component-yield-follows-element/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-follows-element/main.svelte similarity index 100% rename from test/runtime/samples/component-yield-follows-element/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-follows-element/main.svelte diff --git a/test/runtime/samples/component-yield-if/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-if/Widget.svelte similarity index 100% rename from test/runtime/samples/component-yield-if/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-if/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-yield-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-yield-if/_config.js new file mode 100644 index 000000000000..fe9881826dd1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-yield-if/_config.js @@ -0,0 +1,26 @@ +import { test } from '../../test'; + +export default test({ + html: '

', + + test({ assert, component, target }) { + const { widget } = component; + + assert.equal(widget.show, false); + + widget.show = true; + assert.htmlEqual(target.innerHTML, '

Hello

'); + + component.data = 'World'; + assert.htmlEqual(target.innerHTML, '

World

'); + + widget.show = false; + assert.htmlEqual(target.innerHTML, '

'); + + component.data = 'Goodbye'; + assert.htmlEqual(target.innerHTML, '

'); + + widget.show = true; + assert.htmlEqual(target.innerHTML, '

Goodbye

'); + } +}); diff --git a/test/runtime/samples/component-yield-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-if/main.svelte similarity index 100% rename from test/runtime/samples/component-yield-if/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-if/main.svelte diff --git a/test/runtime/samples/component-yield-multiple-in-each/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-each/Widget.svelte similarity index 100% rename from test/runtime/samples/component-yield-multiple-in-each/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-each/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-each/_config.js new file mode 100644 index 000000000000..6748a3db8793 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-each/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

Hello Alice

+

Hello Bob

+

Hello Charles

+ `, + + test({ assert, component, target }) { + component.people = ['Alice', 'Charles', 'Bob']; + + assert.htmlEqual( + target.innerHTML, + ` +

Hello Alice

+

Hello Charles

+

Hello Bob

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-yield-multiple-in-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-each/main.svelte similarity index 100% rename from test/runtime/samples/component-yield-multiple-in-each/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-each/main.svelte diff --git a/test/runtime/samples/component-yield-multiple-in-if/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-if/Widget.svelte similarity index 100% rename from test/runtime/samples/component-yield-multiple-in-if/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-if/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-if/_config.js new file mode 100644 index 000000000000..8e25066edb9b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-if/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

Hello

+ `, + + test({ assert, component, target }) { + component.arriving = false; + assert.htmlEqual(target.innerHTML, "

Goodbye

"); + } +}); diff --git a/test/runtime/samples/component-yield-multiple-in-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-if/main.svelte similarity index 100% rename from test/runtime/samples/component-yield-multiple-in-if/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-multiple-in-if/main.svelte diff --git a/test/runtime/samples/component-yield-nested-if/Inner.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-nested-if/Inner.svelte similarity index 100% rename from test/runtime/samples/component-yield-nested-if/Inner.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-nested-if/Inner.svelte diff --git a/test/runtime/samples/component-yield-nested-if/Outer.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-nested-if/Outer.svelte similarity index 100% rename from test/runtime/samples/component-yield-nested-if/Outer.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-nested-if/Outer.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-yield-nested-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-yield-nested-if/_config.js new file mode 100644 index 000000000000..de560e8fdd4f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-yield-nested-if/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + html: ` + One + Inner + `, + + test({ assert, component, target }) { + component.foo = false; + assert.htmlEqual(target.innerHTML, ''); + + component.foo = true; + assert.htmlEqual(target.innerHTML, 'One\nInner'); + } +}); diff --git a/test/runtime/samples/component-yield-nested-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-nested-if/main.svelte similarity index 100% rename from test/runtime/samples/component-yield-nested-if/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-nested-if/main.svelte diff --git a/test/runtime/samples/component-yield-parent/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-parent/Widget.svelte similarity index 100% rename from test/runtime/samples/component-yield-parent/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-parent/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-yield-parent/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-yield-parent/_config.js new file mode 100644 index 000000000000..9dc6618bb3de --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-yield-parent/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

Hello

+ `, + + test({ assert, component, target }) { + assert.equal(component.data, 'Hello'); + + component.data = 'World'; + assert.equal(component.data, 'World'); + assert.htmlEqual( + target.innerHTML, + ` +

World

+ ` + ); + } +}); diff --git a/test/runtime/samples/component-yield-parent/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-parent/main.svelte similarity index 100% rename from test/runtime/samples/component-yield-parent/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-parent/main.svelte diff --git a/test/runtime/samples/component-yield-placement/Modal.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-placement/Modal.svelte similarity index 100% rename from test/runtime/samples/component-yield-placement/Modal.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-placement/Modal.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-yield-placement/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-yield-placement/_config.js new file mode 100644 index 000000000000..be64151449a8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-yield-placement/_config.js @@ -0,0 +1,32 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { showModal: true }; + }, + + html: ` + + + + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + button?.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/component-yield-placement/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-placement/main.svelte similarity index 100% rename from test/runtime/samples/component-yield-placement/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-placement/main.svelte diff --git a/test/runtime/samples/component-yield-static/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-static/Widget.svelte similarity index 100% rename from test/runtime/samples/component-yield-static/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-static/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-yield-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-yield-static/_config.js new file mode 100644 index 000000000000..3345dc3037f5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-yield-static/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: ` + Hello + `, + + test({ assert, component, target }) { + component.name = 'World'; + assert.htmlEqual( + target.innerHTML, + ` + Hello World + ` + ); + } +}); diff --git a/test/runtime/samples/component-yield-static/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield-static/main.svelte similarity index 100% rename from test/runtime/samples/component-yield-static/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield-static/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component-yield/_config.js b/packages/svelte/tests/runtime-legacy/samples/component-yield/_config.js new file mode 100644 index 000000000000..f5237b8c11c8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component-yield/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

Hello + +

` +}); diff --git a/test/runtime/samples/component-yield/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component-yield/main.svelte similarity index 100% rename from test/runtime/samples/component-yield/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component-yield/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/component/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/component/Widget.svelte new file mode 100644 index 000000000000..9b44ef57a841 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component/Widget.svelte @@ -0,0 +1 @@ +

i am a widget

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/component/_config.js b/packages/svelte/tests/runtime-legacy/samples/component/_config.js new file mode 100644 index 000000000000..4eb3cdb430ae --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/component/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

i am a widget

' +}); diff --git a/test/runtime/samples/component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/component/main.svelte similarity index 100% rename from test/runtime/samples/component/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/component/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-in-computed/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-in-computed/_config.js new file mode 100644 index 000000000000..fe6736ef893c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-in-computed/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

4, 12, 60

+ `, + + async test({ component, target, assert }) { + component.permutation = [2, 3, 1]; + await (component.promise1 = Promise.resolve({ length: 1, width: 2, height: 3 })); + try { + await (component.promise2 = Promise.reject({ length: 97, width: 98, height: 99 })); + } catch (e) { + // nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

2, 11, 2

+

9506, 28811, 98

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-in-computed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-in-computed/main.svelte new file mode 100644 index 000000000000..285fc4434813 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-in-computed/main.svelte @@ -0,0 +1,27 @@ + + +{#await promise1 then { length, width, height }} + {@const { [0]: a, [1]: b, [2]: c } = permutation} + {@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(length, width, height) } +

{first}, {second}, {third}

+{/await} + +{#await promise2 catch { [`leng${th}`]: l, [`wid${th}`]: w, height: h }} + {@const [a, b, c] = permutation} + {@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(l, w, h) } +

{first}, {second}, {third}

+{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-props/_config.js new file mode 100644 index 000000000000..fe6736ef893c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-props/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

4, 12, 60

+ `, + + async test({ component, target, assert }) { + component.permutation = [2, 3, 1]; + await (component.promise1 = Promise.resolve({ length: 1, width: 2, height: 3 })); + try { + await (component.promise2 = Promise.reject({ length: 97, width: 98, height: 99 })); + } catch (e) { + // nothing + } + + assert.htmlEqual( + target.innerHTML, + ` +

2, 11, 2

+

9506, 28811, 98

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-props/main.svelte new file mode 100644 index 000000000000..fbc54e4d0bd3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-computed-props/main.svelte @@ -0,0 +1,25 @@ + + +{#await promise1 then { length, width, height }} + {@const [a, b, c] = permutation} + {@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(length, width, height) } +

{first}, {second}, {third}

+{/await} + +{#await promise2 catch { length, width, height }} + {@const [a, b, c] = permutation} + {@const { [`${a}-Dimensions`]: { [c - 1]: first }, [`${b}-Dimensions`]: { [b - 1]: second }, [`${c}-Dimensions`]: { [a - 1]: third } } = calculate(length, width, height) } +

{first}, {second}, {third}

+{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-literals/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-literals/_config.js new file mode 100644 index 000000000000..89b4a5766736 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-literals/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + html: '
12 120 70, 30+4=34
', + async test({ component, target, assert }) { + component.promise1 = Promise.resolve({ width: 5, height: 6 }); + component.promise2 = Promise.reject({ width: 6, height: 7 }); + + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + ` +
30 300 110, 50+6=56
+
42 420 130, 60+7=67
+ ` + ); + + component.constant = 20; + assert.htmlEqual( + target.innerHTML, + ` +
30 600 220, 100+6=106
+
42 840 260, 120+7=127
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-literals/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-literals/main.svelte new file mode 100644 index 000000000000..0875820e4a89 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-literals/main.svelte @@ -0,0 +1,23 @@ + + +{#await promise1 then { width, height }} + {@const {'the-area': area, 'the-volume': volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const { 0: _width, 1: _height, 2: sum } = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/await} + +{#await promise2 catch { width, height }} + {@const {'the-area': area, 'the-volume': volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const { 0: _width, 1: _height, 2: sum } = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-nested-rest/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-nested-rest/_config.js new file mode 100644 index 000000000000..89b4a5766736 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-nested-rest/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + html: '
12 120 70, 30+4=34
', + async test({ component, target, assert }) { + component.promise1 = Promise.resolve({ width: 5, height: 6 }); + component.promise2 = Promise.reject({ width: 6, height: 7 }); + + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + ` +
30 300 110, 50+6=56
+
42 420 130, 60+7=67
+ ` + ); + + component.constant = 20; + assert.htmlEqual( + target.innerHTML, + ` +
30 600 220, 100+6=106
+
42 840 260, 120+7=127
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-nested-rest/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-nested-rest/main.svelte new file mode 100644 index 000000000000..7af5c989e400 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring-nested-rest/main.svelte @@ -0,0 +1,23 @@ + + +{#await promise1 then { width, height }} + {@const {area, volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const [_width, ...[_height, ...[sum]]] = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/await} + +{#await promise2 catch { width, height }} + {@const {area, volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const [_width, ...[_height, ...[sum]]] = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/await} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring/_config.js new file mode 100644 index 000000000000..89b4a5766736 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + html: '
12 120 70, 30+4=34
', + async test({ component, target, assert }) { + component.promise1 = Promise.resolve({ width: 5, height: 6 }); + component.promise2 = Promise.reject({ width: 6, height: 7 }); + + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + ` +
30 300 110, 50+6=56
+
42 420 130, 60+7=67
+ ` + ); + + component.constant = 20; + assert.htmlEqual( + target.innerHTML, + ` +
30 600 220, 100+6=106
+
42 840 260, 120+7=127
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring/main.svelte new file mode 100644 index 000000000000..ab450822c678 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then-destructuring/main.svelte @@ -0,0 +1,23 @@ + + +{#await promise1 then { width, height }} + {@const {area, volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const [_width, _height, sum] = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/await} + +{#await promise2 catch { width, height }} + {@const {area, volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const [_width, _height, sum] = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then/_config.js new file mode 100644 index 000000000000..89b4a5766736 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + html: '
12 120 70, 30+4=34
', + async test({ component, target, assert }) { + component.promise1 = Promise.resolve({ width: 5, height: 6 }); + component.promise2 = Promise.reject({ width: 6, height: 7 }); + + await Promise.resolve(); + assert.htmlEqual( + target.innerHTML, + ` +
30 300 110, 50+6=56
+
42 420 130, 60+7=67
+ ` + ); + + component.constant = 20; + assert.htmlEqual( + target.innerHTML, + ` +
30 600 220, 100+6=106
+
42 840 260, 120+7=127
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then/main.svelte new file mode 100644 index 000000000000..f8eed8711589 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-await-then/main.svelte @@ -0,0 +1,23 @@ + + +{#await promise1 then box} + {@const {area, volume} = calculate(box.width, box.height, constant)} + {@const perimeter = (box.width + box.height) * constant} + {@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]} +
{area} {volume} {perimeter}, {width}+{height}={sum}
+{/await} + +{#await promise2 catch box} + {@const {area, volume} = calculate(box.width, box.height, constant)} + {@const perimeter = (box.width + box.height) * constant} + {@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]} +
{area} {volume} {perimeter}, {width}+{height}={sum}
+{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-component-without-let/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-component-without-let/Component.svelte new file mode 100644 index 000000000000..e9e76f19b9de --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-component-without-let/Component.svelte @@ -0,0 +1,2 @@ + + diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-component-without-let/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-component-without-let/_config.js new file mode 100644 index 000000000000..7cd614ceeb98 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-component-without-let/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
static dynamic
+
static dynamic
+
static dynamic
+ `, + async test({ component, target, assert }) { + component.props = 'xxx'; + assert.htmlEqual( + target.innerHTML, + ` +
static xxx
+
static xxx
+
static xxx
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-component-without-let/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-component-without-let/main.svelte new file mode 100644 index 000000000000..9bee015c98c5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-component-without-let/main.svelte @@ -0,0 +1,24 @@ + + + + + {@const foo = "static"} + {@const bar = props} +
{foo} {bar}
+
+ + + {@const foo = "static"} + {@const bar = props} +
{foo} {bar}
+
+
+ + + {@const foo = "static"} + {@const bar = props} +
{foo} {bar}
+
diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-component/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-component/Component.svelte new file mode 100644 index 000000000000..68ba82f2456c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-component/Component.svelte @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-component/_config.js new file mode 100644 index 000000000000..f0390f79e10e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-component/_config.js @@ -0,0 +1,54 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
12 120 70, 30+4=34
+
12 120 70, 30+4=34
+
12 120 70, 30+4=34
+
+
12 120 70, 30+4=34
+
+
+
12 120 70, 30+4=34
+
+
12 120 70, 30+4=34
+
12 120 70, 30+4=34
+ `, + async test({ component, target, assert }) { + component.constant = 20; + assert.htmlEqual( + target.innerHTML, + ` +
12 240 140, 60+4=64
+
12 240 140, 60+4=64
+
12 240 140, 60+4=64
+
+
12 240 140, 60+4=64
+
+
+
12 240 140, 60+4=64
+
+
12 240 140, 60+4=64
+
12 240 140, 60+4=64
+ ` + ); + + component.box = { width: 5, height: 6 }; + assert.htmlEqual( + target.innerHTML, + ` +
30 600 220, 100+6=106
+
30 600 220, 100+6=106
+
30 600 220, 100+6=106
+
+
30 600 220, 100+6=106
+
+
+
30 600 220, 100+6=106
+
+
30 600 220, 100+6=106
+
30 600 220, 100+6=106
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-component/main.svelte new file mode 100644 index 000000000000..1854c3fba9ca --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-component/main.svelte @@ -0,0 +1,60 @@ + + + + + {@const {area, volume} = calculate(box.width, box.height, constant)} + {@const perimeter = (box.width + box.height) * constant} + {@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]} +
{area} {volume} {perimeter}, {width}+{height}={sum}
+
+ + + {@const {area, volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const [_width, _height, sum] = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+
+ + + {@const {area, volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const [_width, _height, sum] = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+
+
+ + +
+ {@const {area, volume} = calculate(box.width, box.height, constant)} + {@const perimeter = (box.width + box.height) * constant} + {@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]} +
{area} {volume} {perimeter}, {width}+{height}={sum}
+
+ +
+ {@const {area, volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const [_width, _height, sum] = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+
+ + {@const {area, volume} = calculate(box.width, box.height, constant)} + {@const perimeter = (box.width + box.height) * constant} + {@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]} +
{area} {volume} {perimeter}, {width}+{height}={sum}
+
+ + + {@const {area, volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const [_width, _height, sum] = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+
diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-dependencies/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-dependencies/_config.js new file mode 100644 index 000000000000..a449a429c8e0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-dependencies/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
7
+ `, + async test({ component, target, assert }) { + component.a = 5; + + assert.htmlEqual( + target.innerHTML, + ` +
9
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-dependencies/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-dependencies/main.svelte new file mode 100644 index 000000000000..cce3b0c1f753 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-dependencies/main.svelte @@ -0,0 +1,10 @@ + + +{#each [value] as n} + {@const ab = a + b} +
{ab}
+{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-arrow/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-arrow/_config.js new file mode 100644 index 000000000000..b5a54b04c27f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-arrow/_config.js @@ -0,0 +1,55 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

#FF0000

+

#00FF00

+

#0000FF

+ `, + async test({ component, target, assert }) { + component.constant = 20; + + assert.htmlEqual( + target.innerHTML, + ` +

#FF0000

+

#00FF00

+

#0000FF

+ ` + ); + + component.tags = [ + { + name: 'Red', + color: '#FF0000' + }, + { + name: 'Green', + color: '#00FF00' + }, + { + name: 'Blue', + color: '#0000FF' + }, + { + name: 'Black', + color: '#000000' + }, + { + name: 'White', + color: '#FFFFFF' + } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +

#FF0000

+

#00FF00

+

#0000FF

+

#000000

+

#FFFFFF

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-arrow/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-arrow/main.svelte new file mode 100644 index 000000000000..7292a7d485f0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-arrow/main.svelte @@ -0,0 +1,21 @@ + + +{#each tags as tag} + {@const tagColor = tags.find(t => t.name === tag.name).color} +

{tagColor}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-const/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-const/_config.js new file mode 100644 index 000000000000..4569448c3e2a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-const/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

0

+

bar: 1,2,3,1,1,2,3,2, num: 1

+

bar: 0,2,4,1,0,2,4,2, num: 2

+ `, + async test({ component, target, assert }) { + assert.htmlEqual( + target.innerHTML, + ` +

0

+

bar: 1,2,3,1,1,2,3,2, num: 1

+

bar: 0,2,4,1,0,2,4,2, num: 2

+ ` + ); + + component.nums = [1, 2, 3]; + + assert.htmlEqual( + target.innerHTML, + ` +

0

+

bar: 1,2,3,1,1,2,3,2,1,2,3,3, num: 1

+

bar: 0,2,4,1,0,2,4,2,0,2,4,3, num: 2

+

bar: -100,0,100,1,-100,0,100,2,-100,0,100,3, num: 3

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-const/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-const/main.svelte new file mode 100644 index 000000000000..182ea3cfc649 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-const/main.svelte @@ -0,0 +1,26 @@ + + +

{foo}

+{#each nums as num, index} + {@const bar = nums.map((num) => { + const func = (foos, num) => { + return [...foos.map((foo) => foo), num]; + } + return func(foos[index].nums, num); + })} +

bar: {bar}, num: {num}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-in-computed/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-in-computed/_config.js new file mode 100644 index 000000000000..98f3d3a4c931 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-in-computed/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + + `, + + async test({ component, target, assert }) { + component.boxes = [{ length: 10, width: 20, height: 30 }]; + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-in-computed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-in-computed/main.svelte new file mode 100644 index 000000000000..4538883e9e26 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-in-computed/main.svelte @@ -0,0 +1,44 @@ + + +{#each boxes as { [`leng${th}`]: length, [`wid${th}`]: width, height }} + {@const { + [`two${dimension}`]: areas, + [`three${dimension}`]: { + volume + } + } = calculate(length, width, height)} + {@const { + i = 1, + [`bottom${area}`]: bottom, + [`side${area}${i}`]: sideone, + [`side${area}${i + 1}`]: sidetwo + } = areas} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-props/_config.js new file mode 100644 index 000000000000..98f3d3a4c931 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-props/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + + `, + + async test({ component, target, assert }) { + component.boxes = [{ length: 10, width: 20, height: 30 }]; + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-props/main.svelte new file mode 100644 index 000000000000..1e15b06a92fc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-computed-props/main.svelte @@ -0,0 +1,42 @@ + + +{#each boxes as { length, width, height }} + {@const { + [`two${dimension}`]: { + i = 1, + [`bottom${area}`]: bottom, + [`side${area}${i}`]: sideone, + [`side${area}${i + 1}`]: sidetwo + }, + [`three${dimension}`]: { + volume + } + } = calculate(length, width, height)} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-literals/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-literals/_config.js new file mode 100644 index 000000000000..a613c0e98a27 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-literals/_config.js @@ -0,0 +1,38 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
12 120 70, 30+4=34
+
35 350 120, 50+7=57
+
48 480 140, 60+8=68
+ `, + async test({ component, target, assert }) { + component.constant = 20; + + assert.htmlEqual( + target.innerHTML, + ` +
12 240 140, 60+4=64
+
35 700 240, 100+7=107
+
48 960 280, 120+8=128
+ ` + ); + + component.boxes = [ + { width: 3, height: 4 }, + { width: 4, height: 5 }, + { width: 5, height: 6 }, + { width: 6, height: 7 } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
12 240 140, 60+4=64
+
20 400 180, 80+5=85
+
30 600 220, 100+6=106
+
42 840 260, 120+7=127
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-literals/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-literals/main.svelte new file mode 100644 index 000000000000..b0fc221ec974 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-literals/main.svelte @@ -0,0 +1,19 @@ + + +{#each boxes as { width, height }} + {@const { 'the-area': area, 'the-volume': volume } = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const { 2: sum, 0: _width, 1: _height } = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-nested-rest/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-nested-rest/_config.js new file mode 100644 index 000000000000..a613c0e98a27 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-nested-rest/_config.js @@ -0,0 +1,38 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
12 120 70, 30+4=34
+
35 350 120, 50+7=57
+
48 480 140, 60+8=68
+ `, + async test({ component, target, assert }) { + component.constant = 20; + + assert.htmlEqual( + target.innerHTML, + ` +
12 240 140, 60+4=64
+
35 700 240, 100+7=107
+
48 960 280, 120+8=128
+ ` + ); + + component.boxes = [ + { width: 3, height: 4 }, + { width: 4, height: 5 }, + { width: 5, height: 6 }, + { width: 6, height: 7 } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
12 240 140, 60+4=64
+
20 400 180, 80+5=85
+
30 600 220, 100+6=106
+
42 840 260, 120+7=127
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-nested-rest/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-nested-rest/main.svelte new file mode 100644 index 000000000000..4361314b19ae --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure-nested-rest/main.svelte @@ -0,0 +1,19 @@ + + +{#each boxes as { width, height }} + {@const {area, volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const [_width, ...[_height, ...[sum]]] = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure/_config.js new file mode 100644 index 000000000000..a613c0e98a27 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure/_config.js @@ -0,0 +1,38 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
12 120 70, 30+4=34
+
35 350 120, 50+7=57
+
48 480 140, 60+8=68
+ `, + async test({ component, target, assert }) { + component.constant = 20; + + assert.htmlEqual( + target.innerHTML, + ` +
12 240 140, 60+4=64
+
35 700 240, 100+7=107
+
48 960 280, 120+8=128
+ ` + ); + + component.boxes = [ + { width: 3, height: 4 }, + { width: 4, height: 5 }, + { width: 5, height: 6 }, + { width: 6, height: 7 } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
12 240 140, 60+4=64
+
20 400 180, 80+5=85
+
30 600 220, 100+6=106
+
42 840 260, 120+7=127
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure/main.svelte new file mode 100644 index 000000000000..7f0391d5e603 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-destructure/main.svelte @@ -0,0 +1,19 @@ + + +{#each boxes as { width, height }} + {@const {area, volume} = calculate(width, height, constant)} + {@const perimeter = (width + height) * constant} + {@const [_width, _height, sum] = [width * constant, height, width * constant + height]} +
{area} {volume} {perimeter}, {_width}+{_height}={sum}
+{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable1/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable1/_config.js new file mode 100644 index 000000000000..a8ebf6d6d1cc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable1/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

bar: 1,2,3,0,2,4,-100,0,100, num: 1

+

bar: 1,2,3,0,2,4,-100,0,100, num: 2

+

bar: 1,2,3,0,2,4,-100,0,100, num: 3

+ `, + async test({ component, target, assert }) { + assert.htmlEqual( + target.innerHTML, + ` +

bar: 1,2,3,0,2,4,-100,0,100, num: 1

+

bar: 1,2,3,0,2,4,-100,0,100, num: 2

+

bar: 1,2,3,0,2,4,-100,0,100, num: 3

+ ` + ); + + component.nums = [1, 2, 3, 4]; + + assert.htmlEqual( + target.innerHTML, + ` +

bar: 1,2,3,0,2,4,-100,0,100, num: 1

+

bar: 1,2,3,0,2,4,-100,0,100, num: 2

+

bar: 1,2,3,0,2,4,-100,0,100, num: 3

+

bar: 1,2,3,0,2,4,-100,0,100, num: 4

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable1/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable1/main.svelte new file mode 100644 index 000000000000..00c53dd4ff69 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable1/main.svelte @@ -0,0 +1,19 @@ + + +{#each nums as num} + {@const bar = foos.map((foos) => foos.nums)} +

bar: {bar}, num: {num}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable2/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable2/_config.js new file mode 100644 index 000000000000..a6480e7ce4e5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable2/_config.js @@ -0,0 +1,34 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

foo: dummy-foo, num: dummy-num

+

bar: 1,2,3,2,, num: 1

+

bar: 1,2,3,2,, num: 2

+

bar: 1,2,3,2,, num: 3

+ `, + async test({ component, target, assert }) { + assert.htmlEqual( + target.innerHTML, + ` +

foo: dummy-foo, num: dummy-num

+

bar: 1,2,3,2,, num: 1

+

bar: 1,2,3,2,, num: 2

+

bar: 1,2,3,2,, num: 3

+ ` + ); + + component.nums = [1, 2, 3, 4]; + + assert.htmlEqual( + target.innerHTML, + ` +

foo: dummy-foo, num: dummy-num

+

bar: 1,2,3,2,4,, num: 1

+

bar: 1,2,3,2,4,, num: 2

+

bar: 1,2,3,2,4,, num: 3

+

bar: 1,2,3,2,4,, num: 4

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable2/main.svelte new file mode 100644 index 000000000000..1f7afd92fd67 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable2/main.svelte @@ -0,0 +1,33 @@ + + +

foo: {foo}, num: {num}

+{#each nums as num} + {@const bar = foos.map((foo) => + foo.nums.filter((num) => { + if (Object.keys($$slots).length) { + return false; + } else if (Object.keys(foo).length) { + return nums.includes(num) || default_nums.includes(num); + } else { + return false; + } + }) || num + )} +

bar: {bar}, num: {num}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable3/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable3/_config.js new file mode 100644 index 000000000000..4569448c3e2a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable3/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

0

+

bar: 1,2,3,1,1,2,3,2, num: 1

+

bar: 0,2,4,1,0,2,4,2, num: 2

+ `, + async test({ component, target, assert }) { + assert.htmlEqual( + target.innerHTML, + ` +

0

+

bar: 1,2,3,1,1,2,3,2, num: 1

+

bar: 0,2,4,1,0,2,4,2, num: 2

+ ` + ); + + component.nums = [1, 2, 3]; + + assert.htmlEqual( + target.innerHTML, + ` +

0

+

bar: 1,2,3,1,1,2,3,2,1,2,3,3, num: 1

+

bar: 0,2,4,1,0,2,4,2,0,2,4,3, num: 2

+

bar: -100,0,100,1,-100,0,100,2,-100,0,100,3, num: 3

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable3/main.svelte new file mode 100644 index 000000000000..f559627d2399 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-duplicated-variable3/main.svelte @@ -0,0 +1,25 @@ + + +

{foo}

+{#each nums as num, index} + {@const bar = nums.map((num) => { + return (function (foos, num) { + return [...foos.map((foo) => foo), num]; + })(foos[index].nums, num); + })} +

bar: {bar}, num: {num}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-else/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-else/_config.js new file mode 100644 index 000000000000..272092f6c1df --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-else/_config.js @@ -0,0 +1,35 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
12 120 70, 30+4=34
+
35 350 120, 50+7=57
+
48 480 140, 60+8=68
+ `, + async test({ component, target, assert }) { + component.boxes = []; + assert.htmlEqual( + target.innerHTML, + ` +
10 * 2 = 20
+ ` + ); + + component.constant = 35; + assert.htmlEqual( + target.innerHTML, + ` +
35 * 2 = 70
+ ` + ); + + component.boxes = [{ width: 3, height: 4 }]; + + assert.htmlEqual( + target.innerHTML, + ` +
12 420 245, 105+4=109
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-else/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-else/main.svelte new file mode 100644 index 000000000000..7701a579cfb0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-else/main.svelte @@ -0,0 +1,22 @@ + + +{#each boxes as box} + {@const {area, volume} = calculate(box.width, box.height, constant)} + {@const perimeter = (box.width + box.height) * constant} + {@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]} +
{area} {volume} {perimeter}, {width}+{height}={sum}
+{:else} + {@const double = constant + constant} +
{constant} * 2 = {double}
+{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-function/_config.js new file mode 100644 index 000000000000..4569448c3e2a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-function/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

0

+

bar: 1,2,3,1,1,2,3,2, num: 1

+

bar: 0,2,4,1,0,2,4,2, num: 2

+ `, + async test({ component, target, assert }) { + assert.htmlEqual( + target.innerHTML, + ` +

0

+

bar: 1,2,3,1,1,2,3,2, num: 1

+

bar: 0,2,4,1,0,2,4,2, num: 2

+ ` + ); + + component.nums = [1, 2, 3]; + + assert.htmlEqual( + target.innerHTML, + ` +

0

+

bar: 1,2,3,1,1,2,3,2,1,2,3,3, num: 1

+

bar: 0,2,4,1,0,2,4,2,0,2,4,3, num: 2

+

bar: -100,0,100,1,-100,0,100,2,-100,0,100,3, num: 3

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-function/main.svelte new file mode 100644 index 000000000000..2e027c662080 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-function/main.svelte @@ -0,0 +1,26 @@ + + +

{foo}

+{#each nums as num, index} + {@const bar = nums.map((num) => { + function func(foos, num) { + return [...foos.map((foo) => foo), num]; + } + return func(foos[index].nums, num); + })} +

bar: {bar}, num: {num}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-update/_config.js new file mode 100644 index 000000000000..90363bd88ec3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-update/_config.js @@ -0,0 +1,29 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +// Test ensures that the `const` tag is coarse-grained in legacy mode (i.e. always fires an update when the array changes) +export default test({ + html: ` + +

0

+

1

+

2

+

3

+ `, + async test({ target, assert }) { + const btn = target.querySelector('button'); + + btn?.click(); + await tick(); + assert.htmlEqual( + target.innerHTML, + ` + +

0 show (v_item) show (item)

+

1

+

2 show (v_item) show (item)

+

3

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-update/main.svelte new file mode 100644 index 000000000000..66d0d4d0a2b6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each-update/main.svelte @@ -0,0 +1,21 @@ + + + + +{#each items as item, i} + {@const v_item=item} +

+ {i} + {#if v_item?.clicked} + show (v_item) + {/if} + {#if item?.clicked} + show (item) + {/if} +

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-each/_config.js new file mode 100644 index 000000000000..a613c0e98a27 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each/_config.js @@ -0,0 +1,38 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
12 120 70, 30+4=34
+
35 350 120, 50+7=57
+
48 480 140, 60+8=68
+ `, + async test({ component, target, assert }) { + component.constant = 20; + + assert.htmlEqual( + target.innerHTML, + ` +
12 240 140, 60+4=64
+
35 700 240, 100+7=107
+
48 960 280, 120+8=128
+ ` + ); + + component.boxes = [ + { width: 3, height: 4 }, + { width: 4, height: 5 }, + { width: 5, height: 6 }, + { width: 6, height: 7 } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
12 240 140, 60+4=64
+
20 400 180, 80+5=85
+
30 600 220, 100+6=106
+
42 840 260, 120+7=127
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-each/main.svelte new file mode 100644 index 000000000000..004f81cd83f7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-each/main.svelte @@ -0,0 +1,19 @@ + + +{#each boxes as box} + {@const {area, volume} = calculate(box.width, box.height, constant)} + {@const perimeter = (box.width + box.height) * constant} + {@const [width, height, sum] = [box.width * constant, box.height, box.width * constant + box.height]} +
{area} {volume} {perimeter}, {width}+{height}={sum}
+{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-func-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-func-function/_config.js new file mode 100644 index 000000000000..f2fd4ad203fe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-func-function/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` + [12,13,14] + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-func-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-func-function/main.svelte new file mode 100644 index 000000000000..01dce8200498 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-func-function/main.svelte @@ -0,0 +1,8 @@ + + +{#if true} + {@const [func_1] = [[12, 13, 14]]} + {(() => JSON.stringify(func_1))()} +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-hoisting/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-hoisting/_config.js new file mode 100644 index 000000000000..e590e52fe343 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-hoisting/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
4 ^ 4 = 256
+ `, + async test({ component, target, assert }) { + component.value = 3; + + assert.htmlEqual( + target.innerHTML, + ` +
3 ^ 4 = 81
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-hoisting/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-hoisting/main.svelte new file mode 100644 index 000000000000..49fce93274ce --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-hoisting/main.svelte @@ -0,0 +1,11 @@ + + +{#each [value] as n} +
{n} ^ 4 = {hypercubed}
+ + {@const squared = n * n} + {@const cubed = squared * n} + {@const hypercubed = cubed * n} +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-if/_config.js new file mode 100644 index 000000000000..937570511045 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-if/_config.js @@ -0,0 +1,58 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
20 x 40
+
20 x 40
+ `, + get props() { + return { boxes: [{ width: 20, height: 40 }] }; + }, + async test({ component, target, assert }) { + component.boxes = [{ width: 40, height: 70 }]; + assert.htmlEqual( + target.innerHTML, + ` +
40 x 70
+
40 x 70
+ ` + ); + + component.boxes = []; + + assert.htmlEqual(target.innerHTML, ''); + + component.boxes = [ + { width: 20, height: 40 }, + { width: 30, height: 50 } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
20 x 40
+
30 x 50
+
20 x 40
+
30 x 50
+ ` + ); + + component.boxes = [ + { width: 80, height: 70 }, + { width: 90, height: 60 } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
80 x 70
+
90 x 60
+
80 x 70
+
90 x 60
+ ` + ); + + component.boxes = []; + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-if/main.svelte new file mode 100644 index 000000000000..8188625897c1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-if/main.svelte @@ -0,0 +1,24 @@ + + +{#if boxes.length > 1} + {@const box1 = boxes[0]} + {@const box2 = boxes[1]} + {@const { width, height } = box1} +
{width} x {height}
+
{box2.width} x {box2.height}
+{:else if boxes.length > 0} + {@const box = boxes[0]} + {@const { width, height } = box} +
{width} x {height}
+{/if} + +{#if boxes.length > 1} +
{boxes[0].width} x {boxes[0].height}
+
{boxes[1].width} x {boxes[1].height}
+{:else if boxes.length > 0} + {@const box = boxes[0]} + {@const { width, height } = box} +
{width} x {height}
+{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-outro/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-outro/_config.js new file mode 100644 index 000000000000..9628c479d49b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-outro/_config.js @@ -0,0 +1,59 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
20 x 40
+
20 x 40
+ `, + get props() { + return { boxes: [{ width: 20, height: 40 }] }; + }, + async test({ component, target, assert, raf }) { + component.boxes = [{ width: 40, height: 70 }]; + assert.htmlEqual( + target.innerHTML, + ` +
40 x 70
+
40 x 70
+ ` + ); + + component.boxes = []; + + raf.tick(0); + assert.htmlEqual(target.innerHTML, ''); + + component.boxes = [ + { width: 20, height: 40 }, + { width: 30, height: 50 } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
20 x 40
+
30 x 50
+
20 x 40
+
30 x 50
+ ` + ); + + component.boxes = [ + { width: 80, height: 70 }, + { width: 90, height: 60 } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
80 x 70
+
90 x 60
+
80 x 70
+
90 x 60
+ ` + ); + + component.boxes = []; + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-outro/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-outro/main.svelte new file mode 100644 index 000000000000..90ac27fec17f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else-outro/main.svelte @@ -0,0 +1,29 @@ + + +{#if boxes.length > 1} + {@const box1 = boxes[0]} + {@const box2 = boxes[1]} + {@const { width, height } = box1} +
{width} x {height}
+
{box2.width} x {box2.height}
+{:else if boxes.length > 0} + {@const box = boxes[0]} + {@const { width, height } = box} +
{width} x {height}
+{/if} + +{#if boxes.length > 1} +
{boxes[0].width} x {boxes[0].height}
+
{boxes[1].width} x {boxes[1].height}
+{:else if boxes.length > 0} + {@const box = boxes[0]} + {@const { width, height } = box} +
{width} x {height}
+{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else/_config.js new file mode 100644 index 000000000000..b54cc6b8d921 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else/_config.js @@ -0,0 +1,54 @@ +import { test } from '../../test'; + +export default test({ + html: '
20 x 40
', + get props() { + return { boxes: [{ width: 20, height: 40 }] }; + }, + async test({ component, target, assert }) { + component.boxes = [{ width: 30, height: 60 }]; + + assert.htmlEqual( + target.innerHTML, + ` +
30 x 60
+ ` + ); + + component.boxes = [ + { width: 20, height: 40 }, + { width: 30, height: 50 } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
20 x 40
+
30 x 50
+ ` + ); + + component.boxes = [ + { width: 80, height: 70 }, + { width: 90, height: 60 } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
80 x 70
+
90 x 60
+ ` + ); + + component.boxes = [ + { width: 20, height: 40 }, + { width: 30, height: 50 }, + { width: 30, height: 50 } + ]; + assert.htmlEqual(target.innerHTML, '
3
'); + + component.boxes = []; + assert.htmlEqual(target.innerHTML, '
0
'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else/main.svelte new file mode 100644 index 000000000000..1da3d4ea663e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-if-else/main.svelte @@ -0,0 +1,18 @@ + + +{#if boxes.length === 2} + {@const box1 = boxes[0]} + {@const box2 = boxes[1]} + {@const { width, height } = box1} +
{width} x {height}
+
{box2.width} x {box2.height}
+{:else if boxes.length === 1} + {@const box = boxes[0]} + {@const { width, height } = box} +
{width} x {height}
+{:else} + {@const length = boxes.length} +
{length}
+{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-if/_config.js new file mode 100644 index 000000000000..c505af730196 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-if/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; + +export default test({ + html: '
10 x 34
', + get props() { + return { boxes: [{ width: 10, height: 34 }] }; + }, + async test({ component, target, assert }) { + component.boxes = [{ width: 20, height: 40 }]; + + assert.htmlEqual( + target.innerHTML, + ` +
20 x 40
+ ` + ); + + component.boxes = []; + assert.htmlEqual(target.innerHTML, ''); + + component.boxes = [{ width: 18, height: 48 }]; + + assert.htmlEqual( + target.innerHTML, + ` +
18 x 48
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-if/main.svelte new file mode 100644 index 000000000000..8f10ceefb8b6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-if/main.svelte @@ -0,0 +1,9 @@ + + +{#if boxes.length > 0} + {@const box = boxes[0]} + {@const { width, height } = box} +
{width} x {height}
+{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-invalidate/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-invalidate/_config.js new file mode 100644 index 000000000000..9c7a4a320d34 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-invalidate/_config.js @@ -0,0 +1,49 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
[Y] A
+
[N] B
+
[N] C
+ `, + test({ target, assert, window }) { + const [btn1, btn2, btn3] = target.querySelectorAll('button'); + btn1.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + btn2.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
[N] A
+
[Y] B
+
[N] C
+ ` + ); + + btn2.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
[N] A
+
[N] B
+
[N] C
+ ` + ); + + btn3.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
[N] A
+
[N] B
+
[Y] C
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-invalidate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-invalidate/main.svelte new file mode 100644 index 000000000000..6e58cbd9e20e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-invalidate/main.svelte @@ -0,0 +1,16 @@ + + +{#each items as item} + {@const toggle = () => item.selected = !item.selected} +
+ {item.selected ? '[Y]' : '[N]'} + {item.name} + +
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-ordering/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-ordering/_config.js new file mode 100644 index 000000000000..e590e52fe343 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-ordering/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
4 ^ 4 = 256
+ `, + async test({ component, target, assert }) { + component.value = 3; + + assert.htmlEqual( + target.innerHTML, + ` +
3 ^ 4 = 81
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-ordering/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-ordering/main.svelte new file mode 100644 index 000000000000..49fce93274ce --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-ordering/main.svelte @@ -0,0 +1,11 @@ + + +{#each [value] as n} +
{n} ^ 4 = {hypercubed}
+ + {@const squared = n * n} + {@const cubed = squared * n} + {@const hypercubed = cubed * n} +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow-2/_config.js new file mode 100644 index 000000000000..9bae56f49ac0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow-2/_config.js @@ -0,0 +1,39 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

1

+

3,6,9

+

2

+

3,6,9

+

3

+

3,6,9

+ `, + test({ component, target, assert }) { + component.baz = 5; + assert.htmlEqual( + target.innerHTML, + ` +

1

+

5,10,15

+

2

+

5,10,15

+

3

+

5,10,15

+ ` + ); + + component.array = [3, 4, 5]; + assert.htmlEqual( + target.innerHTML, + ` +

3

+

15,20,25

+

4

+

15,20,25

+

5

+

15,20,25

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow-2/main.svelte new file mode 100644 index 000000000000..c3bcb2f6051b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow-2/main.svelte @@ -0,0 +1,15 @@ + + +{#each array as item} +

{foo(item)}

+ {@const bar = array.map((item) => { + const bar = baz; + const foo = (item) => item * bar; + return foo(item); + })} +

{bar}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow/_config.js new file mode 100644 index 000000000000..286a46bb4b20 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow/_config.js @@ -0,0 +1,48 @@ +import { test } from '../../test'; + +export default test({ + html: ` + 7 + 11 + 15 + 7 + 19 + 23 + 27 + 19 + `, + async test({ component, target, assert }) { + component.numbers = [ + { + a: 4, + b: 5, + children: [ + { a: 6, b: 7 }, + { a: 8, b: 9 } + ] + }, + { + a: 10, + b: 11, + children: [ + { a: 12, b: 13 }, + { a: 14, b: 15 } + ] + } + ]; + + assert.htmlEqual( + target.innerHTML, + ` + 9 + 13 + 17 + 9 + 21 + 25 + 29 + 21 + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow/main.svelte new file mode 100644 index 000000000000..725121c73389 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag-shadow/main.svelte @@ -0,0 +1,31 @@ + + +{#each numbers as {a, b, children}} + {@const ab = a + b} + {ab} + {#each children as {a, b}} + {@const ab = a + b} + {ab} + {/each} + {ab} +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/const-tag/_config.js new file mode 100644 index 000000000000..9d625f89b801 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

Hello worldworld!

' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/const-tag/main.svelte b/packages/svelte/tests/runtime-legacy/samples/const-tag/main.svelte new file mode 100644 index 000000000000..3eaf38575519 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/const-tag/main.svelte @@ -0,0 +1,7 @@ + +{#if true} + {@const foo = bar} + {@const yoo = foo} + {@const bar = 'world'} +

Hello {bar}{yoo}!

+{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/ChildComponent.svelte b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/ChildComponent.svelte new file mode 100644 index 000000000000..af77418a1fe3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/ChildComponent.svelte @@ -0,0 +1,6 @@ + + +
Value in child component: {value}
diff --git a/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/_config.js new file mode 100644 index 000000000000..e05bb356374d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + html: ` +
Value in child component:
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/main.svelte b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/main.svelte new file mode 100644 index 000000000000..140aca73a3c8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/constructor-prefer-passed-context/main.svelte @@ -0,0 +1,15 @@ + + +
diff --git a/test/runtime/samples/context-api-b/Leaf.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api-b/Leaf.svelte similarity index 100% rename from test/runtime/samples/context-api-b/Leaf.svelte rename to packages/svelte/tests/runtime-legacy/samples/context-api-b/Leaf.svelte diff --git a/test/runtime/samples/context-api-b/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api-b/Nested.svelte similarity index 100% rename from test/runtime/samples/context-api-b/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/context-api-b/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/context-api-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/context-api-b/_config.js new file mode 100644 index 000000000000..20524de69ebb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-api-b/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
foo/bar
+
foo/baz
+ ` +}); diff --git a/test/runtime/samples/context-api-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api-b/main.svelte similarity index 100% rename from test/runtime/samples/context-api-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/context-api-b/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/context-api-c/Leaf.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api-c/Leaf.svelte new file mode 100644 index 000000000000..ae61ba063c41 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-api-c/Leaf.svelte @@ -0,0 +1,7 @@ + + +
{has}
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/context-api-c/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api-c/Nested.svelte new file mode 100644 index 000000000000..775d55d8f125 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-api-c/Nested.svelte @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/context-api-c/_config.js b/packages/svelte/tests/runtime-legacy/samples/context-api-c/_config.js new file mode 100644 index 000000000000..90300f0f9bea --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-api-c/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
true
+
false
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/context-api-c/main.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api-c/main.svelte new file mode 100644 index 000000000000..03ff1ae6eb44 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-api-c/main.svelte @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/context-api-d/Leaf.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api-d/Leaf.svelte new file mode 100644 index 000000000000..02b6b26e004f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-api-d/Leaf.svelte @@ -0,0 +1,9 @@ + + +{#each [...context.keys()] as key} +
{key}: {context.get(key)}
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/context-api-d/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api-d/Nested.svelte new file mode 100644 index 000000000000..e8a7e083c3d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-api-d/Nested.svelte @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/context-api-d/_config.js b/packages/svelte/tests/runtime-legacy/samples/context-api-d/_config.js new file mode 100644 index 000000000000..d4882207beb3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-api-d/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
a: 1
+
b: 2
+
c: 3
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/context-api-d/main.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api-d/main.svelte new file mode 100644 index 000000000000..82d10215745e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-api-d/main.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/test/runtime/samples/context-api/Tab.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api/Tab.svelte similarity index 100% rename from test/runtime/samples/context-api/Tab.svelte rename to packages/svelte/tests/runtime-legacy/samples/context-api/Tab.svelte diff --git a/test/runtime/samples/context-api/TabList.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api/TabList.svelte similarity index 100% rename from test/runtime/samples/context-api/TabList.svelte rename to packages/svelte/tests/runtime-legacy/samples/context-api/TabList.svelte diff --git a/test/runtime/samples/context-api/TabPanel.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api/TabPanel.svelte similarity index 100% rename from test/runtime/samples/context-api/TabPanel.svelte rename to packages/svelte/tests/runtime-legacy/samples/context-api/TabPanel.svelte diff --git a/test/runtime/samples/context-api/Tabs.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api/Tabs.svelte similarity index 97% rename from test/runtime/samples/context-api/Tabs.svelte rename to packages/svelte/tests/runtime-legacy/samples/context-api/Tabs.svelte index 6692bb31e962..79cc4e11b1be 100644 --- a/test/runtime/samples/context-api/Tabs.svelte +++ b/packages/svelte/tests/runtime-legacy/samples/context-api/Tabs.svelte @@ -1,6 +1,6 @@ - diff --git a/packages/svelte/tests/runtime-legacy/samples/context-api/_config.js b/packages/svelte/tests/runtime-legacy/samples/context-api/_config.js new file mode 100644 index 000000000000..f02c0a4432d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-api/_config.js @@ -0,0 +1,93 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true // to ensure dev mode does not break context in some way + }, + html: ` +
+
+ + +
+ +

Small panel

+
+ `, + + test({ assert, component, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + let buttons = target.querySelectorAll('button'); + + buttons[1].dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+
+ + +
+ +

Large panel

+
+ ` + ); + + component.show_medium = true; + + assert.htmlEqual( + target.innerHTML, + ` +
+
+ + + +
+ +

Large panel

+
+ ` + ); + + buttons = target.querySelectorAll('button'); + + buttons[1].dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
+
+ + + +
+ +

Medium panel

+
+ ` + ); + + component.show_medium = false; + + assert.htmlEqual( + target.innerHTML, + ` +
+
+ + +
+ +

Large panel

+
+ ` + ); + } +}); diff --git a/test/runtime/samples/context-api/main.svelte b/packages/svelte/tests/runtime-legacy/samples/context-api/main.svelte similarity index 100% rename from test/runtime/samples/context-api/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/context-api/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/context-in-await/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/context-in-await/Child.svelte new file mode 100644 index 000000000000..1227c2857dd4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-in-await/Child.svelte @@ -0,0 +1,6 @@ + + +

Context value: {num}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/context-in-await/_config.js b/packages/svelte/tests/runtime-legacy/samples/context-in-await/_config.js new file mode 100644 index 000000000000..1d131be782b5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-in-await/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

...waiting

+ `, + + async test({ assert, component, target }) { + await component.promise; + + assert.htmlEqual( + target.innerHTML, + ` +

Context value: 123

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/context-in-await/main.svelte b/packages/svelte/tests/runtime-legacy/samples/context-in-await/main.svelte new file mode 100644 index 000000000000..4f251f08702b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-in-await/main.svelte @@ -0,0 +1,14 @@ + + +{#await promise} +

...waiting

+{:then} + +{/await} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/context-in-template/_config.js b/packages/svelte/tests/runtime-legacy/samples/context-in-template/_config.js new file mode 100644 index 000000000000..42e3a43fd6f4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-in-template/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + assert.htmlEqual(target.innerHTML, `hello world`); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/context-in-template/main.svelte b/packages/svelte/tests/runtime-legacy/samples/context-in-template/main.svelte new file mode 100644 index 000000000000..35c50900f0d7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-in-template/main.svelte @@ -0,0 +1,11 @@ + + +{get_val()} diff --git a/packages/svelte/tests/runtime-legacy/samples/context-setcontext-return/_config.js b/packages/svelte/tests/runtime-legacy/samples/context-setcontext-return/_config.js new file mode 100644 index 000000000000..bda6cdf5441e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-setcontext-return/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
true
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/context-setcontext-return/main.svelte b/packages/svelte/tests/runtime-legacy/samples/context-setcontext-return/main.svelte new file mode 100644 index 000000000000..87153ee8465a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/context-setcontext-return/main.svelte @@ -0,0 +1,7 @@ + + +
{a === b}
diff --git a/packages/svelte/tests/runtime-legacy/samples/contextual-callback-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/contextual-callback-b/_config.js new file mode 100644 index 000000000000..a4a5f0e3770d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/contextual-callback-b/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/contextual-callback-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/contextual-callback-b/main.svelte new file mode 100644 index 000000000000..37f16b55fa2f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/contextual-callback-b/main.svelte @@ -0,0 +1,11 @@ + + + diff --git a/test/runtime/samples/contextual-callback/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/contextual-callback/Widget.svelte similarity index 100% rename from test/runtime/samples/contextual-callback/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/contextual-callback/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/contextual-callback/_config.js b/packages/svelte/tests/runtime-legacy/samples/contextual-callback/_config.js new file mode 100644 index 000000000000..d2304fbf3034 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/contextual-callback/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + await button?.dispatchEvent(click); + + assert.equal(component.clicked, 'x'); + } +}); diff --git a/test/runtime/samples/contextual-callback/main.svelte b/packages/svelte/tests/runtime-legacy/samples/contextual-callback/main.svelte similarity index 100% rename from test/runtime/samples/contextual-callback/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/contextual-callback/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/css-comments/_config.js b/packages/svelte/tests/runtime-legacy/samples/css-comments/_config.js new file mode 100644 index 000000000000..947b1bc489fd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/css-comments/_config.js @@ -0,0 +1,11 @@ +import { ok, test } from '../../test'; + +// JSDOM makes this test pass when it should fail. weird +export default test({ + test({ assert, target, window }) { + const p = target.querySelector('p'); + ok(p); + + assert.equal(window.getComputedStyle(p).color, 'rgb(255, 0, 0)'); + } +}); diff --git a/test/runtime/samples/css-comments/main.svelte b/packages/svelte/tests/runtime-legacy/samples/css-comments/main.svelte similarity index 100% rename from test/runtime/samples/css-comments/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/css-comments/main.svelte diff --git a/test/runtime/samples/css-space-in-attribute/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/css-space-in-attribute/Widget.svelte similarity index 100% rename from test/runtime/samples/css-space-in-attribute/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/css-space-in-attribute/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/css-space-in-attribute/_config.js b/packages/svelte/tests/runtime-legacy/samples/css-space-in-attribute/_config.js new file mode 100644 index 000000000000..80b8ed5d28e0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/css-space-in-attribute/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const [control, test] = target.querySelectorAll('p'); + + assert.equal(window.getComputedStyle(control).color, ''); + assert.equal(window.getComputedStyle(control).backgroundColor, 'rgba(0, 0, 0, 0)'); + + assert.equal(window.getComputedStyle(test).color, 'rgb(255, 0, 0)'); + assert.equal(window.getComputedStyle(test).backgroundColor, 'rgb(0, 0, 0)'); + } +}); diff --git a/test/runtime/samples/css-space-in-attribute/main.svelte b/packages/svelte/tests/runtime-legacy/samples/css-space-in-attribute/main.svelte similarity index 100% rename from test/runtime/samples/css-space-in-attribute/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/css-space-in-attribute/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/css-vars-escape/Sub.svelte b/packages/svelte/tests/runtime-legacy/samples/css-vars-escape/Sub.svelte new file mode 100644 index 000000000000..4781b65b360c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/css-vars-escape/Sub.svelte @@ -0,0 +1,7 @@ +
hi
+ + diff --git a/packages/svelte/tests/runtime-legacy/samples/css-vars-escape/_config.js b/packages/svelte/tests/runtime-legacy/samples/css-vars-escape/_config.js new file mode 100644 index 000000000000..49a7781f33f1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/css-vars-escape/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` + +
hi
+
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/css-vars-escape/main.svelte b/packages/svelte/tests/runtime-legacy/samples/css-vars-escape/main.svelte new file mode 100644 index 000000000000..d18e2d57f2a7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/css-vars-escape/main.svelte @@ -0,0 +1,6 @@ + + + diff --git a/test/runtime/samples/css/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/css/Widget.svelte similarity index 100% rename from test/runtime/samples/css/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/css/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/css/_config.js b/packages/svelte/tests/runtime-legacy/samples/css/_config.js new file mode 100644 index 000000000000..e38c31d55aa5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/css/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const [control, test] = target.querySelectorAll('p'); + + assert.equal(window.getComputedStyle(control).color, ''); + assert.equal(window.getComputedStyle(test).color, 'rgb(255, 0, 0)'); + } +}); diff --git a/test/runtime/samples/css-false/main.svelte b/packages/svelte/tests/runtime-legacy/samples/css/main.svelte similarity index 100% rename from test/runtime/samples/css-false/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/css/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/custom-method/_config.js b/packages/svelte/tests/runtime-legacy/samples/custom-method/_config.js new file mode 100644 index 000000000000..3d85874654b0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/custom-method/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

0

+ `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + button.dispatchEvent(event); + flushSync(); + assert.equal(component.counter, 1); + assert.htmlEqual( + target.innerHTML, + ` + +

1

+ ` + ); + + button.dispatchEvent(event); + flushSync(); + assert.equal(component.counter, 2); + assert.htmlEqual( + target.innerHTML, + ` + +

2

+ ` + ); + + assert.equal(component.foo(), 42); + } +}); diff --git a/test/runtime/samples/custom-method/main.svelte b/packages/svelte/tests/runtime-legacy/samples/custom-method/main.svelte similarity index 100% rename from test/runtime/samples/custom-method/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/custom-method/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-anchor/Anchor.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-anchor/Anchor.svelte new file mode 100644 index 000000000000..e758d60056a1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-anchor/Anchor.svelte @@ -0,0 +1 @@ +

Anchor

diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-anchor/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-anchor/_config.js new file mode 100644 index 000000000000..0ffcecb43995 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-anchor/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

Anchor

' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-anchor/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-anchor/main.svelte new file mode 100644 index 000000000000..cce6281e49ce --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-anchor/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-block-methods/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-block-methods/_config.js new file mode 100644 index 000000000000..a27673e61f88 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-block-methods/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + html: '
deconflicted
' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-block-methods/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-block-methods/main.svelte new file mode 100644 index 000000000000..ad7548887331 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-block-methods/main.svelte @@ -0,0 +1,5 @@ + + +
{create}
diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins-2/_config.js new file mode 100644 index 000000000000..e0a05f8fd4aa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins-2/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'hello world' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins-2/main.svelte new file mode 100644 index 000000000000..db10a81c74a5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins-2/main.svelte @@ -0,0 +1,6 @@ + + + {foo} + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins/_config.js new file mode 100644 index 000000000000..f3b464c43a47 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: 'got', + + test({ assert, component }) { + assert.equal(component.foo, 'got'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins/get.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins/get.js new file mode 100644 index 000000000000..3ecd58d92f33 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins/get.js @@ -0,0 +1,3 @@ +export function get() { + return 'got'; +} diff --git a/test/runtime/samples/deconflict-builtins/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-builtins/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-builtins/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-builtins/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-global/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-global/_config.js new file mode 100644 index 000000000000..181666660a4a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-global/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + name: 'Set' + }, + + html: '

true

' +}); diff --git a/test/runtime/samples/deconflict-component-name-with-global/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-global/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-component-name-with-global/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-global/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-module-global/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-module-global/_config.js new file mode 100644 index 000000000000..181666660a4a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-module-global/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + name: 'Set' + }, + + html: '

true

' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-module-global/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-module-global/main.svelte new file mode 100644 index 000000000000..9fac58577504 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-component-name-with-module-global/main.svelte @@ -0,0 +1,5 @@ + + +

{set.has('x')}

diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-component-refs/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-component-refs/_config.js new file mode 100644 index 000000000000..99462722e98a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-component-refs/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
    +
  • +
  • bar
  • +
  • baz
  • +
+ `, + + ssrHtml: ` +
    +
  • +
  • bar
  • +
  • baz
  • +
+ `, + + get props() { + return { + components: [ + { name: 'foo', edit: true }, + { name: 'bar', edit: false }, + { name: 'baz', edit: false } + ] + }; + } +}); diff --git a/test/runtime/samples/deconflict-component-refs/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-component-refs/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-component-refs/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-component-refs/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-contexts/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-contexts/_config.js new file mode 100644 index 000000000000..55cc5e1b6ac9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-contexts/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
  • foo
  • bar
  • baz
+ `, + + get props() { + return { components: ['foo', 'bar', 'baz'] }; + } +}); diff --git a/test/runtime/samples/deconflict-contexts/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-contexts/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-contexts/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-contexts/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/_config.js new file mode 100644 index 000000000000..0e8e34bde255 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +/** @type {string[]} */ +let result; + +export default test({ + before_test() { + result = []; + }, + get props() { + return { + /** @param {string} str */ + collect: (str) => result.push(str) + }; + }, + test({ assert }) { + assert.deepEqual(result, ['import_action', 'each_action']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/main.svelte new file mode 100644 index 000000000000..8baed229a164 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/main.svelte @@ -0,0 +1,17 @@ + + +
+ +
    + {#each array as action} +
    + {/each} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/util.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/util.js new file mode 100644 index 000000000000..32bf0ffd2ebd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-action/util.js @@ -0,0 +1,3 @@ +export default function (_, fn) { + fn('import_action'); +} diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-bind/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-bind/Widget.svelte new file mode 100644 index 000000000000..3aaa59b74757 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-bind/Widget.svelte @@ -0,0 +1,3 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-bind/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-bind/_config.js new file mode 100644 index 000000000000..f47bee71df87 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-bind/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-bind/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-bind/main.svelte new file mode 100644 index 000000000000..fe91deca17f1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-contextual-bind/main.svelte @@ -0,0 +1,8 @@ + + +{#each values as value} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-ctx/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-ctx/_config.js new file mode 100644 index 000000000000..d40c663f1ebe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-ctx/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

Hello world!

+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-ctx/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-ctx/main.svelte new file mode 100644 index 000000000000..d1af46a18dd4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-ctx/main.svelte @@ -0,0 +1,5 @@ + + +

Hello {ctx}!

diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-elements-indexes/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-elements-indexes/_config.js new file mode 100644 index 000000000000..6fb6ab644279 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-elements-indexes/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
+ one +
+ `, + + test({ assert, component, target }) { + const { tagList } = component; + tagList.push('two'); + component.tagList = tagList; + + assert.htmlEqual( + target.innerHTML, + ` +
+ one + two +
+ ` + ); + } +}); diff --git a/test/runtime/samples/deconflict-elements-indexes/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-elements-indexes/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-elements-indexes/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-elements-indexes/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-globals/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-globals/_config.js new file mode 100644 index 000000000000..6257792f19c8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-globals/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + name: 'window' + }, + + html: ` +

I hereby declare Svelte the bestest framework.

+

nintendo sixty four

+

Woops.

+

42

+

false

+ ` +}); diff --git a/test/runtime/samples/deconflict-globals/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-globals/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-globals/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-globals/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-non-helpers/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-non-helpers/_config.js new file mode 100644 index 000000000000..e7b876d800f5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-non-helpers/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: 'ABCD', + + test({ assert, component }) { + assert.equal(component.compute(), 'ABCD'); + } +}); diff --git a/test/runtime/samples/deconflict-non-helpers/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-non-helpers/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-non-helpers/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-non-helpers/main.svelte diff --git a/test/runtime/samples/deconflict-non-helpers/module.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-non-helpers/module.js similarity index 100% rename from test/runtime/samples/deconflict-non-helpers/module.js rename to packages/svelte/tests/runtime-legacy/samples/deconflict-non-helpers/module.js diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-self/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-self/_config.js new file mode 100644 index 000000000000..f92f66f53c2d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-self/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

nested component

' +}); diff --git a/test/runtime/samples/deconflict-self/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-self/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-self/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-self/main.svelte diff --git a/test/runtime/samples/deconflict-self/nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-self/nested/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-self/nested/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-self/nested/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-spread-i/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-spread-i/_config.js new file mode 100644 index 000000000000..f47bee71df87 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-spread-i/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-spread-i/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-spread-i/main.svelte new file mode 100644 index 000000000000..a7b201ac4e98 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-spread-i/main.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-template-1/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-1/_config.js new file mode 100644 index 000000000000..80551142a920 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-1/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'template' +}); diff --git a/test/runtime/samples/deconflict-template-1/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-1/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-template-1/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-template-1/main.svelte diff --git a/test/runtime/samples/deconflict-template-1/module.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-1/module.js similarity index 100% rename from test/runtime/samples/deconflict-template-1/module.js rename to packages/svelte/tests/runtime-legacy/samples/deconflict-template-1/module.js diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-template-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-2/_config.js new file mode 100644 index 000000000000..80551142a920 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-2/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'template' +}); diff --git a/test/runtime/samples/deconflict-template-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-2/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-template-2/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-template-2/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-template-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-3/_config.js new file mode 100644 index 000000000000..549acba62171 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-3/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
test
' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-template-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-3/main.svelte new file mode 100644 index 000000000000..6628a9c856f1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-3/main.svelte @@ -0,0 +1 @@ +
test
diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-template-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-4/_config.js new file mode 100644 index 000000000000..33e256feffd6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-4/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

test

' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-template-4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-4/main.svelte new file mode 100644 index 000000000000..a22367b2a5d9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-template-4/main.svelte @@ -0,0 +1,5 @@ + + +

{h1}

diff --git a/test/runtime/samples/deconflict-value/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-value/Widget.svelte similarity index 100% rename from test/runtime/samples/deconflict-value/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-value/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-value/_config.js new file mode 100644 index 000000000000..38cb3aad6a44 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-value/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + + html: ` +

Reactive: foo

+

Value: foo

+ ` +}); diff --git a/test/runtime/samples/deconflict-value/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-value/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-value/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-value/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/deconflict-vars/_config.js b/packages/svelte/tests/runtime-legacy/samples/deconflict-vars/_config.js new file mode 100644 index 000000000000..a652c4bdb229 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/deconflict-vars/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

ab

' +}); diff --git a/test/runtime/samples/deconflict-vars/main.svelte b/packages/svelte/tests/runtime-legacy/samples/deconflict-vars/main.svelte similarity index 100% rename from test/runtime/samples/deconflict-vars/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/deconflict-vars/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/default-data-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/default-data-function/_config.js new file mode 100644 index 000000000000..318aec7f3258 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/default-data-function/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: '

Hello world!

', + + test({ assert, component, target }) { + component.name = () => 'everybody'; + assert.htmlEqual(target.innerHTML, '

Hello everybody!

'); + } +}); diff --git a/test/runtime/samples/default-data-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/default-data-function/main.svelte similarity index 100% rename from test/runtime/samples/default-data-function/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/default-data-function/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/default-data-override/_config.js b/packages/svelte/tests/runtime-legacy/samples/default-data-override/_config.js new file mode 100644 index 000000000000..9da9e5036d17 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/default-data-override/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { name: 'everybody' }; + }, + + html: '

Hello everybody!

' +}); diff --git a/test/runtime/samples/default-data-override/main.svelte b/packages/svelte/tests/runtime-legacy/samples/default-data-override/main.svelte similarity index 100% rename from test/runtime/samples/default-data-override/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/default-data-override/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/default-data/_config.js b/packages/svelte/tests/runtime-legacy/samples/default-data/_config.js new file mode 100644 index 000000000000..240263603d28 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/default-data/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

Hello world!

' +}); diff --git a/test/runtime/samples/default-data/main.svelte b/packages/svelte/tests/runtime-legacy/samples/default-data/main.svelte similarity index 100% rename from test/runtime/samples/default-data/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/default-data/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/destroy-twice/_config.js b/packages/svelte/tests/runtime-legacy/samples/destroy-twice/_config.js new file mode 100644 index 000000000000..d6900ef91d33 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destroy-twice/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; +import { unmount } from 'svelte'; + +export default test({ + test({ component }) { + unmount(component); + unmount(component); + }, + + warnings: [ + 'Tried to unmount a component that was not mounted', + 'Tried to unmount a component that was not mounted' + ] +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/destroy-twice/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destroy-twice/main.svelte new file mode 100644 index 000000000000..61da16d02641 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destroy-twice/main.svelte @@ -0,0 +1 @@ +
diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-assignment-pattern-with-object-pattern/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructured-assignment-pattern-with-object-pattern/_config.js new file mode 100644 index 000000000000..3ef701958224 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-assignment-pattern-with-object-pattern/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
hello
+
hello bar2
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-assignment-pattern-with-object-pattern/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-assignment-pattern-with-object-pattern/main.svelte new file mode 100644 index 000000000000..b71b25bd6750 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-assignment-pattern-with-object-pattern/main.svelte @@ -0,0 +1,11 @@ + + +
hello {bar}
+
hello {bar2}
diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-1/A.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-props-1/A.svelte new file mode 100644 index 000000000000..d1b392ef340f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-1/A.svelte @@ -0,0 +1,24 @@ + + +
+a: {a}, +b: {typeof b}, +c: {c}, +d_one: {d_one}, +d_three: {$d_three}, +f: {f}, +g: {g}, +e: {typeof e}, +e_one: {e_one}, +A: {A}, +C: {C} +
+
{JSON.stringify(THING)}
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-1/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructured-props-1/_config.js new file mode 100644 index 000000000000..62f9ceaa071b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-1/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
a: 1, b: undefined, c: 2, d_one: 3, d_three: 5, f: , g: 9, e: undefined, e_one: 6, A: 1, C: 2
+
{"a":1,"b":{"c":2,"d":[3,4,{}]},"e":[6],"h":8}
+
+
a: a, b: undefined, c: 2, d_one: d_one, d_three: 5, f: f, g: g, e: undefined, e_one: 6, A: 1, C: 2
+
{"a":1,"b":{"c":2,"d":[3,4,{}]},"e":[6],"h":8}
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-1/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-props-1/main.svelte new file mode 100644 index 000000000000..dbe7c88d3368 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-1/main.svelte @@ -0,0 +1,7 @@ + + + +
+
diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/A.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/A.svelte new file mode 100644 index 000000000000..51167edbc46b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/A.svelte @@ -0,0 +1,21 @@ + + +
+ x: {x}, + list_two_a: {list_two_a}, + list_two_b: {list_two_b}, + y: {$y}, + m: {m}, + n: {n}, + o: {o}, + p: {p}, + q: {$q} +
+
{JSON.stringify(LIST)}
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/_config.js new file mode 100644 index 000000000000..0f3fcedce529 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/_config.js @@ -0,0 +1,26 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
x: 1, list_two_a: 2, list_two_b: 5, y: 4, m: 1, n: 2, o: 5, p: 3, q: 4
+
[1,{"a":2},[3,{}]]
+
x: 1, list_two_a: 2, list_two_b: 5, y: 4, m: m, n: n, o: o, p: p, q: q
+
[1,{"a":2},[3,{}]]
+ `, + + async test({ component, assert, target }) { + await component.update(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
x: 1, list_two_a: 2, list_two_b: 5, y: 4, m: 1, n: 2, o: 5, p: 3, q: 4
+
[1,{"a":2},[3,{}]]
+
x: 1, list_two_a: 2, list_two_b: 5, y: 4, m: MM, n: NN, o: OO, p: PP, q: QQ
+
[1,{"a":2},[3,{}]]
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/main.svelte new file mode 100644 index 000000000000..f0044bb5672e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-2/main.svelte @@ -0,0 +1,30 @@ + + +
+
+
diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/A.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/A.svelte new file mode 100644 index 000000000000..6c5aca05b04f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/A.svelte @@ -0,0 +1,10 @@ + + +
i: {i}, j: {j}, k: {$k}, l: {l}, m: {m}, n: {$n}, a: {a}, b: {b}, c: {$c}, d: {d}, e: {e}, f: {$f}
\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/_config.js new file mode 100644 index 000000000000..c78b84ec8cd9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/_config.js @@ -0,0 +1,23 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
i: 9, j: 10, k: 11, l: 12, m: 13, n: 14, a: 9, b: 10, c: 11, d: 12, e: 13, f: 14
+
+
i: 9, j: 10, k: 11, l: 12, m: 13, n: 14, a: a, b: 10, c: c, d: d, e: 13, f: f
+ `, + async test({ component, target, assert }) { + await component.update(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
i: 9, j: 10, k: 11, l: 12, m: 13, n: 14, a: 9, b: 10, c: 11, d: 12, e: 13, f: 14
+
+
i: 9, j: 10, k: 11, l: 12, m: 13, n: 14, a: aa, b: 10, c: cc, d: dd, e: 13, f: ff
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/main.svelte new file mode 100644 index 000000000000..8152d61aab45 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-3/main.svelte @@ -0,0 +1,29 @@ + + +
+
+
diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-4/A.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-props-4/A.svelte new file mode 100644 index 000000000000..ab5e6b76893c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-4/A.svelte @@ -0,0 +1,25 @@ + + +
+a: {a}, +b: {typeof b}, +c: {c}, +d_one: {d_one}, +d_three: {$d_three}, +length: {length}, +f: {f}, +g: {g}, +e: {typeof e}, +e_one: {e_one}, +A: {A}, +C: {C} +
+
{JSON.stringify(THING)}
diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructured-props-4/_config.js new file mode 100644 index 000000000000..fdec37594572 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-4/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
a: 1, b: undefined, c: 2, d_one: 3, d_three: 5, length: 2, f: , g: 9, e: undefined, e_one: 6, A: 1, C: 2
+
{"a":1,"b":{"c":2,"d":[3,4,{},6,7]},"e":[6],"h":8}
+
+
a: a, b: undefined, c: 2, d_one: d_one, d_three: 5, length: 7, f: f, g: g, e: undefined, e_one: 6, A: 1, C: 2
+
{"a":1,"b":{"c":2,"d":[3,4,{},6,7]},"e":[6],"h":8}
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-props-4/main.svelte new file mode 100644 index 000000000000..cc1a31f542a0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-4/main.svelte @@ -0,0 +1,7 @@ + + +
+
+
diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/A.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/A.svelte new file mode 100644 index 000000000000..898ce5aa3d7e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/A.svelte @@ -0,0 +1,23 @@ + + +
+ x: {x}, list_two_a: {list_two_a}, list_two_b: {list_two_b}, y: {y}, l: {l}, m: {m}, + n: {n}, o: {o}, p: {p}, q: {$q}, r: {$r}, s: {s} +
+
{JSON.stringify(LIST)}
diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/_config.js new file mode 100644 index 000000000000..103ce64d7c7b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/_config.js @@ -0,0 +1,26 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
x: 1, list_two_a: 4, list_two_b: 5, y: 3, l: 1, m: 2, n: 4, o: 5, p: 5, q: 6, r: 7, s: 1
+
[1,2,3,{"a":4},[5,{},{},8]]
+
x: 1, list_two_a: 4, list_two_b: 5, y: 3, l: l, m: m, n: n, o: o, p: p, q: q, r: r, s: s
+
[1,2,3,{"a":4},[5,{},{},8]]
+ `, + + async test({ component, assert, target }) { + await component.update(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
x: 1, list_two_a: 4, list_two_b: 5, y: 3, l: 1, m: 2, n: 4, o: 5, p: 5, q: 6, r: 7, s: 1
+
[1,2,3,{"a":4},[5,{},{},8]]
+
x: 1, list_two_a: 4, list_two_b: 5, y: 3, l: LL, m: MM, n: NN, o: OO, p: PP, q: QQ, r: RR, s: SS
+
[1,2,3,{"a":4},[5,{},{},8]]
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/main.svelte new file mode 100644 index 000000000000..a8b9e8a70428 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructured-props-5/main.svelte @@ -0,0 +1,36 @@ + + +
+
+
diff --git a/packages/svelte/tests/runtime-legacy/samples/destructuring-assignment-array/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructuring-assignment-array/_config.js new file mode 100644 index 000000000000..9c09581097c8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructuring-assignment-array/_config.js @@ -0,0 +1,30 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
    +
  • Gruyere
  • +
  • Compté
  • +
  • Beaufort
  • +
  • Abondance
  • +
+ `, + + test({ assert, component, target }) { + component.swap(0, 1); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
    +
  • Compté
  • +
  • Gruyere
  • +
  • Beaufort
  • +
  • Abondance
  • +
+ ` + ); + } +}); diff --git a/test/runtime/samples/destructuring-assignment-array/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destructuring-assignment-array/main.svelte similarity index 100% rename from test/runtime/samples/destructuring-assignment-array/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/destructuring-assignment-array/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/destructuring-between-exports/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructuring-between-exports/_config.js new file mode 100644 index 000000000000..1a3cc19cc65c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructuring-between-exports/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: { bar: 42 } }; + }, + html: ` +

42

+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/destructuring-between-exports/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destructuring-between-exports/main.svelte new file mode 100644 index 000000000000..17cc8dc17dcd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructuring-between-exports/main.svelte @@ -0,0 +1,7 @@ + + +

{bar}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/destructuring-one-value-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructuring-one-value-reactive/_config.js new file mode 100644 index 000000000000..eb885e4d4860 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructuring-one-value-reactive/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + +`, + test({ assert, target }) { + const btn = target.querySelector('button'); + btn?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/destructuring-one-value-reactive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destructuring-one-value-reactive/main.svelte new file mode 100644 index 000000000000..a894510b280b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructuring-one-value-reactive/main.svelte @@ -0,0 +1,11 @@ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/destructuring/_config.js b/packages/svelte/tests/runtime-legacy/samples/destructuring/_config.js new file mode 100644 index 000000000000..3650e546dc1a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/destructuring/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +// TODO err... what is going on here +export default test({ + html: '', + + get props() { + return { foo: 42 }; + }, + + test({ assert, component, target, window }) { + const event = new window.MouseEvent('click'); + // @ts-expect-error wut + const button = target.querySelector('button', { bubbles: true }); + + let count = 0; + let number = null; + } +}); diff --git a/test/runtime/samples/destructuring/main.svelte b/packages/svelte/tests/runtime-legacy/samples/destructuring/main.svelte similarity index 100% rename from test/runtime/samples/destructuring/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/destructuring/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/_config.js b/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/_config.js new file mode 100644 index 000000000000..2c7865b82e76 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + skip: true, // TODO: needs fixing + + compileOptions: { + dev: true + }, + error: '{#each} only works with iterable values.' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/main.svelte new file mode 100644 index 000000000000..7225319e1464 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dev-warning-each-block-require-arraylike/main.svelte @@ -0,0 +1,3 @@ +{#each {} as item} +
{item}
+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/_config.js b/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/_config.js new file mode 100644 index 000000000000..8606f012b47e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + get props() { + return { a: 42 }; + }, + + test({ assert, component }) { + try { + component.foo = 1; + throw new Error('Expected an error'); + } catch (err) { + // @ts-ignore + assert.equal(err.message, 'Cannot set property foo of # which has only a getter'); + } + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/main.svelte new file mode 100644 index 000000000000..5b7ebf809c9c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dev-warning-readonly-computed/main.svelte @@ -0,0 +1,7 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/document-binding-active/_config.js b/packages/svelte/tests/runtime-legacy/samples/document-binding-active/_config.js new file mode 100644 index 000000000000..a8b85bf5789a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/document-binding-active/_config.js @@ -0,0 +1,16 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +// This test is slightly inaccurate, because blurring elements (or focusing the `` directly) +// doesn't trigger the relevant `focusin` event in JSDOM. +export default test({ + test({ assert, target, logs }) { + const [btn1, btn2] = target.querySelectorAll('button'); + + flushSync(() => btn1.focus()); + assert.deepEqual(logs, ['...', 'BODY', 'one']); + + flushSync(() => btn2.focus()); + assert.deepEqual(logs, ['...', 'BODY', 'one', 'two']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/document-binding-active/main.svelte b/packages/svelte/tests/runtime-legacy/samples/document-binding-active/main.svelte new file mode 100644 index 000000000000..17768fa95e53 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/document-binding-active/main.svelte @@ -0,0 +1,10 @@ + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/document-binding-fullscreen/_config.js b/packages/svelte/tests/runtime-legacy/samples/document-binding-fullscreen/_config.js new file mode 100644 index 000000000000..1bd357b401a9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/document-binding-fullscreen/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + before_test() { + Object.defineProperties(window.document, { + fullscreenElement: { + value: null, + configurable: true + } + }); + }, + + async test({ assert, target, window, component }) { + const event = new window.Event('fullscreenchange'); + + const div = target.querySelector('div'); + + Object.defineProperties(window.document, { + fullscreenElement: { + value: div, + configurable: true + } + }); + + window.document.dispatchEvent(event); + + assert.equal(component.fullscreen, div); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/document-binding-fullscreen/main.svelte b/packages/svelte/tests/runtime-legacy/samples/document-binding-fullscreen/main.svelte new file mode 100644 index 000000000000..447742c74181 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/document-binding-fullscreen/main.svelte @@ -0,0 +1,7 @@ + + + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/document-event/_config.js b/packages/svelte/tests/runtime-legacy/samples/document-event/_config.js new file mode 100644 index 000000000000..0a1fc6a3f767 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/document-event/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component, window }) { + assert.deepEqual(component.events, []); + + const event1 = new window.Event('mouseenter'); + window.document.body.dispatchEvent(event1); + assert.deepEqual(component.events, ['enter']); + + const event2 = new window.Event('mouseleave'); + window.document.body.dispatchEvent(event2); + assert.deepEqual(component.events, ['enter', 'leave']); + } +}); diff --git a/test/runtime/samples/document-event/main.svelte b/packages/svelte/tests/runtime-legacy/samples/document-event/main.svelte similarity index 100% rename from test/runtime/samples/document-event/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/document-event/main.svelte diff --git a/test/runtime/samples/dynamic-component-bindings-recreated-b/Green.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated-b/Green.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-bindings-recreated-b/Green.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated-b/Green.svelte diff --git a/test/runtime/samples/dynamic-component-bindings-recreated-b/Red.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated-b/Red.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-bindings-recreated-b/Red.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated-b/Red.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated-b/_config.js new file mode 100644 index 000000000000..99c06d257314 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated-b/_config.js @@ -0,0 +1,36 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: true }; + }, + + html: ` +

parent green

+

green green

+ `, + + test({ assert, component, target }) { + component.foo = undefined; + component.x = false; + + assert.htmlEqual( + target.innerHTML, + ` +

parent red

+

red red

+ ` + ); + + component.foo = undefined; + component.x = true; + + assert.htmlEqual( + target.innerHTML, + ` +

parent green

+

green green

+ ` + ); + } +}); diff --git a/test/runtime/samples/dynamic-component-bindings-recreated-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated-b/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-bindings-recreated-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated-b/main.svelte diff --git a/test/runtime/samples/dynamic-component-bindings-recreated/Green.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated/Green.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-bindings-recreated/Green.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated/Green.svelte diff --git a/test/runtime/samples/dynamic-component-bindings-recreated/Red.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated/Red.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-bindings-recreated/Red.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated/Red.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated/_config.js new file mode 100644 index 000000000000..8877998ba185 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: true, foo: 'one' }; + }, + + html: ` +

green one

+ `, + + test({ assert, component, target }) { + component.x = false; + + assert.htmlEqual( + target.innerHTML, + ` +

red one

+ ` + ); + + component.foo = 'two'; + component.x = true; + + assert.htmlEqual( + target.innerHTML, + ` +

green two

+ ` + ); + } +}); diff --git a/test/runtime/samples/dynamic-component-bindings-recreated/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-bindings-recreated/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings-recreated/main.svelte diff --git a/test/runtime/samples/dynamic-component-bindings/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings/Bar.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-bindings/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings/Bar.svelte diff --git a/test/runtime/samples/dynamic-component-bindings/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings/Foo.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-bindings/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings/_config.js new file mode 100644 index 000000000000..8d7f239d6f6b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings/_config.js @@ -0,0 +1,40 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { x: true }; + }, + + html: ` +

foo

+ + `, + + async test({ assert, component, target, window }) { + let input = target.querySelector('input'); + ok(input); + + input.value = 'abc'; + await input.dispatchEvent(new window.Event('input')); + + assert.equal(component.y, 'abc'); + + component.x = false; + + assert.htmlEqual( + target.innerHTML, + ` +

bar

+ + ` + ); + + input = target.querySelector('input'); + ok(input); + + input.checked = true; + await input.dispatchEvent(new window.Event('change')); + + assert.equal(component.z, true); + } +}); diff --git a/test/runtime/samples/dynamic-component-bindings/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-bindings/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-bindings/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-destroy-null/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-destroy-null/_config.js new file mode 100644 index 000000000000..8b624579ff97 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-destroy-null/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: true }; + }, + + test({ component }) { + component.x = false; + } +}); diff --git a/test/runtime/samples/dynamic-component-destroy-null/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-destroy-null/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-destroy-null/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-destroy-null/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-dirty/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-dirty/_config.js new file mode 100644 index 000000000000..ea0236dcb390 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-dirty/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; + +/** @type {string[]} */ +let calls = []; + +export default test({ + get props() { + return { calls }; + }, + + before_test() { + calls = []; + }, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + + assert.deepEqual(calls.length, 1); + + const event = new window.MouseEvent('click', { bubbles: true }); + await button?.dispatchEvent(event); + + assert.deepEqual(calls.length, 1); + + component.current_path = 'bar'; + assert.deepEqual(calls.length, 2); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-dirty/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-dirty/main.svelte new file mode 100644 index 000000000000..37317e98aada --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-dirty/main.svelte @@ -0,0 +1,16 @@ + + + + +{i} diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp1.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp1.svelte new file mode 100644 index 000000000000..d4fe28a8a370 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp1.svelte @@ -0,0 +1,5 @@ + + +

value(1) = {value}

diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp2.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp2.svelte new file mode 100644 index 000000000000..07d41f3d8464 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/Comp2.svelte @@ -0,0 +1,5 @@ + + +

value(2) = {value}

diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/_config.js new file mode 100644 index 000000000000..ff3f22ac61e3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/_config.js @@ -0,0 +1,35 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

value(1) = 1

+ + `, + + async test({ assert, component, window, target }) { + const button = target.querySelector('button'); + // @ts-ignore + button.dispatchEvent(new window.Event('click')); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +

value(2) = 2

+ + ` + ); + assert.equal(component.n, 2); + // @ts-ignore + button.dispatchEvent(new window.Event('click')); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +

value(1) = 3

+ + ` + ); + assert.equal(component.n, 3); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/main.svelte new file mode 100644 index 000000000000..3a5805b3e546 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-evals-props-once/main.svelte @@ -0,0 +1,12 @@ + + + + + + diff --git a/test/runtime/samples/dynamic-component-events/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-events/Bar.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-events/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-events/Bar.svelte diff --git a/test/runtime/samples/dynamic-component-events/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-events/Foo.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-events/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-events/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-events/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-events/_config.js new file mode 100644 index 000000000000..7e92142cf939 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-events/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: true }; + }, + + html: ` + + `, + + test({ assert, component, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + + target.querySelector('button')?.dispatchEvent(click); + assert.equal(component.selected, 'foo'); + + component.x = false; + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + + target.querySelector('button')?.dispatchEvent(click); + assert.equal(component.selected, 'bar'); + } +}); diff --git a/test/runtime/samples/dynamic-component-events/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-events/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-events/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-events/main.svelte diff --git a/test/runtime/samples/dynamic-component-in-if/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if-initial-falsy/Foo.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-in-if/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if-initial-falsy/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if-initial-falsy/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if-initial-falsy/_config.js new file mode 100644 index 000000000000..1acbf9b07379 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if-initial-falsy/_config.js @@ -0,0 +1,32 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + `, + + test({ assert, component, target }) { + const [btn1, btn2] = target.querySelectorAll('button'); + + flushSync(() => btn1.click()); + assert.htmlEqual( + target.innerHTML, + ` + + +

Foo

+ ` + ); + + flushSync(() => btn2.click()); + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if-initial-falsy/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if-initial-falsy/main.svelte new file mode 100644 index 000000000000..c275f6b4fd16 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if-initial-falsy/main.svelte @@ -0,0 +1,15 @@ + + + + + +{#if show} + +{/if} diff --git a/test/runtime/samples/dynamic-component-in-if/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if/Bar.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-in-if/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if/Bar.svelte diff --git a/test/runtime/samples/dynamic-component-nulled-out/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if/Foo.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-nulled-out/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if/_config.js new file mode 100644 index 000000000000..7c63162c70e1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

Foo

+ `, + + test({ assert, component, target }) { + component.x = component.Bar; + + assert.htmlEqual( + target.innerHTML, + ` +

Bar

+ ` + ); + } +}); diff --git a/test/runtime/samples/dynamic-component-in-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-in-if/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-in-if/main.svelte diff --git a/test/runtime/samples/dynamic-component-inside-element/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-inside-element/Bar.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-inside-element/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-inside-element/Bar.svelte diff --git a/test/runtime/samples/dynamic-component-inside-element/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-inside-element/Foo.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-inside-element/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-inside-element/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-inside-element/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-inside-element/_config.js new file mode 100644 index 000000000000..85cb64a27c5f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-inside-element/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: true }; + }, + + html: ` +

true, therefore Foo

+ `, + + test({ assert, component, target }) { + component.x = false; + + assert.htmlEqual( + target.innerHTML, + ` +

false, therefore Bar

+ ` + ); + } +}); diff --git a/test/runtime/samples/dynamic-component-inside-element/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-inside-element/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-inside-element/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-inside-element/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out-intro/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out-intro/_config.js new file mode 100644 index 000000000000..06694718850a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out-intro/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ component }) { + component.visible = true; + } +}); diff --git a/test/runtime/samples/dynamic-component-nulled-out-intro/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out-intro/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-nulled-out-intro/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out-intro/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out/Foo.svelte new file mode 100644 index 000000000000..c62ee08e19f5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out/Foo.svelte @@ -0,0 +1 @@ +

Foo

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out/_config.js new file mode 100644 index 000000000000..e0a6966ab2ce --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

Foo

+ `, + + test({ assert, component, target }) { + const Bar = component.Bar; + + component.Bar = null; + + assert.htmlEqual(target.innerHTML, ''); + + component.Bar = Bar; + + assert.htmlEqual( + target.innerHTML, + ` +

Foo

+ ` + ); + } +}); diff --git a/test/runtime/samples/dynamic-component-nulled-out/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-nulled-out/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-nulled-out/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-ref/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-ref/Foo.svelte new file mode 100644 index 000000000000..bbbc91ceb827 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-ref/Foo.svelte @@ -0,0 +1,5 @@ + + +Foo diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-ref/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-ref/_config.js new file mode 100644 index 000000000000..dee136120339 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-ref/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: 'Foo', + + test({ assert, component }) { + assert.ok(component.test); + } +}); diff --git a/test/runtime/samples/dynamic-component-ref/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-ref/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-ref/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-ref/main.svelte diff --git a/test/runtime/samples/dynamic-component-slot/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/Bar.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-slot/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/Bar.svelte diff --git a/test/runtime/samples/dynamic-component-slot/Baz.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/Baz.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-slot/Baz.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/Baz.svelte diff --git a/test/runtime/samples/dynamic-component-slot/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/Foo.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-slot/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/_config.js new file mode 100644 index 000000000000..c77076af1ade --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/_config.js @@ -0,0 +1,40 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: true }; + }, + + html: ` +

Foo

+
what goes up must come down
+

element

+ you're it +

neither foo nor bar

+ text + a + b + c +
baz
+ `, + + test({ assert, component, target }) { + component.x = false; + + assert.htmlEqual( + target.innerHTML, + ` +

Bar

+

element

+ you're it +

neither foo nor bar

+ text + a + b + c +
baz
+
what goes up must come down
+ ` + ); + } +}); diff --git a/test/runtime/samples/dynamic-component-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-slot/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-slot/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp1.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp1.svelte new file mode 100644 index 000000000000..e87e7ec69912 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp1.svelte @@ -0,0 +1,9 @@ + + +

value(1) = {value}

+

foo={foo}

+

typeof cb={typeof cb}

diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp2.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp2.svelte new file mode 100644 index 000000000000..06c4c7acfe74 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/Comp2.svelte @@ -0,0 +1,9 @@ + + +

value(2) = {value}

+

foo={foo}

+

typeof cb={typeof cb}

diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/_config.js new file mode 100644 index 000000000000..643066abb58a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/_config.js @@ -0,0 +1,39 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

value(1) = 1

+

foo=bar

+

typeof cb=function

+ + `, + + test({ assert, window, target }) { + const button = target.querySelector('button'); + // @ts-ignore + button.dispatchEvent(new window.Event('click')); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +

value(2) = 2

+

foo=bar

+

typeof cb=function

+ + ` + ); + // @ts-ignore + button.dispatchEvent(new window.Event('click')); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +

value(1) = 1

+

foo=bar

+

typeof cb=function

+ + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/main.svelte new file mode 100644 index 000000000000..082ebbcda26e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-spread-props/main.svelte @@ -0,0 +1,14 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-this/Test.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-this/Test.svelte new file mode 100644 index 000000000000..fddcf1803a31 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-this/Test.svelte @@ -0,0 +1,3 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-this/_config.js new file mode 100644 index 000000000000..f9df7b78a91e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-this/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + test({ assert, component, target }) { + // Shouldn't error + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-this/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-this/main.svelte new file mode 100644 index 000000000000..6b0fe3fe2b72 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-this/main.svelte @@ -0,0 +1,7 @@ + + + diff --git a/test/runtime/samples/dynamic-component-update-existing-instance/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-update-existing-instance/Bar.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-update-existing-instance/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-update-existing-instance/Bar.svelte diff --git a/test/runtime/samples/dynamic-component-update-existing-instance/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-update-existing-instance/Foo.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-update-existing-instance/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-update-existing-instance/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component-update-existing-instance/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-update-existing-instance/_config.js new file mode 100644 index 000000000000..2b36a689efba --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-update-existing-instance/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 0 }; + }, + + html: ` +

Bar 0

+ `, + + test({ assert, component, target }) { + component.x = 1; + + assert.htmlEqual( + target.innerHTML, + ` +

Foo 1

+ ` + ); + } +}); diff --git a/test/runtime/samples/dynamic-component-update-existing-instance/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component-update-existing-instance/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component-update-existing-instance/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component-update-existing-instance/main.svelte diff --git a/test/runtime/samples/dynamic-component/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component/Bar.svelte similarity index 100% rename from test/runtime/samples/dynamic-component/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component/Bar.svelte diff --git a/test/runtime/samples/dynamic-component/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component/Foo.svelte similarity index 100% rename from test/runtime/samples/dynamic-component/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-component/_config.js new file mode 100644 index 000000000000..c48d594b0f74 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-component/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: true }; + }, + + html: ` +

true, therefore Foo

+ `, + + test({ assert, component, target }) { + component.x = false; + + assert.htmlEqual( + target.innerHTML, + ` +

false, therefore Bar

+ ` + ); + } +}); diff --git a/test/runtime/samples/dynamic-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-component/main.svelte similarity index 100% rename from test/runtime/samples/dynamic-component/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/dynamic-component/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-action-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-action-update/_config.js new file mode 100644 index 000000000000..f36d4084d53b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-action-update/_config.js @@ -0,0 +1,50 @@ +import { test } from '../../test'; + +/** @type {string[]} */ +let logs = []; + +export default test({ + html: ` +

tag is h1.

+ `, + get props() { + return { + /** @type {string | false} */ + tag: 'h1', + /** @param {string} log */ + pushLogs(log) { + logs.push(log); + } + }; + }, + after_test() { + logs = []; + }, + + async test({ assert, component, target }) { + assert.equal(component.tag, 'h1'); + + assert.deepEqual(logs, ['create: h1,opt1']); + component.opt = 'opt2'; + + assert.equal(component.tag, 'h1'); + assert.deepEqual(logs, ['create: h1,opt1', 'update: h1,opt2']); + + component.tag = 'h2'; + + assert.equal(component.tag, 'h2'); + assert.deepEqual(logs, ['create: h1,opt1', 'update: h1,opt2', 'destroy', 'create: h2,opt2']); + assert.htmlEqual(target.innerHTML, '

tag is h2.

'); + + component.tag = false; + assert.deepEqual(logs, [ + 'create: h1,opt1', + 'update: h1,opt2', + 'destroy', + 'create: h2,opt2', + 'destroy' + ]); + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-action-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-action-update/main.svelte new file mode 100644 index 000000000000..f6ffe49ec306 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-action-update/main.svelte @@ -0,0 +1,14 @@ + + +tag is {tag}. diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation-2/_config.js new file mode 100644 index 000000000000..364a30066cc5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation-2/_config.js @@ -0,0 +1,119 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +/** @type {() => DOMRect} */ +let originalDivGetBoundingClientRect; +/** @type {() => DOMRect} */ +let originalSpanGetBoundingClientRect; +/** @type {() => DOMRect} */ +let originalParagraphGetBoundingClientRect; + +export default test({ + mode: ['client', 'hydrate'], // no animations in SSR + get props() { + return { + things: [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ], + tag: 'div' + }; + }, + + html: ` +
a
+
b
+
c
+
d
+
e
+ `, + + before_test() { + originalDivGetBoundingClientRect = window.HTMLDivElement.prototype.getBoundingClientRect; + originalSpanGetBoundingClientRect = window.HTMLSpanElement.prototype.getBoundingClientRect; + originalParagraphGetBoundingClientRect = + window.HTMLParagraphElement.prototype.getBoundingClientRect; + + window.HTMLDivElement.prototype.getBoundingClientRect = fakeGetBoundingClientRect; + window.HTMLSpanElement.prototype.getBoundingClientRect = fakeGetBoundingClientRect; + window.HTMLParagraphElement.prototype.getBoundingClientRect = fakeGetBoundingClientRect; + + /** + * @this {HTMLElement} + */ + function fakeGetBoundingClientRect() { + const index = [...(this.parentNode?.children ?? [])].indexOf(this); + const top = index * 30; + + return /** @type {DOMRect} */ ({ + left: 0, + right: 100, + top, + bottom: top + 20 + }); + } + }, + after_test() { + window.HTMLDivElement.prototype.getBoundingClientRect = originalDivGetBoundingClientRect; + window.HTMLSpanElement.prototype.getBoundingClientRect = originalSpanGetBoundingClientRect; + window.HTMLParagraphElement.prototype.getBoundingClientRect = + originalParagraphGetBoundingClientRect; + }, + + async test({ assert, component, raf }) { + // switch tag and things at the same time + flushSync(() => { + component.update('p', [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]); + }); + + const ps = /** @type {NodeListOf} */ ( + document.querySelectorAll('p') + ); + raf.tick(0); + assert.equal(ps[0].dy, 120); + assert.equal(ps[4].dy, -120); + + raf.tick(50); + assert.equal(ps[0].dy, 60); + assert.equal(ps[4].dy, -60); + + raf.tick(100); + assert.equal(ps[0].dy, 0); + assert.equal(ps[4].dy, 0); + + flushSync(() => { + component.update('span', [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ]); + }); + + const spans = /** @type {NodeListOf} */ ( + document.querySelectorAll('span') + ); + + raf.tick(100); + assert.equal(spans[0].dy, 120); + assert.equal(spans[4].dy, -120); + + raf.tick(150); + assert.equal(spans[0].dy, 60); + assert.equal(spans[4].dy, -60); + + raf.tick(200); + assert.equal(spans[0].dy, 0); + assert.equal(spans[4].dy, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation-2/main.svelte new file mode 100644 index 000000000000..f655a40af9bd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation-2/main.svelte @@ -0,0 +1,26 @@ + + +{#each things as thing (thing.id)} + {thing.name} +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation/_config.js new file mode 100644 index 000000000000..05c2dc73048a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation/_config.js @@ -0,0 +1,65 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + things: [ + { id: 1, name: 'a' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 5, name: 'e' } + ], + tag: 'div' + }; + }, + + html: ` +
a
+
b
+
c
+
d
+
e
+ `, + + test({ assert, component, target, raf }) { + component.tag = 'p'; + assert.equal(target.querySelectorAll('p').length, 5); + + component.tag = 'div'; + let divs = target.querySelectorAll('div'); + divs.forEach((div) => { + div.getBoundingClientRect = function () { + const index = [...(this.parentNode?.children ?? [])].indexOf(this); + const top = index * 30; + + return /** @type {DOMRect} */ ({ + left: 0, + right: 100, + top, + bottom: top + 20 + }); + }; + }); + + component.things = [ + { id: 5, name: 'e' }, + { id: 2, name: 'b' }, + { id: 3, name: 'c' }, + { id: 4, name: 'd' }, + { id: 1, name: 'a' } + ]; + + raf.tick(0); + + divs = target.querySelectorAll('div'); + assert.equal(divs[0].style.transform, 'translate(0px, 120px)'); + assert.equal(divs[1].style.transform, ''); + assert.equal(divs[2].style.transform, ''); + assert.equal(divs[3].style.transform, ''); + assert.equal(divs[4].style.transform, 'translate(0px, -120px)'); + + raf.tick(100); + assert.deepEqual([divs[0].style.transform, divs[4].style.transform], ['', '']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation/main.svelte new file mode 100644 index 000000000000..0fa9fecf30d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-animation/main.svelte @@ -0,0 +1,18 @@ + + +{#each things as thing (thing.id)} + {thing.name} +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-boolean/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-boolean/_config.js new file mode 100644 index 000000000000..bc3c0df8d0d2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-boolean/_config.js @@ -0,0 +1,19 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { disabled: false }; + }, + html: '', + + test({ assert, component, target }) { + const button = target.querySelector('button'); + ok(button); + + assert.equal(button.disabled, false); + + component.disabled = true; + assert.htmlEqual(target.innerHTML, ''); + assert.equal(button.disabled, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-boolean/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-boolean/main.svelte new file mode 100644 index 000000000000..9fe3103dc426 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-boolean/main.svelte @@ -0,0 +1,5 @@ + + +Click me diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-spread/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-spread/_config.js new file mode 100644 index 000000000000..94a14b1f540e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-spread/_config.js @@ -0,0 +1,29 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {Record} */ + props: { + disabled: true, + type: 'button', + 'data-named': 'foo' + } + }; + }, + html: '', + + test({ assert, component, target }) { + const button = target.querySelector('button'); + ok(button); + assert.equal(button.disabled, true); + assert.equal(button.type, 'button'); + assert.equal(button.dataset.named, 'foo'); + + component.props = { type: 'submit' }; + assert.htmlEqual(target.innerHTML, ''); + assert.equal(button.disabled, false); + assert.equal(button.type, 'submit'); + assert.equal(button.dataset.named, undefined); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-spread/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-spread/main.svelte new file mode 100644 index 000000000000..1822f828c0a3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute-spread/main.svelte @@ -0,0 +1,9 @@ + + +Click me diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute/_config.js new file mode 100644 index 000000000000..b8e83d5a8e2c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { tag: 'div' }; + }, + html: '
Foo
', + + test({ assert, component, target }) { + component.tag = 'h1'; + + assert.htmlEqual( + target.innerHTML, + ` +

Foo

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute/main.svelte new file mode 100644 index 000000000000..2498e06de9e6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-attribute/main.svelte @@ -0,0 +1,5 @@ + + +Foo diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-binding-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-binding-this/_config.js new file mode 100644 index 000000000000..34554143b4c5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-binding-this/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: '
', + + test({ assert, component, target }) { + const div = target.querySelector('div'); + assert.equal(div, component.foo); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-binding-this/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-binding-this/main.svelte new file mode 100644 index 000000000000..75e8b02ce161 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-binding-this/main.svelte @@ -0,0 +1,6 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-change-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-change-tag/_config.js new file mode 100644 index 000000000000..09331bfa4b4c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-change-tag/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { tag: 'div' }; + }, + html: '
Foo
', + + test({ assert, component, target }) { + component.tag = 'h1'; + + assert.htmlEqual( + target.innerHTML, + ` +

Foo

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-change-tag/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-change-tag/main.svelte new file mode 100644 index 000000000000..a9c4d5c00c74 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-change-tag/main.svelte @@ -0,0 +1,5 @@ + + +Foo \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-class-directive/Link.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-class-directive/Link.svelte new file mode 100644 index 000000000000..5d1edf4662b4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-class-directive/Link.svelte @@ -0,0 +1,13 @@ + + + + {item.text} + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-class-directive/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-class-directive/_config.js new file mode 100644 index 000000000000..76fe15a16ebe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-class-directive/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
foo
+
foo0
+
foo0
+
foo0
+
foo1
+
foo2
+
foo3
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-class-directive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-class-directive/main.svelte new file mode 100644 index 000000000000..58e9303100b6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-class-directive/main.svelte @@ -0,0 +1,16 @@ + + + + + +{#each foo as item} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-empty-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-empty-tag/_config.js new file mode 100644 index 000000000000..653ccc21927f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-empty-tag/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-empty-tag/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-empty-tag/main.svelte new file mode 100644 index 000000000000..e3889ce0f5c7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-empty-tag/main.svelte @@ -0,0 +1,5 @@ + + +Foo diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler1/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler1/_config.js new file mode 100644 index 000000000000..6ddd8930bdbe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler1/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +let clicked = false; +function handler() { + clicked = true; +} + +export default test({ + get props() { + return { handler }; + }, + html: '', + + before_test() { + clicked = false; + }, + + test({ assert, target }) { + assert.equal(clicked, false); + + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + button?.dispatchEvent(click); + + assert.equal(clicked, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler1/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler1/main.svelte new file mode 100644 index 000000000000..7a7fef9c22cf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler1/main.svelte @@ -0,0 +1,6 @@ + + +Foo \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler2/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler2/_config.js new file mode 100644 index 000000000000..38211ccb6c40 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler2/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; + +let clicked = false; +function handler() { + clicked = true; +} + +export default test({ + get props() { + return { tag: 'div', handler }; + }, + html: '
Foo
', + + before_test() { + clicked = false; + }, + + test({ assert, component, target }) { + assert.equal(clicked, false); + + component.tag = 'button'; + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + button?.dispatchEvent(click); + + assert.equal(clicked, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler2/main.svelte new file mode 100644 index 000000000000..f2534c1f62a8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler2/main.svelte @@ -0,0 +1,6 @@ + + +Foo diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler3/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler3/_config.js new file mode 100644 index 000000000000..01c02087f779 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler3/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, logs, target }) { + const button = target.querySelector('button'); + + button?.click(); + button?.click(); + button?.click(); + + assert.deepEqual(logs, ['create', 'trigger', 'trigger', 'trigger']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler3/main.svelte new file mode 100644 index 000000000000..38d088503999 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-event-handler3/main.svelte @@ -0,0 +1,9 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-expression/_config.js new file mode 100644 index 000000000000..7161c045b5e8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-expression/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
Foo
' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-expression/main.svelte new file mode 100644 index 000000000000..7ec11e4ef6d8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-expression/main.svelte @@ -0,0 +1 @@ +Foo \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-invalid-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-invalid-this/_config.js new file mode 100644 index 000000000000..357390a029a9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-invalid-this/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'server'], // SSR errors on render already + + compileOptions: { + dev: true + }, + + get props() { + return { tag: 123 }; + }, + + error: + 'svelte_element_invalid_this_value\n' + + 'The `this` prop on `` must be a string, if defined' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-invalid-this/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-invalid-this/main.svelte new file mode 100644 index 000000000000..bcc2c293bb24 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-invalid-this/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-null-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-null-tag/_config.js new file mode 100644 index 000000000000..653ccc21927f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-null-tag/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-null-tag/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-null-tag/main.svelte new file mode 100644 index 000000000000..58dc96ff2a17 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-null-tag/main.svelte @@ -0,0 +1,5 @@ + + +Foo diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-pass-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-pass-props/_config.js new file mode 100644 index 000000000000..35aa42e3e8d6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-pass-props/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +let clicked = false; + +export default test({ + get props() { + return { + tag: 'div', + onClick: () => (clicked = true) + }; + }, + html: '
Foo
', + + async test({ assert, target, window }) { + const div = target.querySelector('div'); + await div?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + + assert.equal(clicked, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-pass-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-pass-props/main.svelte new file mode 100644 index 000000000000..6a54a93f2718 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-pass-props/main.svelte @@ -0,0 +1,6 @@ + + +Foo \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-slot/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-slot/Foo.svelte new file mode 100644 index 000000000000..51dda4b7e38d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-slot/Foo.svelte @@ -0,0 +1,7 @@ +

Foo

+
+ +
+
+ +
diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-slot/_config.js new file mode 100644 index 000000000000..615016522bc1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-slot/_config.js @@ -0,0 +1,34 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: true }; + }, + + html: ` +

Foo

+
+

This is default slot

+
+
+

This is other slot

+
+ `, + + test({ assert, component, target }) { + component.tag = 'h2'; + + assert.htmlEqual( + target.innerHTML, + ` +

Foo

+
+

This is default slot

+
+
+

This is other slot

+
+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-slot/main.svelte new file mode 100644 index 000000000000..4b1cd81969e3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-slot/main.svelte @@ -0,0 +1,10 @@ + + + + This is default slot + This is other slot + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-spread-attributes/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-spread-attributes/_config.js new file mode 100644 index 000000000000..a314ed0eed3f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-spread-attributes/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
this is a div
' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-spread-attributes/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-spread-attributes/main.svelte new file mode 100644 index 000000000000..54aa7bea7d74 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-spread-attributes/main.svelte @@ -0,0 +1,8 @@ + + +this is a div diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-store/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-store/_config.js new file mode 100644 index 000000000000..8ff46df1b1f5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-store/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-store/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-store/main.svelte new file mode 100644 index 000000000000..6a7952a404ff --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-store/main.svelte @@ -0,0 +1,6 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-string/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-string/_config.js new file mode 100644 index 000000000000..7161c045b5e8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-string/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
Foo
' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-string/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-string/main.svelte new file mode 100644 index 000000000000..0f45eaeb24bd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-string/main.svelte @@ -0,0 +1 @@ +Foo diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-implicit-namespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-implicit-namespace/_config.js new file mode 100644 index 000000000000..136dc92f54c5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-implicit-namespace/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target }) { + const svg = target.querySelector('svg'); + const rect = target.querySelector('path'); + assert.equal(svg?.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(rect?.namespaceURI, 'http://www.w3.org/2000/svg'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-implicit-namespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-implicit-namespace/main.svelte new file mode 100644 index 000000000000..9d190b7b2d56 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-implicit-namespace/main.svelte @@ -0,0 +1,10 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace-2/_config.js new file mode 100644 index 000000000000..6eb8ef7e1977 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace-2/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const path = target.querySelector('path'); + + assert.equal(path?.namespaceURI, 'http://www.w3.org/2000/svg'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace-2/main.svelte new file mode 100644 index 000000000000..0a3c1954bc52 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace-2/main.svelte @@ -0,0 +1,11 @@ + + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace-2/svg.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace-2/svg.svelte new file mode 100644 index 000000000000..5932e7863f61 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace-2/svg.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace/_config.js new file mode 100644 index 000000000000..999b8fc9b5fd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const [svg1, svg2] = target.querySelectorAll('svg'); + const [path1, path2] = target.querySelectorAll('path'); + const [fO1, fO2] = target.querySelectorAll('foreignObject'); + const [span1, span2] = target.querySelectorAll('span'); + + assert.equal(svg1.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(path1.namespaceURI, 'http://www.w3.org/2000/svg'); + + assert.equal(svg2.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(path2.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(fO1.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(span1.namespaceURI, 'http://www.w3.org/1999/xhtml'); + assert.equal(fO2.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(span2.namespaceURI, 'http://www.w3.org/1999/xhtml'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace/main.svelte new file mode 100644 index 000000000000..4dadcde018fa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-inherit-namespace/main.svelte @@ -0,0 +1,22 @@ + + + + {#each iconNode as [tag, attrs]} + + {/each} + + + + + + ok + + + {#if true} + ok + {/if} + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-options-namespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-options-namespace/_config.js new file mode 100644 index 000000000000..a18ad5dc1059 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-options-namespace/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target }) { + const svg = target.querySelector('svg'); + const rect = target.querySelector('rect'); + assert.equal(svg?.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(rect?.namespaceURI, 'http://www.w3.org/2000/svg'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-options-namespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-options-namespace/main.svelte new file mode 100644 index 000000000000..0cc8a2a1f3f6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-options-namespace/main.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-options-namespace/rect.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-options-namespace/rect.svelte new file mode 100644 index 000000000000..e7472917148c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg-options-namespace/rect.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg/_config.js new file mode 100644 index 000000000000..b0f98886f700 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target }) { + const svg = target.querySelector('svg'); + const rect = target.querySelector('path'); + assert.equal(svg?.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(rect?.namespaceURI, 'http://www.w3.org/2000/svg'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg/main.svelte new file mode 100644 index 000000000000..15c233fd9ad1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-svg/main.svelte @@ -0,0 +1,3 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-template-literals/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-template-literals/_config.js new file mode 100644 index 000000000000..0d66d14aa1a6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-template-literals/_config.js @@ -0,0 +1,23 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { size: 1 }; + }, + html: '

This is h1 tag

', + + test({ assert, component, target }) { + const h1 = target.querySelector('h1'); + component.size = 2; + + assert.htmlEqual( + target.innerHTML, + ` +

This is h2 tag

+ ` + ); + + const h2 = target.querySelector('h2'); + assert.notEqual(h1, h2); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-template-literals/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-template-literals/main.svelte new file mode 100644 index 000000000000..84b63dcca70d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-template-literals/main.svelte @@ -0,0 +1,5 @@ + + +This is h{size} tag diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-textarea/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-textarea/_config.js new file mode 100644 index 000000000000..4c0967dae67a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-textarea/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target }) { + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-textarea/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-textarea/main.svelte new file mode 100644 index 000000000000..e7378a397969 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-textarea/main.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-transition/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-transition/_config.js new file mode 100644 index 000000000000..6b55bcf44cbf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-transition/_config.js @@ -0,0 +1,23 @@ +import { ok, test } from '../../test'; + +export default test({ + test({ assert, component, target, raf }) { + component.visible = true; + const h1 = target.querySelector('h1'); + ok(h1); + raf.tick(0); + assert.equal(h1.style.opacity, '0'); + + raf.tick(150); + component.tag = 'h2'; + const h2 = target.querySelector('h2'); + ok(h2); + assert.equal(h1.style.opacity, ''); + assert.equal(h2.style.opacity, ''); + + raf.tick(200); + component.visible = false; + raf.tick(250); + assert.equal(h2.style.opacity, '0.5'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-transition/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-transition/main.svelte new file mode 100644 index 000000000000..b30d948d6b30 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-transition/main.svelte @@ -0,0 +1,17 @@ + + +{#if visible} + +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-undefined-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-undefined-tag/_config.js new file mode 100644 index 000000000000..f2118ef5794c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-undefined-tag/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + html: '', + test({ component, target, assert }) { + component.tag = 'h1'; + assert.htmlEqual(target.innerHTML, '

Foo

'); + + component.tag = null; + assert.htmlEqual(target.innerHTML, ''); + + component.tag = 'div'; + assert.htmlEqual(target.innerHTML, '
Foo
'); + + component.tag = false; + assert.htmlEqual(target.innerHTML, ''); + + component.tag = 'span'; + assert.htmlEqual(target.innerHTML, 'Foo'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-undefined-tag/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-undefined-tag/main.svelte new file mode 100644 index 000000000000..6aca93ca1319 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-undefined-tag/main.svelte @@ -0,0 +1,5 @@ + + +Foo diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-variable/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-variable/_config.js new file mode 100644 index 000000000000..5b1ff747b1b9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-variable/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { tag: 'div', text: 'Foo' }; + }, + html: '
Foo
', + + test({ assert, component, target }) { + const div = target.querySelector('div'); + component.tag = 'nav'; + component.text = 'Bar'; + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + + const nav = target.querySelector('nav'); + assert.notEqual(div, nav); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-variable/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-variable/main.svelte new file mode 100644 index 000000000000..d60953bba5de --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-variable/main.svelte @@ -0,0 +1,6 @@ + + +{text} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-tag/_config.js new file mode 100644 index 000000000000..23aeab8a67b3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-tag/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { propTag: 'hr' }; + }, + html: '



', + + test({ assert, component, target }) { + assert.htmlEqual(target.innerHTML, '



'); + component.propTag = 'link'; + assert.htmlEqual(target.innerHTML, '


'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-tag/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-tag/main.svelte new file mode 100644 index 000000000000..00a130bc9947 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-tag/main.svelte @@ -0,0 +1,12 @@ + + +

+ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-1/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-1/_config.js new file mode 100644 index 000000000000..d880635a59f9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-1/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + get props() { + return { tag: 'br' }; + }, + warnings: ['`` is a void element — it cannot have content'] +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-1/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-1/main.svelte new file mode 100644 index 000000000000..bcf3fed2c3aa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-1/main.svelte @@ -0,0 +1,5 @@ + + +foo diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-2/_config.js new file mode 100644 index 000000000000..d880635a59f9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-2/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + get props() { + return { tag: 'br' }; + }, + warnings: ['`` is a void element — it cannot have content'] +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-2/main.svelte new file mode 100644 index 000000000000..02256545455e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-2/main.svelte @@ -0,0 +1,5 @@ + + +
bar
diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-3/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-3/Nested.svelte new file mode 100644 index 000000000000..e62294a13538 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-3/Nested.svelte @@ -0,0 +1 @@ +
This is nested
diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-3/_config.js new file mode 100644 index 000000000000..d880635a59f9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-3/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + get props() { + return { tag: 'br' }; + }, + warnings: ['`` is a void element — it cannot have content'] +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-3/main.svelte new file mode 100644 index 000000000000..97045e176640 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-3/main.svelte @@ -0,0 +1,6 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-4/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-4/Nested.svelte new file mode 100644 index 000000000000..e62294a13538 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-4/Nested.svelte @@ -0,0 +1 @@ +
This is nested
diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-4/_config.js new file mode 100644 index 000000000000..51e056d429d1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-4/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + get props() { + return { tag: 'br' }; + }, + html: '
', + warnings: ['`` is a void element — it cannot have content'] +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-4/main.svelte new file mode 100644 index 000000000000..97045e176640 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-4/main.svelte @@ -0,0 +1,6 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-5/_config.js b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-5/_config.js new file mode 100644 index 000000000000..86f63d9d32c6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-5/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + warnings: ['`` is a void element — it cannot have content'] +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-5/main.svelte b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-5/main.svelte new file mode 100644 index 000000000000..990772b1e6ec --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/dynamic-element-void-with-content-5/main.svelte @@ -0,0 +1,10 @@ + + +{#each tags as tag} + {tag.t}
+ + {#if tag.t !== 'input'}{tag.content}{/if} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-after-let/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-after-let/Child.svelte new file mode 100644 index 000000000000..35102eaaa6ab --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-after-let/Child.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-after-let/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-after-let/_config.js new file mode 100644 index 000000000000..10466c3abc71 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-after-let/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
a a
+
b
+
a a
+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-after-let/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-after-let/main.svelte new file mode 100644 index 000000000000..6a9b99442a9d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-after-let/main.svelte @@ -0,0 +1,16 @@ + + +
+ {value[0]} + {#each value as n}{n}{/each} +
+
+ {value[0]} +
+
+ {value[0]} + {#each value as n}{n}{/each} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-array-literal/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-array-literal/_config.js new file mode 100644 index 000000000000..53da79e33ef6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-array-literal/_config.js @@ -0,0 +1,26 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + + `, + + test({ assert, component, target }) { + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + + const button = target.querySelector('button'); + ok(button); + + const event = new window.Event('click', { bubbles: true }); + + button.dispatchEvent(event); + assert.equal(component.clicked, 'racoon'); + } +}); diff --git a/test/runtime/samples/each-block-array-literal/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-array-literal/main.svelte similarity index 100% rename from test/runtime/samples/each-block-array-literal/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-array-literal/main.svelte diff --git a/test/runtime/samples/each-block-component-no-props/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-component-no-props/Child.svelte similarity index 100% rename from test/runtime/samples/each-block-component-no-props/Child.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-component-no-props/Child.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-component-no-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-component-no-props/_config.js new file mode 100644 index 000000000000..2cc7eee06a62 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-component-no-props/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

hello

+ `, + + async test({ assert, component, target }) { + await component.remove(); + assert.htmlEqual(target.innerHTML, ''); + + await component.add(); + assert.htmlEqual(target.innerHTML, '

hello

'); + + await component.remove(); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/each-block-component-no-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-component-no-props/main.svelte similarity index 100% rename from test/runtime/samples/each-block-component-no-props/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-component-no-props/main.svelte diff --git a/test/runtime/samples/each-block-containing-component-in-if/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-containing-component-in-if/Nested.svelte similarity index 100% rename from test/runtime/samples/each-block-containing-component-in-if/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-containing-component-in-if/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-containing-component-in-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-containing-component-in-if/_config.js new file mode 100644 index 000000000000..de6168a04374 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-containing-component-in-if/_config.js @@ -0,0 +1,39 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { show: false, fields: [1, 2] }; + }, + + html: '
', + + test({ assert, component, target }) { + component.show = true; + component.fields = [1, 2, 3]; + + assert.htmlEqual( + target.innerHTML, + ` +
+ 1 + 2 + 3 +
+ ` + ); + + component.fields = [1, 2, 3, 4]; + + assert.htmlEqual( + target.innerHTML, + ` +
+ 1 + 2 + 3 + 4 +
+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-containing-component-in-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-containing-component-in-if/main.svelte similarity index 100% rename from test/runtime/samples/each-block-containing-component-in-if/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-containing-component-in-if/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-containing-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-containing-if/_config.js new file mode 100644 index 000000000000..66a98a9ef6ba --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-containing-if/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component, target }) { + const items = /** @type {Array<{ description: string; completed: boolean }>} */ ( + component.items + ); + items.forEach((item) => (item.completed = false)); + + component.currentFilter = 'all'; + + assert.htmlEqual( + target.innerHTML, + ` +
  • one
  • two
  • three
+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-containing-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-containing-if/main.svelte similarity index 100% rename from test/runtime/samples/each-block-containing-if/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-containing-if/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-deconflict-name-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-deconflict-name-context/_config.js new file mode 100644 index 000000000000..5471dabbf165 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-deconflict-name-context/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: { bar: ['x', 'y', 'z'] } }; + }, + + html: ` + + + + `, + + ssrHtml: ` + + + + `, + + test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + + inputs[1].value = 'w'; + inputs[1].dispatchEvent(new window.MouseEvent('input')); + + assert.deepEqual(component.foo, { + bar: ['x', 'w', 'z'] + }); + } +}); diff --git a/test/runtime/samples/each-block-deconflict-name-context/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-deconflict-name-context/main.svelte similarity index 100% rename from test/runtime/samples/each-block-deconflict-name-context/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-deconflict-name-context/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-as-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-as-object/_config.js new file mode 100644 index 000000000000..e353fed1e9a8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-as-object/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + array: [ + [1, 2, 3, 4, 5], + [6, 7, 8], + [9, 10, 11, 12] + ] + }; + }, + + html: ` +

First: 1, Third: 3, Length: 5

+

First: 6, Third: 8, Length: 3

+

First: 9, Third: 11, Length: 4

+ `, + + test({ assert, component, target }) { + component.array = [[12, 13]]; + assert.htmlEqual( + target.innerHTML, + ` +

First: 12, Third: , Length: 2

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-as-object/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-as-object/main.svelte new file mode 100644 index 000000000000..cff735555be1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-as-object/main.svelte @@ -0,0 +1,7 @@ + + +{#each array as { 0: first, '2': third, "length": length }} +

First: {first}, Third: {third}, Length: {length}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-computed-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-computed-props/_config.js new file mode 100644 index 000000000000..b3c41d57cb6c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-computed-props/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + array: [ + [1, 2, 3, 4, 5], + [6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16, 17, 18, 19, 20, 21, 22] + ] + }; + }, + + html: ` +

First: 1, Half: 3, Last: 5, Length: 5

+

First: 6, Half: 7, Last: 8, Length: 3

+

First: 9, Half: 11, Last: 12, Length: 4

+

First: 13, Half: 18, Last: 22, Length: 10

+ `, + + test({ assert, component, target }) { + component.array = [[23, 24, 25, 26, 27, 28, 29]]; + assert.htmlEqual( + target.innerHTML, + ` +

First: 23, Half: 26, Last: 29, Length: 7

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-computed-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-computed-props/main.svelte new file mode 100644 index 000000000000..00a9a99a89cc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-computed-props/main.svelte @@ -0,0 +1,7 @@ + + +{#each array as { 0: first, length, [length - 1]: last, [Math.floor(length / 2)]: half }} +

First: {first}, Half: {half}, Last: {last}, Length: {length}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-nested-rest/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-nested-rest/_config.js new file mode 100644 index 000000000000..a25adde20c72 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-nested-rest/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + array: [ + [1, 2, 3, 4, 5], + [6, 7, 8], + [9, 10, 11, 12], + [13, 14, 15, 16, 17, 18, 19, 20, 21, 22] + ] + }; + }, + + html: ` +

First: 1, Second: 2, Third: 3, Elements remaining: 2

+

First: 6, Second: 7, Third: 8, Elements remaining: 0

+

First: 9, Second: 10, Third: 11, Elements remaining: 1

+

First: 13, Second: 14, Third: 15, Elements remaining: 7

+ `, + + test({ assert, component, target }) { + component.array = [[23, 24, 25, 26, 27, 28, 29]]; + assert.htmlEqual( + target.innerHTML, + ` +

First: 23, Second: 24, Third: 25, Elements remaining: 4

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-nested-rest/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-nested-rest/main.svelte new file mode 100644 index 000000000000..fc73462464e8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-nested-rest/main.svelte @@ -0,0 +1,9 @@ + + +{#each array as [first, second, ...[third, ...{ length }]]} +

+ First: {first}, Second: {second}, Third: {third}, Elements remaining: {length} +

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-sparse/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-sparse/_config.js new file mode 100644 index 000000000000..a3fc00a1c497 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-sparse/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animalPawsEntries: [ + ['raccoon', 'hands'], + ['eagle', 'wings'] + ] + }; + }, + + html: ` +

hands

+

wings

+ `, + + test({ assert, component, target }) { + component.animalPawsEntries = [['foo', 'bar']]; + assert.htmlEqual( + target.innerHTML, + ` +

bar

+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-destructured-array-sparse/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-sparse/main.svelte similarity index 100% rename from test/runtime/samples/each-block-destructured-array-sparse/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array-sparse/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array/_config.js new file mode 100644 index 000000000000..0342a857bb46 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animalPawsEntries: [ + ['raccoon', 'hands'], + ['eagle', 'wings'] + ] + }; + }, + + html: ` +

raccoon: hands

+

eagle: wings

+ `, + + test({ assert, component, target }) { + component.animalPawsEntries = [['foo', 'bar']]; + assert.htmlEqual( + target.innerHTML, + ` +

foo: bar

+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-destructured-array/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array/main.svelte similarity index 100% rename from test/runtime/samples/each-block-destructured-array/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-destructured-array/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-before-initialised/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-before-initialised/_config.js new file mode 100644 index 000000000000..b086f7cdf89e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-before-initialised/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + error: "Cannot access 'c' before initialization" +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-before-initialised/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-before-initialised/main.svelte new file mode 100644 index 000000000000..76eb09c0de56 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-before-initialised/main.svelte @@ -0,0 +1,7 @@ + + +{#each array as { a, b = c, c }} + {a}{b}{c} +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-binding/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-binding/_config.js new file mode 100644 index 000000000000..5623a8dd53ab --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-binding/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + `, + ssrHtml: ` + + + `, + + test({ assert, component, target, window }) { + const [input1, input2] = target.querySelectorAll('input'); + assert.equal(input1.value, ''); + assert.equal(input2.value, 'hello'); + + const inputEvent = new window.InputEvent('input'); + + input2.value = 'world'; + input2.dispatchEvent(inputEvent); + assert.equal(input2.value, 'world'); + assert.equal(component.array[1].value, 'world'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-binding/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-binding/main.svelte new file mode 100644 index 000000000000..e93a01038b06 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default-binding/main.svelte @@ -0,0 +1,7 @@ + + +{#each array as { value = "hello" }} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default/_config.js new file mode 100644 index 000000000000..07e6498c9d0d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default/_config.js @@ -0,0 +1,60 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {Array>} */ + animalEntries: [ + { + animal: 'raccoon', + class: 'mammal', + species: 'P. lotor', + kilogram: 25, + bmi: 0.04 + }, + { + animal: 'eagle', + class: 'bird', + kilogram: 5.4 + }, + { + animal: 'tiger', + class: 'mammal', + kilogram: 10, + pound: 30 + }, + { + animal: 'lion', + class: 'mammal', + kilogram: 10, + height: 50 + }, + { + animal: 'leopard', + class: 'mammal', + kilogram: 30, + height: 50, + bmi: 10 + } + ] + }; + }, + + html: ` +

raccoon - P. lotor - 25kg (55 lb) - 30cm - 0.04

+

eagle - unknown - 5.4kg (12 lb) - 30cm - 0.006

+

tiger - unknown - 10kg (30 lb) - 30cm - 0.011111111111111112

+

lion - unknown - 10kg (22 lb) - 50cm - 0.004

+

leopard - unknown - 30kg (66 lb) - 50cm - 10

+ `, + + test({ assert, component, target }) { + component.animalEntries = [{ animal: 'cow', class: 'mammal', species: '‎B. taurus' }]; + assert.htmlEqual( + target.innerHTML, + ` +

cow - ‎B. taurus - 50kg (110 lb) - 30cm - 0.05555555555555555

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default/main.svelte new file mode 100644 index 000000000000..44e720e17451 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-default/main.svelte @@ -0,0 +1,8 @@ + + +{#each animalEntries as { animal, species = 'unknown', kilogram: weight = 50, pound = (weight * 2.2).toFixed(0), height = defaultHeight, bmi = weight / (height * height), ...props } } +

{animal} - {species} - {weight}kg ({pound} lb) - {height}cm - {bmi}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-binding/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-binding/_config.js new file mode 100644 index 000000000000..18bd70b9acf1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-binding/_config.js @@ -0,0 +1,55 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { + people: [{ name: { first: 'Doctor', last: 'Who' } }] + }; + }, + + html: ` + + +

Doctor Who

+ `, + + ssrHtml: ` + + +

Doctor Who

+ `, + + test({ assert, component, target, window }) { + const inputs = target.querySelectorAll('input'); + + inputs[1].value = 'Oz'; + inputs[1].dispatchEvent(new window.Event('input')); + flushSync(); + + const { people } = component; + + assert.deepEqual(people, [{ name: { first: 'Doctor', last: 'Oz' } }]); + + assert.htmlEqual( + target.innerHTML, + ` + + +

Doctor Oz

+ ` + ); + + people[0].name.first = 'Frank'; + component.people = people; + + assert.htmlEqual( + target.innerHTML, + ` + + +

Frank Oz

+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-destructured-object-binding/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-binding/main.svelte similarity index 100% rename from test/runtime/samples/each-block-destructured-object-binding/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-binding/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-computed-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-computed-props/_config.js new file mode 100644 index 000000000000..02362eff6183 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-computed-props/_config.js @@ -0,0 +1,45 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + firstString: 'cats', + secondString: 'dogs', + objectsArray: [ + { + dogs: 'woof', + cats: 'meow', + stac: 'stack', + DOGS: 'WOOF' + }, + { + dogs: 'A German sheppard', + cats: 'A tailless cat', + stac: 'A jenga tower', + DOGS: 'A GERMAN SHEPPARD' + }, + { + dogs: 'dogs', + cats: 'cats', + stac: 'stac', + DOGS: 'DOGS' + } + ] + }; + }, + + html: ` +

cats: meow

+

dogs: woof

+

stac: stack

+

DOGS: WOOF

+

cats: A tailless cat

+

dogs: A German sheppard

+

stac: A jenga tower

+

DOGS: A GERMAN SHEPPARD

+

cats: cats

+

dogs: dogs

+

stac: stac

+

DOGS: DOGS

+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-computed-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-computed-props/main.svelte new file mode 100644 index 000000000000..9c2ae2961769 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-computed-props/main.svelte @@ -0,0 +1,12 @@ + + +{#each objectsArray as { [firstString]: firstProp, [secondString]: secondProp, [firstString.split('').reverse().join('')]: reverseFirst, [secondString.toUpperCase()]: upperSecond } } +

{firstString}: {firstProp}

+

{secondString}: {secondProp}

+

{firstString.split('').reverse().join('')}: {reverseFirst}

+

{secondString.toUpperCase()}: {upperSecond}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-props/_config.js new file mode 100644 index 000000000000..418e8bf3e612 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-props/_config.js @@ -0,0 +1,41 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + objectsArray: [ + { + 'foo-bar': 'FooBar', + 0: 'zero', + prop: 'prop' + }, + { + 'foo-bar': 'foobar', + 0: 'null', + prop: 'a prop' + }, + { + 'foo-bar': 'FOO BAR', + 0: 'nada', + prop: 'the prop' + } + ] + }; + }, + + html: ` +

FooBar: prop zero

+

foobar: a prop null

+

FOO BAR: the prop nada

+ `, + + test({ assert, component, target }) { + component.objectsArray = [{ 'foo-bar': 'Fool Ball', 0: 'nil', prop: 'one prop' }]; + assert.htmlEqual( + target.innerHTML, + ` +

Fool Ball: one prop nil

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-props/main.svelte new file mode 100644 index 000000000000..08826e80e9d7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-props/main.svelte @@ -0,0 +1,7 @@ + + +{#each objectsArray as { 0: prop0, "foo-bar": propFooBar, prop: varProp } } +

{propFooBar}: {varProp} {prop0}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-rest/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-rest/_config.js new file mode 100644 index 000000000000..3915e2eda3bb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-rest/_config.js @@ -0,0 +1,50 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {Array>} */ + objectsArray: [ + { + quote: 'q1', + 'wrong-quote': 'wq1', + 16: '16', + 17: '17', + class: 'class' + }, + { + quote: 'q2', + 'wrong-quote': 'wq2', + 16: 'sixteen', + 17: 'seventeen', + class: 'glass' + }, + { + quote: 'q3', + 'wrong-quote': 'wq3', + 16: 'seize', + 17: 'dix-sept', + class: 'mass' + } + ] + }; + }, + + html: ` +

Quote: q1, Wrong Quote: wq1, 16: 16, 17: 17

+

Quote: q2, Wrong Quote: wq2, 16: sixteen, 17: seventeen

+

Quote: q3, Wrong Quote: wq3, 16: seize, 17: dix-sept

+ `, + + test({ assert, component, target }) { + component.objectsArray = [ + { quote: 'new-quote', 'wrong-quote': 'wq4', 16: 'ten+six', 17: 'ten+seven', role: 'role' } + ]; + assert.htmlEqual( + target.innerHTML, + ` +

Quote: new-quote, Wrong Quote: wq4, 16: ten+six, 17: ten+seven

+ ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-rest/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-rest/main.svelte new file mode 100644 index 000000000000..84a4f1b4fe9e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-literal-rest/main.svelte @@ -0,0 +1,7 @@ + + +{#each objectsArray as { "quote": quotedProp, "wrong-quote": wrongQuote, 16: sixteen, [10 + 7]: seventeen, ...props }} +

Quote: {quotedProp}, Wrong Quote: {wrongQuote}, 16: {sixteen}, 17: {seventeen}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-reserved-key/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-reserved-key/_config.js new file mode 100644 index 000000000000..3bd91deb619e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-reserved-key/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

bar

+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-reserved-key/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-reserved-key/main.svelte new file mode 100644 index 000000000000..c3e11c3ea1ad --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-reserved-key/main.svelte @@ -0,0 +1,7 @@ + + +{#each foo as { in: bar }} +

{bar}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-rest/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-rest/_config.js new file mode 100644 index 000000000000..c410496f93aa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-rest/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animalEntries: [ + { animal: 'raccoon', class: 'mammal' }, + { animal: 'eagle', class: 'bird' } + ] + }; + }, + + html: ` +

raccoon

+

eagle

+ `, + + test({ assert, component, target }) { + component.animalEntries = [{ animal: 'cow', class: 'mammal' }]; + assert.htmlEqual( + target.innerHTML, + ` +

cow

+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-destructured-object-rest/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-rest/main.svelte similarity index 100% rename from test/runtime/samples/each-block-destructured-object-rest/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object-rest/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object/_config.js new file mode 100644 index 000000000000..802058c1f0c2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animalPawsEntries: [ + { animal: 'raccoon', pawType: 'hands' }, + { animal: 'eagle', pawType: 'wings' } + ] + }; + }, + + html: ` +

raccoon: hands

+

eagle: wings

+ `, + + test({ assert, component, target }) { + component.animalPawsEntries = [{ animal: 'cow', pawType: 'hooves' }]; + assert.htmlEqual( + target.innerHTML, + ` +

cow: hooves

+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-destructured-object/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object/main.svelte similarity index 100% rename from test/runtime/samples/each-block-destructured-object/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-destructured-object/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-dynamic-else-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-dynamic-else-static/_config.js new file mode 100644 index 000000000000..da68f7c1a04d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-dynamic-else-static/_config.js @@ -0,0 +1,45 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animals: ['alpaca', 'baboon', 'capybara'] + }; + }, + + html: ` +

alpaca

+

baboon

+

capybara

+ `, + + test({ assert, component, target }) { + component.animals = []; + assert.htmlEqual( + target.innerHTML, + ` +

no animals

+ ` + ); + + // trigger an 'update' of the else block, to ensure that + // nonexistent update method is not called + component.animals = []; + + component.animals = ['wombat']; + assert.htmlEqual( + target.innerHTML, + ` +

wombat

+ ` + ); + + component.animals = ['dinosaur']; + assert.htmlEqual( + target.innerHTML, + ` +

dinosaur

+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-dynamic-else-static/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-dynamic-else-static/main.svelte similarity index 100% rename from test/runtime/samples/each-block-dynamic-else-static/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-dynamic-else-static/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-else-in-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-else-in-if/_config.js new file mode 100644 index 000000000000..f8069b81eb14 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-else-in-if/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

nothing

+

after

+ `, + + test({ assert, component, target }) { + component.visible = false; + assert.htmlEqual(target.innerHTML, ''); + + component.visible = true; + assert.htmlEqual( + target.innerHTML, + ` +

nothing

+

after

+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-else-in-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-else-in-if/main.svelte similarity index 100% rename from test/runtime/samples/each-block-else-in-if/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-else-in-if/main.svelte diff --git a/test/runtime/samples/each-block-else-mount-or-intro/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-else-mount-or-intro/Widget.svelte similarity index 100% rename from test/runtime/samples/each-block-else-mount-or-intro/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-else-mount-or-intro/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-else-mount-or-intro/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-else-mount-or-intro/_config.js new file mode 100644 index 000000000000..65878c66cad8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-else-mount-or-intro/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { items: [] }; + }, + html: 'No items.' +}); diff --git a/test/runtime/samples/each-block-else-mount-or-intro/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-else-mount-or-intro/main.svelte similarity index 100% rename from test/runtime/samples/each-block-else-mount-or-intro/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-else-mount-or-intro/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-else-starts-empty/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-else-starts-empty/_config.js new file mode 100644 index 000000000000..53075e88ad55 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-else-starts-empty/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {string[]} */ + animals: [], + foo: 'something else' + }; + }, + + html: ` + before +

no animals, but rather something else

+ after + `, + + test({ assert, component, target }) { + component.animals = ['wombat']; + assert.htmlEqual( + target.innerHTML, + ` + before +

wombat

+ after + ` + ); + } +}); diff --git a/test/runtime/samples/each-block-else-starts-empty/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-else-starts-empty/main.svelte similarity index 100% rename from test/runtime/samples/each-block-else-starts-empty/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-else-starts-empty/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-else/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-else/_config.js new file mode 100644 index 000000000000..43b139eeebd7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-else/_config.js @@ -0,0 +1,50 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animals: ['alpaca', 'baboon', 'capybara'], + foo: 'something else' + }; + }, + + html: ` + before +

alpaca

+

baboon

+

capybara

+ after + `, + + test({ assert, component, target }) { + component.animals = []; + assert.htmlEqual( + target.innerHTML, + ` + before +

no animals, but rather something else

+ after + ` + ); + + component.foo = 'something other'; + assert.htmlEqual( + target.innerHTML, + ` + before +

no animals, but rather something other

+ after + ` + ); + + component.animals = ['wombat']; + assert.htmlEqual( + target.innerHTML, + ` + before +

wombat

+ after + ` + ); + } +}); diff --git a/test/runtime/samples/each-block-else/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-else/main.svelte similarity index 100% rename from test/runtime/samples/each-block-else/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-else/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-empty-outro/Thing.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-empty-outro/Thing.svelte new file mode 100644 index 000000000000..d3707c7d8bfa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-empty-outro/Thing.svelte @@ -0,0 +1,5 @@ + + +

{thing}

\ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-empty-outro/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-empty-outro/_config.js new file mode 100644 index 000000000000..3ab1af60b42e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-empty-outro/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { visible: true, empty: [] }; + }, + + html: ` +
+

text

+
+ `, + + test({ assert, component, target }) { + component.visible = false; + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/each-block-empty-outro/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-empty-outro/main.svelte similarity index 100% rename from test/runtime/samples/each-block-empty-outro/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-empty-outro/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-func-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-func-function/_config.js new file mode 100644 index 000000000000..c6495ac8b9d9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-func-function/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

1

+

2

+

3

+

4

+

5

+ ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-func-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-func-function/main.svelte new file mode 100644 index 000000000000..812e7940d50b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-func-function/main.svelte @@ -0,0 +1,3 @@ +{#each [1, 2, 3, 4, 5] as func} +

{(() => func)()}

+{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-function/_config.js new file mode 100644 index 000000000000..5aaf9d65eb7a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-function/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

1, 2, 3

+

2, 4, 6

+

3, 6, 9

+ `, + + test({ assert, component, target }) { + component.numbers = [4, 5]; + assert.htmlEqual( + target.innerHTML, + ` +

16, 20

+

20, 25

+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-function/main.svelte similarity index 100% rename from test/runtime/samples/each-block-function/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-function/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-in-if-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-in-if-block/_config.js new file mode 100644 index 000000000000..5043074a2ed6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-in-if-block/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + dummy: false, + fruits: ['Apple', 'Banana', 'Tomato'] + }; + }, + + html: '
Apple
Banana
Tomato
', + + test({ assert, component, target }) { + component.dummy = true; + assert.htmlEqual( + target.innerHTML, + '
Apple
Banana
Tomato
' + ); + } +}); diff --git a/test/runtime/samples/each-block-in-if-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-in-if-block/main.svelte similarity index 100% rename from test/runtime/samples/each-block-in-if-block/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-in-if-block/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-index-only/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-index-only/_config.js new file mode 100644 index 000000000000..ad9df3a2f15b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-index-only/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { things: [0, 0, 0, 0, 0] }; + }, + + html: ` +

0

+

1

+

2

+

3

+

4

+ `, + + test({ assert, component, target }) { + component.things = [0, 0, 0]; + + assert.htmlEqual( + target.innerHTML, + ` +

0

+

1

+

2

+ ` + ); + } +}); diff --git a/test/runtime/samples/each-block-index-only/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-index-only/main.svelte similarity index 100% rename from test/runtime/samples/each-block-index-only/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-index-only/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-indexed/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-indexed/_config.js new file mode 100644 index 000000000000..d63c030e4439 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-indexed/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animals: ['adder', 'blue whale', 'chameleon'] + }; + }, + html: '

0: adder

1: blue whale

2: chameleon

' +}); diff --git a/test/runtime/samples/each-block-indexed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-indexed/main.svelte similarity index 100% rename from test/runtime/samples/each-block-indexed/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-indexed/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-bind-group/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-bind-group/_config.js new file mode 100644 index 000000000000..e993f739639a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-bind-group/_config.js @@ -0,0 +1,80 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + + + + `, + + test({ assert, target, window }) { + const [input1, input2, input3, input4, input5] = target.querySelectorAll('input'); + const event = new window.Event('change'); + + input3.checked = true; + input3.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + + + + ` + ); + + assert.equal(input1.checked, false); + assert.equal(input2.checked, false); + assert.equal(input3.checked, true); + assert.equal(input4.checked, false); + assert.equal(input5.checked, false); + + input4.checked = true; + input4.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + + + + ` + ); + + assert.equal(input1.checked, false); + assert.equal(input2.checked, false); + assert.equal(input3.checked, true); + assert.equal(input4.checked, true); + assert.equal(input5.checked, false); + + input3.checked = false; + input3.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + + + + ` + ); + + assert.equal(input1.checked, false); + assert.equal(input2.checked, false); + assert.equal(input3.checked, false); + assert.equal(input4.checked, true); + assert.equal(input5.checked, false); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-bind-group/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-bind-group/main.svelte new file mode 100644 index 000000000000..80c0db4f83ae --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-bind-group/main.svelte @@ -0,0 +1,21 @@ + + +{#each flavours as flavour (flavour)} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-changed/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-changed/_config.js new file mode 100644 index 000000000000..2315cd5cc790 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-changed/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + titles: [{ name: 'a' }, { name: 'b' }, { name: 'c' }] + }; + }, + + html: '

a

b

c

', + + test({ assert, component, target }) { + component.titles = [{ name: 'b' }, { name: 'c' }, { name: 'a' }]; + + assert.htmlEqual(target.innerHTML, '

b

c

a

'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-changed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-changed/main.svelte new file mode 100644 index 000000000000..1e1ef513a7a3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-changed/main.svelte @@ -0,0 +1,8 @@ + +
+ {#each titles as title (title.name)} +

{title.name}

+ {/each} +
diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-component-action/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-component-action/Component.svelte new file mode 100644 index 000000000000..0528ab2d62df --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-component-action/Component.svelte @@ -0,0 +1,5 @@ + + +
diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-component-action/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-component-action/_config.js new file mode 100644 index 000000000000..ad35c6677575 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-component-action/_config.js @@ -0,0 +1,23 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component }) { + assert.equal(component.count, 0); + + component.arr = ['2']; + + assert.equal(component.count, 1); + + component.arr = ['1', '2']; + + assert.equal(component.count, 2); + + component.arr = ['2', '1']; + + assert.equal(component.count, 2); + + component.arr = []; + + assert.equal(component.count, 0); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-component-action/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-component-action/main.svelte new file mode 100644 index 000000000000..bfacdf402a02 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-component-action/main.svelte @@ -0,0 +1,17 @@ + + +{#each arr as item (item)} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-2/_config.js new file mode 100644 index 000000000000..a19d789c78e2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-2/_config.js @@ -0,0 +1,28 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + + 0 +
    + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + button.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + 1 +
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-2/main.svelte new file mode 100644 index 000000000000..ab455a585e84 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-2/main.svelte @@ -0,0 +1,20 @@ + + + +{num} +
        + {#each cards as c, i (i)} +
      • {c}
      • + {/each} +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-key/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-key/_config.js new file mode 100644 index 000000000000..1f9bd42ae3a1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-key/_config.js @@ -0,0 +1,39 @@ +import { test } from '../../test'; + +let count = 0; +let value = 'foo'; + +export default test({ + get props() { + return { + value() { + count++; + return value; + } + }; + }, + + before_test() { + count = 0; + value = 'foo'; + }, + + html: ` +
      foo
      +
      foo
      + `, + + test({ assert, component, target }) { + value = 'bar'; + component.id = 1; + + assert.equal(count, 4); + assert.htmlEqual( + target.innerHTML, + ` +
      bar
      +
      bar
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-key/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-key/main.svelte new file mode 100644 index 000000000000..9a15c7d98e8a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic-key/main.svelte @@ -0,0 +1,8 @@ + + +{#each ['foo', 'bar'] as key (id + key)} +
      {value()}
      +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic/_config.js new file mode 100644 index 000000000000..b54e54d4f077 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic/_config.js @@ -0,0 +1,38 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + todos: [ + { id: 123, description: 'buy milk' }, + { id: 234, description: 'drink milk' } + ] + }; + }, + + html: ` +

      buy milk

      +

      drink milk

      + `, + + test({ assert, component, target }) { + const [p1, p2] = target.querySelectorAll('p'); + + component.todos = [ + { id: 123, description: 'buy beer' }, + { id: 234, description: 'drink beer' } + ]; + assert.htmlEqual( + target.innerHTML, + ` +

      buy beer

      +

      drink beer

      + ` + ); + + const [p3, p4] = target.querySelectorAll('p'); + + assert.equal(p1, p3); + assert.equal(p2, p4); + } +}); diff --git a/test/runtime/samples/each-block-keyed-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-dynamic/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-dynamic/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-else/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-else/_config.js new file mode 100644 index 000000000000..43b139eeebd7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-else/_config.js @@ -0,0 +1,50 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animals: ['alpaca', 'baboon', 'capybara'], + foo: 'something else' + }; + }, + + html: ` + before +

      alpaca

      +

      baboon

      +

      capybara

      + after + `, + + test({ assert, component, target }) { + component.animals = []; + assert.htmlEqual( + target.innerHTML, + ` + before +

      no animals, but rather something else

      + after + ` + ); + + component.foo = 'something other'; + assert.htmlEqual( + target.innerHTML, + ` + before +

      no animals, but rather something other

      + after + ` + ); + + component.animals = ['wombat']; + assert.htmlEqual( + target.innerHTML, + ` + before +

      wombat

      + after + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-else/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-else/main.svelte new file mode 100644 index 000000000000..2a82653ff16a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-else/main.svelte @@ -0,0 +1,12 @@ + + +before +{#each animals as animal (animal)} +

      {animal}

      +{:else} +

      no animals, but rather {foo}

      +{/each} +after diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-empty/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-empty/_config.js new file mode 100644 index 000000000000..513a76c86d8b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-empty/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: [{ z: 1 }, { z: 2 }] }; + }, + + html: '' +}); diff --git a/test/runtime/samples/each-block-keyed-empty/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-empty/main.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-empty/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-empty/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html-b/_config.js new file mode 100644 index 000000000000..7a3cc43fd66b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html-b/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      hello John
      +
      hello Jill
      + `, + + test({ assert, component, target }) { + component.names = component.names.reverse(); + assert.htmlEqual( + target.innerHTML, + ` +
      hello Jill
      +
      hello John
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html-b/main.svelte new file mode 100644 index 000000000000..02955577fc53 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html-b/main.svelte @@ -0,0 +1,11 @@ + + +{#each names as name (name)} +
      + hello + {@html name} +
      +{/each} + diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html/_config.js new file mode 100644 index 000000000000..f4486f59f367 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + html: ` + JohnJill + `, + + test({ assert, component, target }) { + component.names = component.names.reverse(); + assert.htmlEqual(target.innerHTML, 'JillJohn'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html/main.svelte new file mode 100644 index 000000000000..97c5f8c8986f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-html/main.svelte @@ -0,0 +1,8 @@ + + +{#each names as name (name)} + {@html name} +{/each} + diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-iife/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-iife/_config.js new file mode 100644 index 000000000000..beeb94e5ff29 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-iife/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      1
      +
      2
      +
      3
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-iife/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-iife/main.svelte new file mode 100644 index 000000000000..8753357bae68 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-iife/main.svelte @@ -0,0 +1,9 @@ + + +{#each arr as item ((() => item)())} +
      + {item} +
      +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index-in-event-handler/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index-in-event-handler/_config.js new file mode 100644 index 000000000000..997ca61ecfa7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index-in-event-handler/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + + `, + + test({ assert, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + + target.querySelectorAll('button')[1].dispatchEvent(click); + target.querySelectorAll('button')[1].dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index-in-event-handler/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index-in-event-handler/main.svelte new file mode 100644 index 000000000000..7bb14e88f0fb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index-in-event-handler/main.svelte @@ -0,0 +1,16 @@ + + +{#each list as value, index (value)} + {#if value} + + {/if} +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index/_config.js new file mode 100644 index 000000000000..9e4c77c8be3a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `
      0
      1
      ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index/main.svelte new file mode 100644 index 000000000000..0bda97bc691f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-index/main.svelte @@ -0,0 +1,3 @@ +{#each {length: 2} as item, i (`${i}`)} +
      {i}
      +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-nested/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-nested/Child.svelte new file mode 100644 index 000000000000..e7ed72685038 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-nested/Child.svelte @@ -0,0 +1,5 @@ + + +{id} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-nested/_config.js new file mode 100644 index 000000000000..b3e06609d895 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-nested/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + html: ` + 1 + `, + + test({ assert, component, target }) { + component.desks = [ + { + id: 1, + teams: [] + } + ]; + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-nested/main.svelte new file mode 100644 index 000000000000..86f665a5e785 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-nested/main.svelte @@ -0,0 +1,16 @@ + + +{#each desks as desk (desk.id)} + {#each desk.teams as team (team.id)} + + {/each} +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-non-prop/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-non-prop/_config.js new file mode 100644 index 000000000000..98c605c5b051 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-non-prop/_config.js @@ -0,0 +1,34 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { words: ['foo', 'bar', 'baz'] }; + }, + + html: ` +

      foo

      +

      bar

      +

      baz

      + `, + + test({ assert, component, target }) { + const [p1, p2, p3] = target.querySelectorAll('p'); + + component.words = ['foo', 'baz']; + + assert.htmlEqual( + target.innerHTML, + ` +

      foo

      +

      baz

      + ` + ); + + const [p4, p5] = target.querySelectorAll('p'); + + assert.ok(!target.contains(p2), '`

      ` element should be removed'); + + assert.equal(p1, p4, 'first `

      ` element should be retained'); + assert.equal(p3, p5, 'last `

      ` element should be retained'); + } +}); diff --git a/test/runtime/samples/each-block-keyed-non-prop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-non-prop/main.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-non-prop/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-non-prop/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-object-identity/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-object-identity/_config.js new file mode 100644 index 000000000000..154554d079e8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-object-identity/_config.js @@ -0,0 +1,33 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + todos: [ + { + description: 'implement keyed each blocks' + }, + { + description: 'implement client-side hydration' + } + ] + }; + }, + + html: ` +

      1: implement keyed each blocks

      +

      2: implement client-side hydration

      + `, + + test({ assert, component, target }) { + const [p1, p2] = target.querySelectorAll('p'); + + component.todos = [component.todos[1]]; + assert.htmlEqual(target.innerHTML, '

      1: implement client-side hydration

      '); + + const [p3] = target.querySelectorAll('p'); + + assert.ok(!target.contains(p1), 'first `

      ` element should be removed'); + assert.equal(p2, p3, 'second `

      ` element should be retained'); + } +}); diff --git a/test/runtime/samples/each-block-keyed-object-identity/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-object-identity/main.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-object-identity/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-object-identity/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-random-permute/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-random-permute/_config.js new file mode 100644 index 000000000000..5bc47362b717 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-random-permute/_config.js @@ -0,0 +1,67 @@ +import { test } from '../../test'; + +const VALUES = Array.from('abcdefghijklmnopqrstuvwxyz'); + +/** @param {string} array */ +function toObjects(array) { + return array.split('').map((x) => ({ id: x })); +} + +function permute() { + const values = VALUES.slice(); + const number = Math.floor(Math.random() * VALUES.length); + const permuted = []; + for (let i = 0; i < number; i++) { + permuted.push(...values.splice(Math.floor(Math.random() * (number - i)), 1)); + } + + return permuted.join(''); +} + +export default test({ + get props() { + return { values: toObjects('abc') }; + }, + + html: '(a)(b)(c)', + + test({ assert, component, target }) { + /** @param {string} sequence */ + function test(sequence) { + const previous = target.textContent; + const expected = sequence + .split('') + .map((x) => `(${x})`) + .join(''); + component.values = toObjects(sequence); + assert.htmlEqual( + target.innerHTML, + expected, + `\n${previous} -> ${expected}\n${target.textContent}` + ); + } + + // first, some fixed tests so that we can debug them + test('abc'); + test('abcd'); + test('abecd'); + test('fabecd'); + test('fabed'); + test('beadf'); + test('ghbeadf'); + test('gf'); + test('gc'); + test('g'); + test(''); + test('abc'); + test('duqbmineapjhtlofrskcg'); + test('hdnkjougmrvftewsqpailcb'); + test('bidhfacge'); + test('kgjnempcboaflidh'); + test('fekbijachgd'); + test('kdmlgfbicheja'); + + // then, we party + for (let i = 0; i < 100; i += 1) test(permute()); + } +}); diff --git a/test/runtime/samples/each-block-keyed-random-permute/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-random-permute/main.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-random-permute/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-random-permute/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-recursive/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-recursive/_config.js new file mode 100644 index 000000000000..acdf96f4319c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-recursive/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + tree: [ + { id: 1, sub: null }, + { id: 2, sub: [{ id: 11 }] } + ] + }; + }, + + html: ` +

      1
      +
      2\n
      11
      + `, + + test({ assert, component, target }) { + component.tree = [ + { id: 1, sub: null }, + { id: 2, sub: null } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
      1
      +
      2
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-recursive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-recursive/main.svelte new file mode 100644 index 000000000000..5e90ec501caf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-recursive/main.svelte @@ -0,0 +1,12 @@ + + +{#each tree as item, i (item.id)} +
      + {item.id} + {#if item.sub} + + {/if} +
      +{/each} diff --git a/test/runtime/samples/each-block-keyed-shift/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-shift/Nested.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-shift/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-shift/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-shift/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-shift/_config.js new file mode 100644 index 000000000000..114283b20fd7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-shift/_config.js @@ -0,0 +1,36 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + titles: [{ name: 'a' }, { name: 'b' }, { name: 'c' }] + }; + }, + + html: ` +

      a

      +

      b

      +

      c

      + `, + + test({ assert, component, target }) { + component.titles = [{ name: 'b' }, { name: 'c' }]; + + assert.htmlEqual( + target.innerHTML, + ` +

      b

      +

      c

      + ` + ); + + component.titles = [{ name: 'c' }]; + + assert.htmlEqual( + target.innerHTML, + ` +

      c

      + ` + ); + } +}); diff --git a/test/runtime/samples/each-block-keyed-shift/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-shift/main.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-shift/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-shift/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-siblings/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-siblings/_config.js new file mode 100644 index 000000000000..b9df5292de13 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-siblings/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + ones: [{ text: '1' }], + twos: [{ text: '2' }] + }; + }, + + html: ` +
      1
      +
      2
      + `, + + test({ assert, component, target }) { + component.ones = [{ text: '11' }]; + + assert.htmlEqual( + target.innerHTML, + ` +
      11
      +
      2
      + ` + ); + } +}); diff --git a/test/runtime/samples/each-block-keyed-siblings/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-siblings/main.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-siblings/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-siblings/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-static/_config.js new file mode 100644 index 000000000000..cac14eb3e3b2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-static/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: [{ z: 1 }, { z: 2 }] }; + }, + + html: ` +

      does not change

      +

      does not change

      + ` +}); diff --git a/test/runtime/samples/each-block-keyed-static/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-static/main.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-static/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-static/main.svelte diff --git a/test/runtime/samples/each-block-keyed-unshift/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-unshift/Nested.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-unshift/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-unshift/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-unshift/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-unshift/_config.js new file mode 100644 index 000000000000..b853991652ab --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-unshift/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { titles: [{ name: 'b' }, { name: 'c' }] }; + }, + + html: ` +

      b

      +

      c

      + `, + + test({ assert, component, target }) { + component.titles = [{ name: 'a' }, { name: 'b' }, { name: 'c' }]; + + assert.htmlEqual( + target.innerHTML, + ` +

      a

      +

      b

      +

      c

      + ` + ); + } +}); diff --git a/test/runtime/samples/each-block-keyed-unshift/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed-unshift/main.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed-unshift/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed-unshift/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-keyed/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed/_config.js new file mode 100644 index 000000000000..2ffab3334e0c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed/_config.js @@ -0,0 +1,35 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + todos: [ + { + id: 123, + description: 'implement keyed each blocks' + }, + { + id: 234, + description: 'implement client-side hydration' + } + ] + }; + }, + + html: ` +

      1: implement keyed each blocks

      +

      2: implement client-side hydration

      + `, + + test({ assert, component, target }) { + const [p1, p2] = target.querySelectorAll('p'); + + component.todos = [{ id: 234, description: 'implement client-side hydration' }]; + assert.htmlEqual(target.innerHTML, '

      1: implement client-side hydration

      '); + + const [p3] = target.querySelectorAll('p'); + + assert.ok(!target.contains(p1), 'first `

      ` element should be removed'); + assert.equal(p2, p3, 'second `

      ` element should be retained'); + } +}); diff --git a/test/runtime/samples/each-block-keyed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-keyed/main.svelte similarity index 100% rename from test/runtime/samples/each-block-keyed/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-keyed/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-random-permute/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-random-permute/_config.js new file mode 100644 index 000000000000..58f83b938e9b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-random-permute/_config.js @@ -0,0 +1,37 @@ +import { test } from '../../test'; + +const VALUES = Array.from('abcdefghijklmnopqrstuvwxyz'); + +function permute() { + const values = VALUES.slice(); + const number = Math.floor(Math.random() * VALUES.length); + const permuted = []; + for (let i = 0; i < number; i++) { + permuted.push(...values.splice(Math.floor(Math.random() * (number - i)), 1)); + } + + return { + data: permuted, + expected: permuted.length ? `(${permuted.join(')(')})` : '' + }; +} + +let step = permute(); + +export default test({ + get props() { + return { values: step.data }; + }, + + get html() { + return step.expected; + }, + + test({ assert, component, target }) { + for (let i = 0; i < 100; i++) { + step = permute(); + component.values = step.data; + assert.htmlEqual(target.innerHTML, step.expected); + } + } +}); diff --git a/test/runtime/samples/each-block-random-permute/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-random-permute/main.svelte similarity index 100% rename from test/runtime/samples/each-block-random-permute/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-random-permute/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-recursive-with-function-condition/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-recursive-with-function-condition/_config.js new file mode 100644 index 000000000000..e619a68646d8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-recursive-with-function-condition/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      OK

      +

      OK

      +
      one
      +
      two
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-recursive-with-function-condition/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-recursive-with-function-condition/main.svelte new file mode 100644 index 000000000000..9b62c03cf618 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-recursive-with-function-condition/main.svelte @@ -0,0 +1,13 @@ + + +{#each data as datum} + {#if datum.foo && a()} +

      OK

      + + {:else} +
      {datum.bar}
      + {/if} +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-ref-import/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-ref-import/_config.js new file mode 100644 index 000000000000..052cdd27c4b2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-ref-import/_config.js @@ -0,0 +1,6 @@ +import { test } from '../../test'; + +export default test({ + html: ``, + ssrHtml: `` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-ref-import/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-ref-import/main.svelte new file mode 100644 index 000000000000..26f629eb06f0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-ref-import/main.svelte @@ -0,0 +1,7 @@ + + +{#each foo.bar as bar} + +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-ref-import/utils.js b/packages/svelte/tests/runtime-legacy/samples/each-block-ref-import/utils.js new file mode 100644 index 000000000000..e4b44346570b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-ref-import/utils.js @@ -0,0 +1,9 @@ +export const foo = { + get bar() { + return [ + { + value: '' + } + ]; + } +}; diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-2/_config.js new file mode 100644 index 000000000000..d362c4b6d1be --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-2/_config.js @@ -0,0 +1,29 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + Hello + + `, + ssrHtml: ` + Hello + + `, + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + input.value = 'abcd'; + input.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + abcd + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-2/main.svelte new file mode 100644 index 000000000000..f5bff01e6cc2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-2/main.svelte @@ -0,0 +1,10 @@ + + +{#each a as { a }} + {a} + +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-3/_config.js new file mode 100644 index 000000000000..6c096f7581af --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-3/_config.js @@ -0,0 +1,112 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
      + Hello World + + +
      +
      + Sapper App + + +
      + `, + + ssrHtml: ` +
      + Hello World + + +
      +
      + Sapper App + + +
      + `, + test({ assert, target, window }) { + const [input1, input2, input3, input4] = target.querySelectorAll('input'); + input1.value = 'Awesome'; + input1.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      + Awesome World + + +
      +
      + Sapper App + + +
      + ` + ); + + input2.value = 'Svelte'; + input2.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      + Awesome Svelte + + +
      +
      + Sapper App + + +
      + ` + ); + + input3.value = 'Foo'; + input3.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      + Awesome Svelte + + +
      +
      + Foo App + + +
      + ` + ); + + input4.value = 'Bar'; + input4.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      + Awesome Svelte + + +
      +
      + Foo Bar + + +
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-3/main.svelte new file mode 100644 index 000000000000..2e8fe5e59193 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-3/main.svelte @@ -0,0 +1,14 @@ + + +{#each a as a} +
      + {a[0]} {a[1]} + + +
      +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-4/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-4/_config.js new file mode 100644 index 000000000000..54c71f80acc4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-4/_config.js @@ -0,0 +1,72 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      + b: Hello + +
      + + `, + ssrHtml: ` +
      + b: Hello + +
      + + `, + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + const button = target.querySelector('button'); + ok(button); + + input.value = 'Awesome'; + input.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      + b: Awesome + +
      + + ` + ); + + button.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      + c: World + +
      + + ` + ); + + assert.equal(input.value, 'World'); + + input.value = 'Svelte'; + input.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      + c: Svelte + +
      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-4/main.svelte new file mode 100644 index 000000000000..bc4f172dd020 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind-4/main.svelte @@ -0,0 +1,14 @@ + + +{#each a as { a, key }} +
      + {key}: {a[key]} + +
      +{/each} + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind/_config.js new file mode 100644 index 000000000000..d362c4b6d1be --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind/_config.js @@ -0,0 +1,29 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + Hello + + `, + ssrHtml: ` + Hello + + `, + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + input.value = 'abcd'; + input.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + abcd + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind/main.svelte new file mode 100644 index 000000000000..f3471e179f3b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-bind/main.svelte @@ -0,0 +1,10 @@ + + +{#each a as a} + {a} + +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-self/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-self/_config.js new file mode 100644 index 000000000000..dff51907088f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-self/_config.js @@ -0,0 +1,16 @@ +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + assert.equal(target.querySelectorAll('input').length, 3); + + const input = target.querySelector('input'); + ok(input); + input.value = 'svelte'; + await input.dispatchEvent(new window.Event('input')); + + assert.equal(target.querySelectorAll('input').length, 3); + assert.deepEqual(component.data, { a: 'svelte', b: 'B', c: 'C' }); + assert.deepEqual(component.x, ['a', 'b', 'c']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-self/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-self/main.svelte new file mode 100644 index 000000000000..e3643c524afa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow-self/main.svelte @@ -0,0 +1,15 @@ + + +{#each x as x} + +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow/_config.js new file mode 100644 index 000000000000..cc15ff47c40e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '(alpaca)(baboon)(capybara) (lemur)' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow/main.svelte new file mode 100644 index 000000000000..58294d35b43b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-scope-shadow/main.svelte @@ -0,0 +1,10 @@ +{#each animals as animal} + ({animal}) +{/each} + +({animal}) + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-static/_config.js new file mode 100644 index 000000000000..f9385ed49b64 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-static/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {string[]} */ + items: [] + }; + }, + + html: '', + + test({ assert, component, target }) { + component.items = ['x']; + assert.htmlEqual(target.innerHTML, 'foo'); + } +}); diff --git a/test/runtime/samples/each-block-static/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-static/main.svelte similarity index 100% rename from test/runtime/samples/each-block-static/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-static/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-string/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-string/_config.js new file mode 100644 index 000000000000..b335ea07b413 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-string/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + html: ` +
      f
      +
      o
      +
      o
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-string/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-string/main.svelte new file mode 100644 index 000000000000..ae60f0f6b32f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-string/main.svelte @@ -0,0 +1,3 @@ +{#each 'foo' as c} +
      {c}
      +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-text-node/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-text-node/_config.js new file mode 100644 index 000000000000..f849e1bda931 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-text-node/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animals: ['alpaca', 'baboon', 'capybara'] + }; + }, + + html: '(alpaca)(baboon)(capybara)', + + test({ assert, component, target }) { + component.animals = ['caribou', 'dogfish']; + assert.htmlEqual(target.innerHTML, '(caribou)(dogfish)'); + component.animals = []; + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/each-block-text-node/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-text-node/main.svelte similarity index 100% rename from test/runtime/samples/each-block-text-node/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block-text-node/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-unkeyed-else-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-unkeyed-else-2/_config.js new file mode 100644 index 000000000000..43b139eeebd7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-unkeyed-else-2/_config.js @@ -0,0 +1,50 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animals: ['alpaca', 'baboon', 'capybara'], + foo: 'something else' + }; + }, + + html: ` + before +

      alpaca

      +

      baboon

      +

      capybara

      + after + `, + + test({ assert, component, target }) { + component.animals = []; + assert.htmlEqual( + target.innerHTML, + ` + before +

      no animals, but rather something else

      + after + ` + ); + + component.foo = 'something other'; + assert.htmlEqual( + target.innerHTML, + ` + before +

      no animals, but rather something other

      + after + ` + ); + + component.animals = ['wombat']; + assert.htmlEqual( + target.innerHTML, + ` + before +

      wombat

      + after + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-unkeyed-else-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-unkeyed-else-2/main.svelte new file mode 100644 index 000000000000..3275cb1f83de --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-unkeyed-else-2/main.svelte @@ -0,0 +1,12 @@ + + +before +{#each animals as animal} +

      {animal}

      +{:else} +

      no animals, but rather {foo}

      +{/each} +after diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-with-iterable/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block-with-iterable/_config.js new file mode 100644 index 000000000000..98f000cdb551 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-with-iterable/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      1

      +

      2

      + +

      1 0

      +

      2 1

      + +

      1 0

      +

      2 1

      + `, + + test({ assert, component, target }) { + component.numbers = new Set([2, 3]); + assert.htmlEqual( + target.innerHTML, + ` +

      2

      +

      3

      + +

      2 0

      +

      3 1

      + +

      2 0

      +

      3 1

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block-with-iterable/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block-with-iterable/main.svelte new file mode 100644 index 000000000000..b69e5ec3fa70 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block-with-iterable/main.svelte @@ -0,0 +1,15 @@ + + +{#each numbers as i} +

      {i}

      +{/each} + +{#each numbers as i, index} +

      {i} {index}

      +{/each} + +{#each numbers as i, index (i)} +

      {i} {index}

      +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/each-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-block/_config.js new file mode 100644 index 000000000000..76f42f16aaf5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-block/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + animals: ['alpaca', 'baboon', 'capybara'] + }; + }, + + html: ` +

      alpaca

      +

      baboon

      +

      capybara

      + `, + + test({ assert, component, target }) { + component.animals = ['alpaca', 'baboon', 'caribou', 'dogfish']; + assert.htmlEqual( + target.innerHTML, + ` +

      alpaca

      +

      baboon

      +

      caribou

      +

      dogfish

      + ` + ); + + component.animals = []; + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/each-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-block/main.svelte similarity index 100% rename from test/runtime/samples/each-block/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-block/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment-2/_config.js new file mode 100644 index 000000000000..ed7ecbf9276a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment-2/_config.js @@ -0,0 +1,24 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + foo + + `, + test({ assert, target, window }) { + const button = target.querySelector('button'); + + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + button?.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + bar + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment-2/main.svelte new file mode 100644 index 000000000000..5f40af5c0b14 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment-2/main.svelte @@ -0,0 +1,12 @@ + + +{#each arr as o} + {o.prop} + +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment/_config.js new file mode 100644 index 000000000000..c4aa3fb891c2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment/_config.js @@ -0,0 +1,106 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + 1 + + 2 + + 3 + + `, + test({ assert, target, window }) { + let [incrementBtn, ...buttons] = target.querySelectorAll('button'); + + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + buttons[0].dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + 2 + + 2 + + 3 + + ` + ); + + buttons[0].dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + 4 + + 2 + + 3 + + ` + ); + + buttons[2].dispatchEvent(clickEvent); + flushSync(); + buttons[2].dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + 4 + + 2 + + 12 + + ` + ); + + incrementBtn.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + 4 + + 2 + + 12 + + 4 + + ` + ); + + [incrementBtn, ...buttons] = target.querySelectorAll('button'); + + buttons[3].dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + 4 + + 2 + + 12 + + 8 + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment/main.svelte new file mode 100644 index 000000000000..f74bffbe04f7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-blocks-assignment/main.svelte @@ -0,0 +1,13 @@ + + + +{#each arr as o} + {o} + +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/each-blocks-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-blocks-expression/_config.js new file mode 100644 index 000000000000..eddc806e0d3e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-blocks-expression/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      a

      b

      c

      ' +}); diff --git a/test/runtime/samples/each-blocks-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-blocks-expression/main.svelte similarity index 100% rename from test/runtime/samples/each-blocks-expression/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-blocks-expression/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-blocks-nested-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-blocks-nested-b/_config.js new file mode 100644 index 000000000000..f006437cd31b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-blocks-nested-b/_config.js @@ -0,0 +1,26 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + categories: [ + { + name: 'animals', + things: [{ name: 'aardvark' }, { name: 'buffalo' }, { name: 'chinchilla' }] + }, + { + name: 'countries', + things: [{ name: 'albania' }, { name: 'brazil' }, { name: 'china' }] + }, + { + name: 'people', + things: [{ name: 'alice' }, { name: 'bob' }, { name: 'carol' }, { name: 'dave' }] + } + ] + }; + }, + html: '

      animals: aardvark

      animals: buffalo

      animals: chinchilla

      countries: albania

      countries: brazil

      countries: china

      people: alice

      people: bob

      people: carol

      people: dave

      ', + test() { + // TODO + } +}); diff --git a/test/runtime/samples/each-blocks-nested-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-blocks-nested-b/main.svelte similarity index 100% rename from test/runtime/samples/each-blocks-nested-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-blocks-nested-b/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-blocks-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-blocks-nested/_config.js new file mode 100644 index 000000000000..825d2d8e3ffc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-blocks-nested/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + columns: ['a', 'b', 'c'], + rows: [1, 2, 3] + }; + }, + + html: '
      a, 1
      a, 2
      a, 3
      b, 1
      b, 2
      b, 3
      c, 1
      c, 2
      c, 3
      ', + + // TODO + test() {} +}); diff --git a/test/runtime/samples/each-blocks-nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-blocks-nested/main.svelte similarity index 100% rename from test/runtime/samples/each-blocks-nested/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/each-blocks-nested/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/each-blocks-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/each-blocks-update/_config.js new file mode 100644 index 000000000000..a00605a634a5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-blocks-update/_config.js @@ -0,0 +1,27 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + +

      1, 2, 3

      + `, + + test({ assert, target }) { + let buttons = target.querySelectorAll('button'); + + flushSync(() => buttons[2].click()); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

      1, 2, 4

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/each-blocks-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/each-blocks-update/main.svelte new file mode 100644 index 000000000000..0abded02ff93 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/each-blocks-update/main.svelte @@ -0,0 +1,9 @@ + + +{#each arr as n} + +{/each} + +

      {arr.join(', ')}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/element-invalid-name/_config.js b/packages/svelte/tests/runtime-legacy/samples/element-invalid-name/_config.js new file mode 100644 index 000000000000..0969422b91f8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/element-invalid-name/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` + Hello + ` +}); diff --git a/test/runtime/samples/element-invalid-name/main.svelte b/packages/svelte/tests/runtime-legacy/samples/element-invalid-name/main.svelte similarity index 100% rename from test/runtime/samples/element-invalid-name/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/element-invalid-name/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/Empty.svelte b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/Empty.svelte new file mode 100644 index 000000000000..1708640d08ed --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/Empty.svelte @@ -0,0 +1,8 @@ + + diff --git a/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/_config.js b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/_config.js new file mode 100644 index 000000000000..f49b9fdde566 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + `, + + test({ assert, target, window, logs }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + // @ts-ignore + button.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + assert.deepEqual(logs, ['destroy']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/main.svelte b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/main.svelte new file mode 100644 index 000000000000..7f7d50582f19 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/empty-component-destroy/main.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/empty-dom/_config.js b/packages/svelte/tests/runtime-legacy/samples/empty-dom/_config.js new file mode 100644 index 000000000000..653ccc21927f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/empty-dom/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/empty-dom/main.svelte b/packages/svelte/tests/runtime-legacy/samples/empty-dom/main.svelte new file mode 100644 index 000000000000..3098443ea3d4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/empty-dom/main.svelte @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/empty-style-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/empty-style-block/_config.js new file mode 100644 index 000000000000..653ccc21927f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/empty-style-block/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '' +}); diff --git a/test/runtime/samples/empty-style-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/empty-style-block/main.svelte similarity index 100% rename from test/runtime/samples/empty-style-block/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/empty-style-block/main.svelte diff --git a/test/runtime/samples/escape-template-literals/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/escape-template-literals/Widget.svelte similarity index 100% rename from test/runtime/samples/escape-template-literals/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/escape-template-literals/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/escape-template-literals/_config.js b/packages/svelte/tests/runtime-legacy/samples/escape-template-literals/_config.js new file mode 100644 index 000000000000..7f758b4f5127 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escape-template-literals/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: + '`${foo}\\n`\n`\n
      foo
      \n
      `${foo}\\n`
      ' + + '
      / $clicks: 0 `tim$es` \\
      $dollars `backticks` pyramid /\\
      ' + + '

      ${ ${ ${

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/escape-template-literals/main.svelte b/packages/svelte/tests/runtime-legacy/samples/escape-template-literals/main.svelte new file mode 100644 index 000000000000..8f3eeda9cf4c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escape-template-literals/main.svelte @@ -0,0 +1,19 @@ + + +`${foo}\n` +{@html "`"} +
      foo
      + +
      + / $clicks: {0} `tim${"e"}s` \ +
      +
      + $dollars `backticks` pyramid /\ +
      +

      + ${'{'} + ${'{'} + {'$'}{'{'} +

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/escaped-attr-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/escaped-attr-2/_config.js new file mode 100644 index 000000000000..4841323e4e40 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escaped-attr-2/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, logs }) { + assert.deepEqual(logs, []); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/escaped-attr-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/escaped-attr-2/main.svelte new file mode 100644 index 000000000000..ec1ecfcac58d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escaped-attr-2/main.svelte @@ -0,0 +1,8 @@ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/escaped-attr-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/escaped-attr-3/_config.js new file mode 100644 index 000000000000..ab03ae56d2f7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escaped-attr-3/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + assert.htmlEqual(target.innerHTML, '
      blah
      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/escaped-attr-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/escaped-attr-3/main.svelte new file mode 100644 index 000000000000..ff33fbf59a73 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escaped-attr-3/main.svelte @@ -0,0 +1 @@ +
      blah
      diff --git a/packages/svelte/tests/runtime-legacy/samples/escaped-attr/_config.js b/packages/svelte/tests/runtime-legacy/samples/escaped-attr/_config.js new file mode 100644 index 000000000000..4841323e4e40 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escaped-attr/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, logs }) { + assert.deepEqual(logs, []); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/escaped-attr/main.svelte b/packages/svelte/tests/runtime-legacy/samples/escaped-attr/main.svelte new file mode 100644 index 000000000000..d4852b90c7df --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escaped-attr/main.svelte @@ -0,0 +1,4 @@ + + diff --git a/packages/svelte/tests/runtime-legacy/samples/escaped-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/escaped-expression/_config.js new file mode 100644 index 000000000000..e6d5ef34078e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escaped-expression/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `

      <marquee>hello</marquee>

      ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/escaped-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/escaped-expression/main.svelte new file mode 100644 index 000000000000..8ba27841be21 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escaped-expression/main.svelte @@ -0,0 +1 @@ +

      {'hello'}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/escaped-text/_config.js b/packages/svelte/tests/runtime-legacy/samples/escaped-text/_config.js new file mode 100644 index 000000000000..16d12ba59f1a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/escaped-text/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + html: ` + @x + @@x + #foo + ##foo + %1 + %%2 + +
      + @x + @@x + #foo + ##foo + %1 + %%2 +
      + +
      + @x + @@x + #foo + ##foo + %1 + %%2 + inner +
      + ` +}); diff --git a/test/runtime/samples/escaped-text/main.svelte b/packages/svelte/tests/runtime-legacy/samples/escaped-text/main.svelte similarity index 100% rename from test/runtime/samples/escaped-text/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/escaped-text/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-async/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-async/_config.js new file mode 100644 index 000000000000..6ec8c072bd72 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-async/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-async/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-async/main.svelte new file mode 100644 index 000000000000..b22a6af92ed7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-async/main.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-console-log/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-console-log/_config.js new file mode 100644 index 000000000000..4ef272e072db --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-console-log/_config.js @@ -0,0 +1,28 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { foo: 42 }; + }, + + html: ` + + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + /** @type {number[]} */ + const messages = []; + + const log = console.log; + console.log = (msg) => messages.push(msg); + button.dispatchEvent(event); + console.log = log; + + assert.deepEqual(messages, [42]); + } +}); diff --git a/test/runtime/samples/event-handler-console-log/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-console-log/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-console-log/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-console-log/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-deconflicted/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-deconflicted/_config.js new file mode 100644 index 000000000000..1466f16c1bed --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-deconflicted/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { click_handler: 'x' }; + }, + + html: ` + + ` +}); diff --git a/test/runtime/samples/event-handler-deconflicted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-deconflicted/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-deconflicted/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-deconflicted/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-destructured/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-destructured/_config.js new file mode 100644 index 000000000000..35e9c6752c97 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-destructured/_config.js @@ -0,0 +1,24 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + button.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/event-handler-destructured/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-destructured/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-destructured/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-destructured/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-2/_config.js new file mode 100644 index 000000000000..681fa25d7be4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-2/_config.js @@ -0,0 +1,45 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

      0

      + + + `, + + test({ assert, target, window }) { + const [toggle, handler_a, handler_b] = target.querySelectorAll('button'); + const p = target.querySelector('p'); + ok(p); + + const event = new window.MouseEvent('click', { bubbles: true }); + + handler_a.dispatchEvent(event); + flushSync(); + assert.equal(p.innerHTML, '1'); + + toggle.dispatchEvent(event); + flushSync(); + + handler_a.dispatchEvent(event); + flushSync(); + assert.equal(p.innerHTML, '2'); + + toggle.dispatchEvent(event); + flushSync(); + + handler_b.dispatchEvent(event); + flushSync(); + assert.equal(p.innerHTML, '1'); + + toggle.dispatchEvent(event); + flushSync(); + + handler_b.dispatchEvent(event); + flushSync(); + + assert.equal(p.innerHTML, '2'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-2/main.svelte new file mode 100644 index 000000000000..1b2041d3b80f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-2/main.svelte @@ -0,0 +1,20 @@ + + + + +

      {number}

      + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-bound-var/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-bound-var/Nested.svelte new file mode 100644 index 000000000000..948fc308c0a3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-bound-var/Nested.svelte @@ -0,0 +1,7 @@ + +{text} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-bound-var/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-bound-var/_config.js new file mode 100644 index 000000000000..afb0fbcc54ac --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-bound-var/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + + Hello World + `, + test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + button.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + + Bye World + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-bound-var/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-bound-var/main.svelte new file mode 100644 index 000000000000..bb7d9befc409 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-bound-var/main.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-expression/_config.js new file mode 100644 index 000000000000..04d9469ede9b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-expression/_config.js @@ -0,0 +1,24 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: '', + + async test({ assert, target, window }) { + const [button] = target.querySelectorAll('button'); + + const event = new window.MouseEvent('click', { bubbles: true }); + + button.dispatchEvent(event); + flushSync(); + assert.htmlEqual(target.innerHTML, ''); + + button.dispatchEvent(event); + flushSync(); + assert.htmlEqual(target.innerHTML, ''); + + button.dispatchEvent(event); + flushSync(); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-expression/main.svelte new file mode 100644 index 000000000000..f53aa7aaddb0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-expression/main.svelte @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-hash/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-hash/_config.js new file mode 100644 index 000000000000..33710f18ed59 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-hash/_config.js @@ -0,0 +1,70 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

      + + +

      +

      0

      + + `, + + test({ assert, target, window }) { + const [updateButton1, updateButton2, button] = target.querySelectorAll('button'); + + const event = new window.MouseEvent('click', { bubbles: true }); + let err = ''; + window.addEventListener('error', (e) => { + e.preventDefault(); + err = e.message; + }); + + button.dispatchEvent(event); + flushSync(); + assert.equal(err, '', err); + assert.htmlEqual( + target.innerHTML, + ` +

      + + +

      +

      0

      + + ` + ); + + updateButton1.dispatchEvent(event); + flushSync(); + button.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +

      + + +

      +

      1

      + + ` + ); + + updateButton2.dispatchEvent(event); + button.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +

      + + +

      +

      2

      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-hash/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-hash/main.svelte new file mode 100644 index 000000000000..c81af02006c7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-hash/main.svelte @@ -0,0 +1,23 @@ + + +

      + + +

      + +

      { number }

      + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-invalid/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-invalid/_config.js new file mode 100644 index 000000000000..6f453bbfc881 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-invalid/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, target, window }) { + const [buttonUndef, buttonNull, buttonInvalid] = target.querySelectorAll('button'); + + const event = new window.MouseEvent('click', { bubbles: true }); + let err = ''; + window.addEventListener('error', (e) => { + e.preventDefault(); + err = e.message; + }); + + // All three should not throw if proper checking is done in runtime code + await buttonUndef.dispatchEvent(event); + assert.equal(err, '', err); + + await buttonNull.dispatchEvent(event); + assert.equal(err, '', err); + + // TODO: Should this throw? + // await buttonInvalid.dispatchEvent(event); + // assert.equal(err, '', err); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-invalid/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-invalid/main.svelte new file mode 100644 index 000000000000..f4e8c5fdb7f0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-invalid/main.svelte @@ -0,0 +1,13 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-once/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-once/_config.js new file mode 100644 index 000000000000..412839c86dfc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-once/_config.js @@ -0,0 +1,20 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(event); + assert.equal(component.count, 1); + + await button.dispatchEvent(event); + assert.equal(component.count, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-once/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-once/main.svelte new file mode 100644 index 000000000000..d363d708ba8f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-once/main.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-prevent-default/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-prevent-default/_config.js new file mode 100644 index 000000000000..8ec6e314de2a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-prevent-default/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { + bubbles: true, + cancelable: true + }); + + await button.dispatchEvent(event); + + assert.ok(component.default_was_prevented); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-prevent-default/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-prevent-default/main.svelte new file mode 100644 index 000000000000..49d42f330523 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-prevent-default/main.svelte @@ -0,0 +1,11 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-self/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-self/_config.js new file mode 100644 index 000000000000..6797174b7454 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-self/_config.js @@ -0,0 +1,20 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      + +
      + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(event); + + assert.ok(!component.inner_clicked); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-self/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-self/main.svelte new file mode 100644 index 000000000000..b57d88ec020f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-self/main.svelte @@ -0,0 +1,13 @@ + + +
      + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-stop-propagation/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-stop-propagation/_config.js new file mode 100644 index 000000000000..59c99d4ba55d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-stop-propagation/_config.js @@ -0,0 +1,23 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      + +
      + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { + bubbles: true + }); + + await button.dispatchEvent(event); + + assert.ok(component.inner_clicked); + assert.ok(!component.outer_clicked); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-stop-propagation/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-stop-propagation/main.svelte new file mode 100644 index 000000000000..bad73599276d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-modifier-stop-propagation/main.svelte @@ -0,0 +1,20 @@ + + +
      + +
      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-multiple/_config.js new file mode 100644 index 000000000000..f2da7c8843e3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-multiple/_config.js @@ -0,0 +1,18 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(event); + assert.equal(component.clickHandlerOne, 1); + assert.equal(component.clickHandlerTwo, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-multiple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-multiple/main.svelte new file mode 100644 index 000000000000..2dbbe61ea652 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic-multiple/main.svelte @@ -0,0 +1,11 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic/_config.js new file mode 100644 index 000000000000..979ed7a60e56 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic/_config.js @@ -0,0 +1,69 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

      + + +

      +

      0

      + + `, + + test({ assert, target, window }) { + const [updateButton1, updateButton2, button] = target.querySelectorAll('button'); + + const event = new window.MouseEvent('click', { bubbles: true }); + let err = ''; + window.addEventListener('error', (e) => { + e.preventDefault(); + err = e.message; + }); + + button.dispatchEvent(event); + flushSync(); + assert.equal(err, '', err); + assert.htmlEqual( + target.innerHTML, + ` +

      + + +

      +

      0

      + + ` + ); + + updateButton1.dispatchEvent(event); + button.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +

      + + +

      +

      1

      + + ` + ); + + updateButton2.dispatchEvent(event); + button.dispatchEvent(event); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` +

      + + +

      +

      2

      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic/main.svelte new file mode 100644 index 000000000000..17c9ae6cf07c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-dynamic/main.svelte @@ -0,0 +1,23 @@ + + +

      + + +

      + +

      { number }

      + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-each-context-invalidation/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-context-invalidation/_config.js new file mode 100644 index 000000000000..885422b469b3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-context-invalidation/_config.js @@ -0,0 +1,44 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + +

      on: 1

      + `, + + test({ assert, component, target, window }) { + const buttons = target.querySelectorAll('button'); + const event = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

      on: 2

      + ` + ); + + buttons[2].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

      on: 3

      + ` + ); + + assert.deepEqual(component.switches, [{ on: true }, { on: true }, { on: true }]); + } +}); diff --git a/test/runtime/samples/event-handler-each-context-invalidation/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-context-invalidation/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-each-context-invalidation/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-each-context-invalidation/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-each-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-context/_config.js new file mode 100644 index 000000000000..9aa9897a3bcf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-context/_config.js @@ -0,0 +1,25 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { + items: ['whatever'], + foo: 'wrong', + bar: 'right' + }; + }, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + button.dispatchEvent(event); + assert.equal(component.foo, 'right'); + + component.bar = 'left'; + button.dispatchEvent(event); + assert.equal(component.foo, 'left'); + } +}); diff --git a/test/runtime/samples/event-handler-each-context/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-context/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-each-context/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-each-context/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-each-deconflicted/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-deconflicted/_config.js new file mode 100644 index 000000000000..98433eda0497 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-deconflicted/_config.js @@ -0,0 +1,45 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: [1], bar: [2], clicked: 'neither' }; + }, + + html: ` + + +

      clicked: neither

      + `, + + test({ assert, component, target, window }) { + const buttons = target.querySelectorAll('button'); + const event = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(event); + flushSync(); + + assert.equal(component.clicked, 'foo'); + assert.htmlEqual( + target.innerHTML, + ` + + +

      clicked: foo

      + ` + ); + + buttons[1].dispatchEvent(event); + flushSync(); + + assert.equal(component.clicked, 'bar'); + assert.htmlEqual( + target.innerHTML, + ` + + +

      clicked: bar

      + ` + ); + } +}); diff --git a/test/runtime/samples/event-handler-each-deconflicted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-deconflicted/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-each-deconflicted/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-each-deconflicted/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-each-modifier/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-modifier/_config.js new file mode 100644 index 000000000000..b8d675a38e7a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-modifier/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, component, target, window }) { + // set first + await component.lists.update(() => [{ text: 'item1' }, { text: 'item2' }, { text: 'item3' }]); + + await component.lists.update(() => [{ text: 'item3' }, { text: 'item2' }, { text: 'item1' }]); + + await component.lists.update(() => [{ text: 'item1' }, { text: 'item2' }, { text: 'item3' }]); + + const [item1, item2] = /** @type {NodeListOf} */ (target.querySelectorAll('div')); + const [item1Btn1, item1Btn2] = item1.querySelectorAll('button'); + const [item2Btn1, item2Btn2] = item2.querySelectorAll('button'); + + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + + await item1Btn1.dispatchEvent(clickEvent); + assert.equal(component.getNormalCount(), 1); + + await item1Btn2.dispatchEvent(clickEvent); + assert.equal(component.getModifierCount(), 1); + + await item2Btn1.dispatchEvent(clickEvent); + assert.equal(component.getNormalCount(), 2); + + await item2Btn2.dispatchEvent(clickEvent); + assert.equal(component.getModifierCount(), 2); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-each-modifier/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-modifier/main.svelte new file mode 100644 index 000000000000..700b76f0c1ae --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-modifier/main.svelte @@ -0,0 +1,34 @@ + + +{#each $lists as item (item.text)} +
      + {item.text} + + +
      +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/_config.js new file mode 100644 index 000000000000..fdd881ddd9e7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/_config.js @@ -0,0 +1,33 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { items: ['foo', 'bar', 'baz'] }; + }, + + html: ` + + + + `, + + test({ assert, component, target, window }) { + const buttons = target.querySelectorAll('button'); + const event = new window.MouseEvent('click'); + + /** + * @type {any[]} + */ + const clicked = []; + + component.$on('clicked', (/** @type {{ detail: { node: any; }; }} */ event) => { + clicked.push(event.detail.node); + }); + + buttons[1].dispatchEvent(event); + + assert.equal(clicked.length, 1); + assert.equal(clicked[0].nodeName, 'BUTTON'); + assert.equal(clicked[0].textContent, 'bar'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/main.svelte new file mode 100644 index 000000000000..56ae6b2de2da --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-each-this/main.svelte @@ -0,0 +1,11 @@ + + +{#each items as item} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-each/_config.js new file mode 100644 index 000000000000..aa97c5d24a9a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-each/_config.js @@ -0,0 +1,36 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { + items: ['foo', 'bar', 'baz'], + selected: 'foo' + }; + }, + + html: ` + + + +

      selected: foo

      + `, + + test({ assert, target, window }) { + const buttons = target.querySelectorAll('button'); + const event = new window.MouseEvent('click', { bubbles: true }); + + buttons[1].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

      selected: bar

      + ` + ); + } +}); diff --git a/test/runtime/samples/event-handler-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-each/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-each/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-each/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-event-methods/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-event-methods/_config.js new file mode 100644 index 000000000000..1e591e56c631 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-event-methods/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component, target, window }) { + const allow = target.querySelector('.allow-propagation'); + const stop = target.querySelector('.stop-propagation'); + + allow?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + stop?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + + assert.equal(component.foo, true); + assert.equal(component.bar, false); + } +}); diff --git a/test/runtime/samples/event-handler-event-methods/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-event-methods/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-event-methods/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-event-methods/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-hoisted/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-hoisted/_config.js new file mode 100644 index 000000000000..e3e61fd2a710 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-hoisted/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { foo: [1], a: 42 }; + }, + + html: ` + + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + button.dispatchEvent(event); + assert.equal(component.snapshot, 42); + } +}); diff --git a/test/runtime/samples/event-handler-hoisted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-hoisted/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-hoisted/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-hoisted/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-body-once/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-body-once/_config.js new file mode 100644 index 000000000000..2a7499e2048b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-body-once/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, component, window }) { + const event = new window.MouseEvent('click', { bubbles: true }); + + await window.document.body.dispatchEvent(event); + assert.equal(component.count, 1); + + await window.document.body.dispatchEvent(event); + assert.equal(component.count, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-body-once/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-body-once/main.svelte new file mode 100644 index 000000000000..423a75d1f056 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-body-once/main.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-bubble/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-bubble/_config.js new file mode 100644 index 000000000000..c30af43043d2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-bubble/_config.js @@ -0,0 +1,12 @@ +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + const button = target.querySelector('button'); + ok(button); + + await button.click(); + + assert.ok(component.default_was_prevented); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-bubble/button.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-bubble/button.svelte new file mode 100644 index 000000000000..d94a505c0c82 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-bubble/button.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-bubble/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-bubble/main.svelte new file mode 100644 index 000000000000..d5134e28fa1f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-bubble/main.svelte @@ -0,0 +1,11 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-once-duplicated/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-once-duplicated/_config.js new file mode 100644 index 000000000000..7ab15086734b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-once-duplicated/_config.js @@ -0,0 +1,33 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + + + `, + + async test({ assert, component, target, window }) { + const buttons = target.querySelectorAll('button'); + + const event = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + ` + ); + + buttons[1].dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-once-duplicated/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-once-duplicated/main.svelte new file mode 100644 index 000000000000..3c30347b246d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-once-duplicated/main.svelte @@ -0,0 +1,6 @@ + + + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(event); + assert.equal(component.count, 1); + + await button.dispatchEvent(event); + assert.equal(component.count, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-once/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-once/main.svelte new file mode 100644 index 000000000000..2e185788dba5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-once/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-prevent-default/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-prevent-default/_config.js new file mode 100644 index 000000000000..8ec6e314de2a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-prevent-default/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { + bubbles: true, + cancelable: true + }); + + await button.dispatchEvent(event); + + assert.ok(component.default_was_prevented); + } +}); diff --git a/test/runtime/samples/event-handler-modifier-prevent-default/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-prevent-default/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-modifier-prevent-default/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-prevent-default/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-self/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-self/_config.js new file mode 100644 index 000000000000..6797174b7454 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-self/_config.js @@ -0,0 +1,20 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      + +
      + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(event); + + assert.ok(!component.inner_clicked); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-self/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-self/main.svelte new file mode 100644 index 000000000000..1becf44a9ec2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-self/main.svelte @@ -0,0 +1,11 @@ + + +
      + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-immediate-propagation/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-immediate-propagation/_config.js new file mode 100644 index 000000000000..7f0c8d533bc6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-immediate-propagation/_config.js @@ -0,0 +1,20 @@ +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + const event = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(event); + assert.deepEqual(component.logs, ['click_1', 'click_2']); + + component.click_2 = () => component.logs.push('22'); + await button.dispatchEvent(event); + assert.deepEqual(component.logs, ['click_1', 'click_2', 'click_1', '22']); + + component.click_1 = () => component.logs.push('11'); + await button.dispatchEvent(event); + assert.deepEqual(component.logs, ['click_1', 'click_2', 'click_1', '22', '11', '22']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-immediate-propagation/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-immediate-propagation/main.svelte new file mode 100644 index 000000000000..c038c213c492 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-immediate-propagation/main.svelte @@ -0,0 +1,22 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-propagation/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-propagation/_config.js new file mode 100644 index 000000000000..59c99d4ba55d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-propagation/_config.js @@ -0,0 +1,23 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      + +
      + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { + bubbles: true + }); + + await button.dispatchEvent(event); + + assert.ok(component.inner_clicked); + assert.ok(!component.outer_clicked); + } +}); diff --git a/test/runtime/samples/event-handler-modifier-stop-propagation/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-propagation/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-modifier-stop-propagation/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-stop-propagation/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-trusted/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-trusted/_config.js new file mode 100644 index 000000000000..b9237540e15a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-trusted/_config.js @@ -0,0 +1,13 @@ +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(event); + assert.equal(component.trusted, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-trusted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-trusted/main.svelte new file mode 100644 index 000000000000..504326a49814 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-modifier-trusted/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-multiple/_config.js new file mode 100644 index 000000000000..805c8840c946 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-multiple/_config.js @@ -0,0 +1,17 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + const event = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(event); + assert.equal(component.clickHandlerOne, 1); + assert.equal(component.clickHandlerTwo, 1); + } +}); diff --git a/test/runtime/samples/event-handler-multiple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-multiple/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-multiple/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-multiple/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-mutation-scope/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-mutation-scope/_config.js new file mode 100644 index 000000000000..825ffc73ef21 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-mutation-scope/_config.js @@ -0,0 +1,21 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, logs, target }) { + const button = target.querySelector('button'); + ok(button); + + flushSync(() => { + button.click(); + }); + + assert.deepEqual(logs, ['1 - 1']); + + flushSync(() => { + button.click(); + }); + + assert.deepEqual(logs, ['1 - 1', '2 - 2']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-mutation-scope/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-mutation-scope/main.svelte new file mode 100644 index 000000000000..4ef9bf62bc23 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-mutation-scope/main.svelte @@ -0,0 +1,15 @@ + + + +{referenced_directly} diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-removal/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-removal/_config.js new file mode 100644 index 000000000000..f1cce4bfafed --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-removal/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +// TODO gah, JSDOM appears to behave differently to real browsers here... probably need to raise an issue + +export default test({ + html: '', + + test({ assert, component }) { + component.input.focus(); + + // this should NOT trigger blur event + component.visible = false; + assert.ok(!component.blurred); + + component.visible = true; + component.input.focus(); + + // this SHOULD trigger blur event + component.input.blur(); + assert.ok(component.blurred); + } +}); diff --git a/test/runtime/samples/event-handler-removal/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-removal/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-removal/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-removal/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-sanitize/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-sanitize/Component.svelte new file mode 100644 index 000000000000..4b4bd05df62c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-sanitize/Component.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-sanitize/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-sanitize/_config.js new file mode 100644 index 000000000000..4986ac9de2d3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-sanitize/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      toggle
      + + `, + + async test({ assert, target, window }) { + const div = target.querySelector('div'); + const button = target.querySelector('button'); + ok(div); + ok(button); + const event = new window.MouseEvent('some-event'); + + div.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      toggle
      + +

      hello!

      + ` + ); + + button.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      toggle
      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-sanitize/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-sanitize/main.svelte new file mode 100644 index 000000000000..d2023319a3a3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-sanitize/main.svelte @@ -0,0 +1,12 @@ + + +
      toggle
      + visible = !visible}> + +{#if visible} +

      hello!

      +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/Widget.svelte new file mode 100644 index 000000000000..45f55baae18c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/Widget.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/_config.js new file mode 100644 index 000000000000..0201f3da3dac --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + let answer; + component.$on('foo', (/** @type {{ detail: { answer: any; }; }} */ event) => { + answer = event.detail.answer; + }); + + // @ts-ignore + button.dispatchEvent(event); + assert.equal(answer, 42); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/main.svelte new file mode 100644 index 000000000000..d70ec7290e8a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-component/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/Widget.svelte new file mode 100644 index 000000000000..45f55baae18c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/Widget.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/_config.js new file mode 100644 index 000000000000..0201f3da3dac --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.MouseEvent('click'); + + let answer; + component.$on('foo', (/** @type {{ detail: { answer: any; }; }} */ event) => { + answer = event.detail.answer; + }); + + // @ts-ignore + button.dispatchEvent(event); + assert.equal(answer, 42); + } +}); diff --git a/test/runtime/samples/event-handler-shorthand-dynamic-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-shorthand-dynamic-component/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-dynamic-component/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/_config.js new file mode 100644 index 000000000000..47dac621173c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const event = new window.Event('click-now'); + + let clicked; + component.$on('click-now', () => { + clicked = true; + }); + + // @ts-ignore + button.dispatchEvent(event); + assert.ok(clicked); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/main.svelte new file mode 100644 index 000000000000..8241f05659c8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-shorthand-sanitized/main.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-this-methods/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-this-methods/_config.js new file mode 100644 index 000000000000..a089aabed20e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-this-methods/_config.js @@ -0,0 +1,20 @@ +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + // Click events don't focus elements in JSDOM – obviously they would + // in real browsers. More realistically, you'd use this for e.g. + // this.select(), but that's harder to test than this.focus() + + const wont = target.querySelector('.wont-focus'); + const will = target.querySelector('.will-focus'); + ok(wont); + ok(will); + + wont.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + assert.equal(window.document.activeElement, window.document.body); + + will.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + assert.equal(window.document.activeElement, will); + } +}); diff --git a/test/runtime/samples/event-handler-this-methods/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-this-methods/main.svelte similarity index 100% rename from test/runtime/samples/event-handler-this-methods/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler-this-methods/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler-undefined/_config.js new file mode 100644 index 000000000000..662164af47e6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-undefined/_config.js @@ -0,0 +1,14 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const input = target.querySelector('input'); + + flushSync(() => { + input?.click(); + }); + + assert.htmlEqual(target.innerHTML, ``); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler-undefined/main.svelte new file mode 100644 index 000000000000..770c17901c87 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler-undefined/main.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/event-handler/_config.js b/packages/svelte/tests/runtime-legacy/samples/event-handler/_config.js new file mode 100644 index 000000000000..0e437cdeb66d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/event-handler/_config.js @@ -0,0 +1,36 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const event = new window.MouseEvent('click', { bubbles: true }); + + button.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      hello!

      + ` + ); + + button.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/event-handler/main.svelte b/packages/svelte/tests/runtime-legacy/samples/event-handler/main.svelte similarity index 100% rename from test/runtime/samples/event-handler/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/event-handler/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/export-function-hoisting/_config.js b/packages/svelte/tests/runtime-legacy/samples/export-function-hoisting/_config.js new file mode 100644 index 000000000000..c66de4c7f4b8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/export-function-hoisting/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'Compile plz' +}); diff --git a/test/runtime/samples/export-function-hoisting/main.svelte b/packages/svelte/tests/runtime-legacy/samples/export-function-hoisting/main.svelte similarity index 100% rename from test/runtime/samples/export-function-hoisting/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/export-function-hoisting/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/fragment-trailing-whitespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/fragment-trailing-whitespace/_config.js new file mode 100644 index 000000000000..7a62ff904202 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/fragment-trailing-whitespace/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +const message = 'the quick brown fox jumps over the lazy dog'; +// In Svelte 4 this was `${c} ` - whitespace behavior change +const expected = [...message].map((c) => `${c}`).join(''); + +export default test({ + get props() { + return { message }; + }, + + async test({ assert, target }) { + const firstSpanList = target.children[0]; + assert.htmlEqualWithOptions(firstSpanList.innerHTML, expected, { + withoutNormalizeHtml: true, + preserveComments: false + }); + + const secondSpanList = target.children[1]; + assert.htmlEqualWithOptions(secondSpanList.innerHTML, expected, { + withoutNormalizeHtml: true, + preserveComments: false + }); + } +}); diff --git a/test/runtime/samples/fragment-trailing-whitespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/fragment-trailing-whitespace/main.svelte similarity index 100% rename from test/runtime/samples/fragment-trailing-whitespace/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/fragment-trailing-whitespace/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/function-expression-inline/_config.js b/packages/svelte/tests/runtime-legacy/samples/function-expression-inline/_config.js new file mode 100644 index 000000000000..e06350a6b6c9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/function-expression-inline/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; +export default test({ + html: ` + +

      1

      +

      2

      +

      3

      + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + button?.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      2

      +

      4

      +

      6

      + ` + ); + } +}); diff --git a/test/runtime/samples/function-expression-inline/main.svelte b/packages/svelte/tests/runtime-legacy/samples/function-expression-inline/main.svelte similarity index 100% rename from test/runtime/samples/function-expression-inline/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/function-expression-inline/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/function-hoisting/_config.js b/packages/svelte/tests/runtime-legacy/samples/function-hoisting/_config.js new file mode 100644 index 000000000000..e2d4cb66b902 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/function-hoisting/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { greeting: 'Good day' }; + }, + + html: '

      Good day, world

      ' +}); diff --git a/test/runtime/samples/function-hoisting/main.svelte b/packages/svelte/tests/runtime-legacy/samples/function-hoisting/main.svelte similarity index 100% rename from test/runtime/samples/function-hoisting/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/function-hoisting/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/function-in-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/function-in-expression/_config.js new file mode 100644 index 000000000000..b240c2ebc927 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/function-in-expression/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + numbers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + }; + }, + + html: '1, 3, 5, 7, 9', + + test({ assert, component, target }) { + component.numbers = [10, 11, 12, 13, 14, 15, 16]; + + assert.htmlEqual(target.innerHTML, '11, 13, 15'); + } +}); diff --git a/test/runtime/samples/function-in-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/function-in-expression/main.svelte similarity index 100% rename from test/runtime/samples/function-in-expression/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/function-in-expression/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/globals-accessible-directly-process/_config.js b/packages/svelte/tests/runtime-legacy/samples/globals-accessible-directly-process/_config.js new file mode 100644 index 000000000000..38d3e5afa3f8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/globals-accessible-directly-process/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + html: '

      Hello world!

      ', + + before_test() { + process.env.TMP_VAR = 'world'; + }, + + after_test() { + delete process.env.TMP_VAR; + } +}); diff --git a/test/runtime/samples/globals-accessible-directly-process/main.svelte b/packages/svelte/tests/runtime-legacy/samples/globals-accessible-directly-process/main.svelte similarity index 100% rename from test/runtime/samples/globals-accessible-directly-process/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/globals-accessible-directly-process/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/globals-accessible-directly/_config.js b/packages/svelte/tests/runtime-legacy/samples/globals-accessible-directly/_config.js new file mode 100644 index 000000000000..b3b105102170 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/globals-accessible-directly/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target }) { + assert.htmlEqual(target.innerHTML, 'NaN'); + } +}); diff --git a/test/runtime/samples/globals-accessible-directly/main.svelte b/packages/svelte/tests/runtime-legacy/samples/globals-accessible-directly/main.svelte similarity index 100% rename from test/runtime/samples/globals-accessible-directly/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/globals-accessible-directly/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/globals-not-dereferenced/_config.js b/packages/svelte/tests/runtime-legacy/samples/globals-not-dereferenced/_config.js new file mode 100644 index 000000000000..552fd44853cf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/globals-not-dereferenced/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 10 }; + }, + + html: '5', + + test({ assert, component, target }) { + component.x = 3; + assert.htmlEqual(target.innerHTML, '3'); + } +}); diff --git a/test/runtime/samples/globals-not-dereferenced/main.svelte b/packages/svelte/tests/runtime-legacy/samples/globals-not-dereferenced/main.svelte similarity index 100% rename from test/runtime/samples/globals-not-dereferenced/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/globals-not-dereferenced/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/globals-not-overwritten-by-bindings/_config.js b/packages/svelte/tests/runtime-legacy/samples/globals-not-overwritten-by-bindings/_config.js new file mode 100644 index 000000000000..6ffb1b737089 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/globals-not-overwritten-by-bindings/_config.js @@ -0,0 +1,86 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      + + +
      + +
      + + +
      + +
      + + +
      + `, + + ssrHtml: ` +
      + + +
      + +
      + + +
      + +
      + + +
      + `, + + get props() { + return { + todos: { + first: { description: 'Buy some milk', done: true }, + second: { + description: 'Do the laundry', + done: true + }, + third: { + description: "Find life's true purpose", + done: false + } + } + }; + }, + + test({ assert, component, target, window }) { + const input = /** @type {HTMLInputElement} */ ( + document.querySelectorAll('input[type="checkbox"]')[2] + ); + const change = new window.Event('change'); + + input.checked = true; + input.dispatchEvent(change); + flushSync(); + + assert.ok(component.todos.third.done); + assert.htmlEqual( + target.innerHTML, + ` +
      + + +
      + +
      + + +
      + +
      + + +
      + ` + ); + } +}); diff --git a/test/runtime/samples/globals-not-overwritten-by-bindings/main.svelte b/packages/svelte/tests/runtime-legacy/samples/globals-not-overwritten-by-bindings/main.svelte similarity index 100% rename from test/runtime/samples/globals-not-overwritten-by-bindings/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/globals-not-overwritten-by-bindings/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-data/_config.js b/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-data/_config.js new file mode 100644 index 000000000000..3851fe0a2ca7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-data/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 10 }; + }, + + html: 'potato', + + test({ assert, component, target }) { + component.x = 3; + assert.htmlEqual(target.innerHTML, 'potato'); + } +}); diff --git a/test/runtime/samples/globals-shadowed-by-data/main.svelte b/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-data/main.svelte similarity index 100% rename from test/runtime/samples/globals-shadowed-by-data/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-data/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-each-binding/_config.js b/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-each-binding/_config.js new file mode 100644 index 000000000000..457c4f5a1d77 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-each-binding/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      Alert1

      Alert2

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-each-binding/main.svelte b/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-each-binding/main.svelte new file mode 100644 index 000000000000..3d0ac3f3ec0b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-each-binding/main.svelte @@ -0,0 +1,7 @@ + + +{#each alerts as alert} +

      {alert}

      +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-helpers/_config.js b/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-helpers/_config.js new file mode 100644 index 000000000000..3851fe0a2ca7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-helpers/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 10 }; + }, + + html: 'potato', + + test({ assert, component, target }) { + component.x = 3; + assert.htmlEqual(target.innerHTML, 'potato'); + } +}); diff --git a/test/runtime/samples/globals-shadowed-by-helpers/main.svelte b/packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-helpers/main.svelte similarity index 100% rename from test/runtime/samples/globals-shadowed-by-helpers/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/globals-shadowed-by-helpers/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/hash-in-attribute/_config.js b/packages/svelte/tests/runtime-legacy/samples/hash-in-attribute/_config.js new file mode 100644 index 000000000000..40dbfffe17f8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/hash-in-attribute/_config.js @@ -0,0 +1,34 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { links: ['a', 'b', 'c'] }; + }, + + html: ` + x#a + x#b + x#c + `, + + test({ assert, component, target }) { + component.links = ['d', 'e', 'f']; + + const links = [...target.querySelectorAll('a')]; + + assert.deepEqual( + // Vitest/JSDom does prepend the base URL, so we need to strip it + links.map((l) => l.href.slice(l.href.lastIndexOf('/') + 1)), + ['x#d', 'x#e', 'x#f'] + ); + + assert.htmlEqual( + target.innerHTML, + ` + x#d + x#e + x#f + ` + ); + } +}); diff --git a/test/runtime/samples/hash-in-attribute/main.svelte b/packages/svelte/tests/runtime-legacy/samples/hash-in-attribute/main.svelte similarity index 100% rename from test/runtime/samples/hash-in-attribute/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/hash-in-attribute/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/A.svelte b/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/A.svelte new file mode 100644 index 000000000000..f05488e3e4e3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/A.svelte @@ -0,0 +1,5 @@ + + + + +A \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/B.svelte b/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/B.svelte new file mode 100644 index 000000000000..943b307cc302 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/B.svelte @@ -0,0 +1,5 @@ + + + + +B \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/_config.js new file mode 100644 index 000000000000..4c2c96dca4a9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: ` + A + `, + + test({ assert, component, window }) { + component.x = false; + + const meta = window.document.querySelectorAll('meta'); + + assert.equal(meta.length, 1); + assert.equal(meta[0].name, 'description'); + assert.equal(meta[0].content, 'B'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/main.svelte new file mode 100644 index 000000000000..e4acd7737ad9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-detached-in-dynamic-component/main.svelte @@ -0,0 +1,8 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/head-if-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/head-if-block/_config.js new file mode 100644 index 000000000000..281a4694c9a9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-if-block/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { condition: false }; + }, + + test({ assert, component, window }) { + assert.equal(window.document.title, ''); + + component.condition = true; + assert.equal(window.document.title, 'woo!!!'); + } +}); diff --git a/test/runtime/samples/head-if-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/head-if-block/main.svelte similarity index 100% rename from test/runtime/samples/head-if-block/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/head-if-block/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/head-if-else-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/head-if-else-block/_config.js new file mode 100644 index 000000000000..873146ed16ad --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-if-else-block/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { condition: false }; + }, + + test({ assert, component, window }) { + assert.equal(window.document.title, ''); + assert.equal(Boolean(window.document.getElementById('meta')), true); + + component.condition = true; + assert.equal(window.document.title, 'woo!!!'); + assert.equal(window.document.getElementById('meta'), null); + } +}); diff --git a/test/runtime/samples/head-if-else-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/head-if-else-block/main.svelte similarity index 100% rename from test/runtime/samples/head-if-else-block/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/head-if-else-block/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/head-if-else-raw-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/head-if-else-raw-dynamic/_config.js new file mode 100644 index 000000000000..c429b44b8955 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-if-else-raw-dynamic/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +const foo = ''; +const bar = ''; + +export default test({ + get props() { + return { condition: false, foo, bar }; + }, + + test({ assert, component, window }) { + assert.equal(window.document.head.innerHTML.includes(foo), false); + assert.equal(window.document.head.innerHTML.includes(bar), true); + + component.condition = true; + assert.equal(window.document.head.innerHTML.includes(foo), true); + assert.equal(window.document.head.innerHTML.includes(bar), false); + } +}); diff --git a/test/runtime/samples/head-if-else-raw-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/head-if-else-raw-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/head-if-else-raw-dynamic/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/head-if-else-raw-dynamic/main.svelte diff --git a/test/runtime/samples/head-raw-dynamic/Bar.svelte b/packages/svelte/tests/runtime-legacy/samples/head-raw-dynamic/Bar.svelte similarity index 100% rename from test/runtime/samples/head-raw-dynamic/Bar.svelte rename to packages/svelte/tests/runtime-legacy/samples/head-raw-dynamic/Bar.svelte diff --git a/test/runtime/samples/head-raw-dynamic/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/head-raw-dynamic/Foo.svelte similarity index 100% rename from test/runtime/samples/head-raw-dynamic/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/head-raw-dynamic/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/head-raw-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/head-raw-dynamic/_config.js new file mode 100644 index 000000000000..7a5510271c01 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-raw-dynamic/_config.js @@ -0,0 +1,26 @@ +import { test } from '../../test'; + +const foo = ''; +const bar = ''; + +export default test({ + get props() { + return { condition: 1, foo, bar }; + }, + + test({ assert, component, window }) { + assert.equal(window.document.head.innerHTML.includes(foo), true); + + component.condition = 3; + assert.equal(window.document.head.innerHTML.includes(foo), false); + + component.condition = 2; + assert.equal(window.document.title, 'bar!!!'); + assert.equal(window.document.head.innerHTML.includes(bar), true); + assert.equal(Boolean(window.document.getElementById('meta')), true); + + component.condition = 3; + assert.equal(window.document.head.innerHTML.includes(bar), false); + assert.equal(window.document.getElementById('meta'), null); + } +}); diff --git a/test/runtime/samples/head-raw-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/head-raw-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/head-raw-dynamic/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/head-raw-dynamic/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/head-title-dynamic-simple/_config.js b/packages/svelte/tests/runtime-legacy/samples/head-title-dynamic-simple/_config.js new file mode 100644 index 000000000000..1e5bd54a0729 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-title-dynamic-simple/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: 'A Title' }; + }, + + test({ assert, component, window }) { + assert.equal(window.document.title, 'A Title'); + + component.foo = 'Also A Title'; + assert.equal(window.document.title, 'Also A Title'); + } +}); diff --git a/test/runtime/samples/head-title-dynamic-simple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/head-title-dynamic-simple/main.svelte similarity index 100% rename from test/runtime/samples/head-title-dynamic-simple/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/head-title-dynamic-simple/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/head-title-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/head-title-dynamic/_config.js new file mode 100644 index 000000000000..c1578f070515 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-title-dynamic/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { adjective: 'custom' }; + }, + + test({ assert, component, window }) { + assert.equal(window.document.title, 'a custom title'); + + component.adjective = 'different'; + assert.equal(window.document.title, 'a different title'); + } +}); diff --git a/test/runtime/samples/head-title-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/head-title-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/head-title-dynamic/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/head-title-dynamic/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/head-title-empty/_config.js b/packages/svelte/tests/runtime-legacy/samples/head-title-empty/_config.js new file mode 100644 index 000000000000..76b7f9d8543d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-title-empty/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, window }) { + assert.equal(window.document.title, ''); + } +}); diff --git a/test/runtime/samples/head-title-empty/main.svelte b/packages/svelte/tests/runtime-legacy/samples/head-title-empty/main.svelte similarity index 100% rename from test/runtime/samples/head-title-empty/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/head-title-empty/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/head-title-static-dynamic-element/_config.js b/packages/svelte/tests/runtime-legacy/samples/head-title-static-dynamic-element/_config.js new file mode 100644 index 000000000000..5afa16553ee7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-title-static-dynamic-element/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, window }) { + assert.equal(window.document.title, 'changed'); + + const meta = window.document.head.querySelector('meta'); + assert.htmlEqual(meta?.outerHTML || '', ``); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/head-title-static-dynamic-element/main.svelte b/packages/svelte/tests/runtime-legacy/samples/head-title-static-dynamic-element/main.svelte new file mode 100644 index 000000000000..28eb01755439 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-title-static-dynamic-element/main.svelte @@ -0,0 +1,8 @@ + + + + changed + + diff --git a/packages/svelte/tests/runtime-legacy/samples/head-title-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/head-title-static/_config.js new file mode 100644 index 000000000000..da910cf2e364 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/head-title-static/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, window }) { + assert.equal(window.document.title, 'changed'); + } +}); diff --git a/test/runtime/samples/head-title-static/main.svelte b/packages/svelte/tests/runtime-legacy/samples/head-title-static/main.svelte similarity index 100% rename from test/runtime/samples/head-title-static/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/head-title-static/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/hello-world/_config.js b/packages/svelte/tests/runtime-legacy/samples/hello-world/_config.js new file mode 100644 index 000000000000..f03af1b02158 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/hello-world/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { name: 'world' }; + }, + + html: '

      Hello world!

      ', + + test({ assert, component, target }) { + component.name = 'everybody'; + assert.htmlEqual(target.innerHTML, '

      Hello everybody!

      '); + } +}); diff --git a/test/runtime/samples/hello-world/main.svelte b/packages/svelte/tests/runtime-legacy/samples/hello-world/main.svelte similarity index 100% rename from test/runtime/samples/hello-world/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/hello-world/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/helpers-not-call-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/helpers-not-call-expression/_config.js new file mode 100644 index 000000000000..db0d7cc2338f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/helpers-not-call-expression/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      1,4,9

      ' +}); diff --git a/test/runtime/samples/helpers-not-call-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/helpers-not-call-expression/main.svelte similarity index 100% rename from test/runtime/samples/helpers-not-call-expression/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/helpers-not-call-expression/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/helpers/_config.js b/packages/svelte/tests/runtime-legacy/samples/helpers/_config.js new file mode 100644 index 000000000000..56d4dc2ebea9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/helpers/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      sdrawkcab

      ' +}); diff --git a/test/runtime/samples/helpers/main.svelte b/packages/svelte/tests/runtime-legacy/samples/helpers/main.svelte similarity index 100% rename from test/runtime/samples/helpers/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/helpers/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/html-entities-alongside-expressions/_config.js b/packages/svelte/tests/runtime-legacy/samples/html-entities-alongside-expressions/_config.js new file mode 100644 index 000000000000..762e694b783f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-entities-alongside-expressions/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      <p> & > </p>
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/html-entities-alongside-expressions/main.svelte b/packages/svelte/tests/runtime-legacy/samples/html-entities-alongside-expressions/main.svelte new file mode 100644 index 000000000000..2c65010b03d2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-entities-alongside-expressions/main.svelte @@ -0,0 +1,5 @@ + + +
      <p> & {str} </p>
      diff --git a/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-attributes/_config.js b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-attributes/_config.js new file mode 100644 index 000000000000..e1c652881964 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-attributes/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + + + + + + + + + + + + + + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-attributes/main.svelte b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-attributes/main.svelte new file mode 100644 index 000000000000..21d56a2f6951 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-attributes/main.svelte @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-component-slot/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-component-slot/Component.svelte new file mode 100644 index 000000000000..8063609738c2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-component-slot/Component.svelte @@ -0,0 +1,3 @@ +
      + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-component-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-component-slot/_config.js new file mode 100644 index 000000000000..ed89521113f5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-component-slot/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
       
      + +
      +   +
      + +
       
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-component-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-component-slot/main.svelte new file mode 100644 index 000000000000..8baecfedcc4a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-component-slot/main.svelte @@ -0,0 +1,13 @@ + + +  + + +   + + + + {@html " "} + diff --git a/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-elements/_config.js b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-elements/_config.js new file mode 100644 index 000000000000..049a2d2e2bcb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-elements/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      this <em>should</em> not be <strong>bold</strong>

      + ` +}); diff --git a/test/runtime/samples/html-entities-inside-elements/main.svelte b/packages/svelte/tests/runtime-legacy/samples/html-entities-inside-elements/main.svelte similarity index 100% rename from test/runtime/samples/html-entities-inside-elements/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/html-entities-inside-elements/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/html-entities/_config.js b/packages/svelte/tests/runtime-legacy/samples/html-entities/_config.js new file mode 100644 index 000000000000..add763989e20 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-entities/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; + +export default test({ + html: ` + * + * + * + * + * + + + A + + + + &stringnotanentity; + + different &rect and ▭ + + ©otherstring + + ©=otherstring + + ©=otherstring + + ©123 + + Ÿotherstring + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/html-entities/main.svelte b/packages/svelte/tests/runtime-legacy/samples/html-entities/main.svelte new file mode 100644 index 000000000000..2d0d66c939de --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-entities/main.svelte @@ -0,0 +1,24 @@ +* +* +* +* +* + + +A + + + +&stringnotanentity; + +different &rect and ▭ + +©otherstring + +©=otherstring + +©=otherstring + +©123 + +Ÿotherstring diff --git a/packages/svelte/tests/runtime-legacy/samples/html-non-entities-inside-elements/_config.js b/packages/svelte/tests/runtime-legacy/samples/html-non-entities-inside-elements/_config.js new file mode 100644 index 000000000000..786f94b7c99c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-non-entities-inside-elements/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      'foo'
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/html-non-entities-inside-elements/main.svelte b/packages/svelte/tests/runtime-legacy/samples/html-non-entities-inside-elements/main.svelte new file mode 100644 index 000000000000..b878bc467842 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/html-non-entities-inside-elements/main.svelte @@ -0,0 +1 @@ +
      'foo'
      diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-component-store-function-conditionals/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-component-store-function-conditionals/Widget.svelte new file mode 100644 index 000000000000..a74ce95de527 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-component-store-function-conditionals/Widget.svelte @@ -0,0 +1 @@ +

      OK

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-component-store-function-conditionals/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-component-store-function-conditionals/_config.js new file mode 100644 index 000000000000..7519b0b5eb3c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-component-store-function-conditionals/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      OK

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-component-store-function-conditionals/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-component-store-function-conditionals/main.svelte new file mode 100644 index 000000000000..765654f0d2a8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-component-store-function-conditionals/main.svelte @@ -0,0 +1,12 @@ + + +{#if $a || b() } + +{:else} +
      fail
      +{/if} \ No newline at end of file diff --git a/test/runtime/samples/if-block-component-without-outro/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-component-without-outro/Widget.svelte similarity index 100% rename from test/runtime/samples/if-block-component-without-outro/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-component-without-outro/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-component-without-outro/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-component-without-outro/_config.js new file mode 100644 index 000000000000..3d4f6497cd1b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-component-without-outro/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: true }; + }, + + html: '
      A wild component appears
      ', + + test({ assert, component, target }) { + component.foo = false; + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/if-block-component-without-outro/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-component-without-outro/main.svelte similarity index 100% rename from test/runtime/samples/if-block-component-without-outro/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-component-without-outro/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-compound-outro-no-dependencies/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-compound-outro-no-dependencies/_config.js new file mode 100644 index 000000000000..40f0609eef75 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-compound-outro-no-dependencies/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'blah blah blah blah' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-compound-outro-no-dependencies/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-compound-outro-no-dependencies/main.svelte new file mode 100644 index 000000000000..84224116da65 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-compound-outro-no-dependencies/main.svelte @@ -0,0 +1,32 @@ + + +{#if $foo} + blah +{:else} + {#if bar()} + + {/if} +{/if} + +{#if $foo} + blah +{:else} + {#if bar} + + {/if} +{/if} + +{#if $foo} + blah +{:else if bar()} + +{/if} + +{#if $foo} + blah +{:else if bar} + +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-conservative-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-conservative-update/_config.js new file mode 100644 index 000000000000..3cc5e9dffc87 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-conservative-update/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +let count = 0; + +export default test({ + get props() { + return { + foo: 'potato', + fn: () => { + count += 1; + return true; + } + }; + }, + + html: '

      potato

      ', + + before_test() { + count = 0; + }, + test({ assert, component, target }) { + assert.equal(count, 1); + + component.foo = 'soup'; + assert.equal(count, 1); + + assert.htmlEqual(target.innerHTML, '

      soup

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-conservative-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-conservative-update/main.svelte new file mode 100644 index 000000000000..93a40b0e9ef4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-conservative-update/main.svelte @@ -0,0 +1,8 @@ + + +{#if fn()} +

      {foo}

      +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-else-conservative-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-else-conservative-update/_config.js new file mode 100644 index 000000000000..99e4bf7a465a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-else-conservative-update/_config.js @@ -0,0 +1,47 @@ +import { test } from '../../test'; + +let a = true; +let count_a = 0; +let count_b = 0; + +export default test({ + get props() { + return { + foo: 'potato', + fn: () => { + count_a += 1; + return a; + }, + other_fn: () => { + count_b += 1; + return true; + } + }; + }, + + html: '

      potato

      ', + + before_test() { + a = true; + count_a = 0; + count_b = 0; + }, + + test({ assert, component, target }) { + assert.equal(count_a, 1); + assert.equal(count_b, 0); + + a = false; + component.foo = 'soup'; + assert.equal(count_a, 2); + assert.equal(count_b, 1); + + assert.htmlEqual(target.innerHTML, '

      SOUP

      '); + + component.foo = 'salad'; + assert.equal(count_a, 3); + assert.equal(count_b, 1); + + assert.htmlEqual(target.innerHTML, '

      SALAD

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-else-conservative-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-else-conservative-update/main.svelte new file mode 100644 index 000000000000..ef9da266b9d4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-else-conservative-update/main.svelte @@ -0,0 +1,11 @@ + + +{#if fn(foo)} +

      {foo}

      +{:else if other_fn()} +

      {foo.toUpperCase()}

      +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-else-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-else-in-each/_config.js new file mode 100644 index 000000000000..ed12c91f8767 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-else-in-each/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { array: [true, false] }; + }, + html: ` +
      foo
      +
      bar
      + ` +}); diff --git a/test/runtime/samples/if-block-else-in-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-else-in-each/main.svelte similarity index 100% rename from test/runtime/samples/if-block-else-in-each/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-else-in-each/main.svelte diff --git a/test/runtime/samples/if-block-else-partial-outro/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-else-partial-outro/Foo.svelte similarity index 100% rename from test/runtime/samples/if-block-else-partial-outro/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-else-partial-outro/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-else-partial-outro/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-else-partial-outro/_config.js new file mode 100644 index 000000000000..b94d1f53a5d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-else-partial-outro/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 1, y: false }; + }, + + html: ` + 1 + `, + + test({ assert, component, target }) { + component.x = 2; + assert.htmlEqual( + target.innerHTML, + ` + 2 + ` + ); + } +}); diff --git a/test/runtime/samples/if-block-else-partial-outro/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-else-partial-outro/main.svelte similarity index 100% rename from test/runtime/samples/if-block-else-partial-outro/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-else-partial-outro/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-else-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-else-update/_config.js new file mode 100644 index 000000000000..bed9ff661139 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-else-update/_config.js @@ -0,0 +1,69 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const [btn1, btn2] = target.querySelectorAll('button'); + + const clickEvent = new window.Event('click', { bubbles: true }); + + btn2.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + +
      + foo: false, bar: true +
      + bar! + ` + ); + + btn1.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + +
      + foo: true, bar: true +
      + foo! + ` + ); + + btn2.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + +
      + foo: true, bar: false +
      + foo! + ` + ); + + btn1.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + +
      + foo: false, bar: false +
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-else-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-else-update/main.svelte new file mode 100644 index 000000000000..258d0422ba31 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-else-update/main.svelte @@ -0,0 +1,21 @@ + + + + + +
      +{@html `foo: ${foo}, bar: ${bar.every(x => x)}`} +
      + +{#if foo} + foo! +{:else if bar.every(x => x)} + bar! +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-else/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-else/_config.js new file mode 100644 index 000000000000..ceffda2d9c33 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-else/_config.js @@ -0,0 +1,41 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: true, bar: false }; + }, + + html: ` +

      foo

      +

      not bar

      + `, + + test({ assert, component, target }) { + component.foo = false; + assert.htmlEqual( + target.innerHTML, + ` +

      not foo

      +

      not bar

      + ` + ); + + component.bar = true; + assert.htmlEqual( + target.innerHTML, + ` +

      not foo

      +

      bar

      + ` + ); + + component.foo = true; + assert.htmlEqual( + target.innerHTML, + ` +

      foo

      +

      bar

      + ` + ); + } +}); diff --git a/test/runtime/samples/if-block-else/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-else/main.svelte similarity index 100% rename from test/runtime/samples/if-block-else/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-else/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-elseif-no-else/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-elseif-no-else/_config.js new file mode 100644 index 000000000000..ad4bdf95e1ad --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-elseif-no-else/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 11 }; + }, + + html: ` +

      x is greater than 10

      + `, + + test({ assert, component, target }) { + component.x = 4; + assert.htmlEqual( + target.innerHTML, + ` +

      x is less than 5

      + ` + ); + + component.x = 6; + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/if-block-elseif-no-else/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-elseif-no-else/main.svelte similarity index 100% rename from test/runtime/samples/if-block-elseif-no-else/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-elseif-no-else/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-elseif-text/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-elseif-text/_config.js new file mode 100644 index 000000000000..57ab538f9925 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-elseif-text/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 11 }; + }, + + html: ` + before-if-after + `, + + test({ assert, component, target }) { + component.x = 4; + assert.htmlEqual( + target.innerHTML, + ` + before-elseif-after + ` + ); + + component.x = 6; + assert.htmlEqual( + target.innerHTML, + ` + before-else-after + ` + ); + } +}); diff --git a/test/runtime/samples/if-block-elseif-text/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-elseif-text/main.svelte similarity index 100% rename from test/runtime/samples/if-block-elseif-text/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-elseif-text/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-elseif/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-elseif/_config.js new file mode 100644 index 000000000000..c25fcce0f358 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-elseif/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 11 }; + }, + + html: ` +

      x is greater than 10

      + `, + + test({ assert, component, target }) { + component.x = 4; + assert.htmlEqual( + target.innerHTML, + ` +

      x is less than 5

      + ` + ); + + component.x = 6; + assert.htmlEqual( + target.innerHTML, + ` +

      x is between 5 and 10

      + ` + ); + } +}); diff --git a/test/runtime/samples/if-block-elseif/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-elseif/main.svelte similarity index 100% rename from test/runtime/samples/if-block-elseif/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-elseif/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-expression/_config.js new file mode 100644 index 000000000000..08bffb483fe5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-expression/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      two is greater than one

      ' +}); diff --git a/test/runtime/samples/if-block-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-expression/main.svelte similarity index 100% rename from test/runtime/samples/if-block-expression/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-expression/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-first/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-first/_config.js new file mode 100644 index 000000000000..6ee308b9dd96 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-first/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { visible: false }; + }, + + html: '
      before me
      ', + + test({ assert, component, target }) { + component.visible = true; + assert.htmlEqual(target.innerHTML, '
      i am visible
      before me
      '); + } +}); diff --git a/test/runtime/samples/if-block-first/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-first/main.svelte similarity index 100% rename from test/runtime/samples/if-block-first/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-first/main.svelte diff --git a/test/runtime/samples/if-block-no-outro-else-with-outro/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-no-outro-else-with-outro/Widget.svelte similarity index 100% rename from test/runtime/samples/if-block-no-outro-else-with-outro/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-no-outro-else-with-outro/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-no-outro-else-with-outro/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-no-outro-else-with-outro/_config.js new file mode 100644 index 000000000000..2e33ad190bbe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-no-outro-else-with-outro/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; + +export default test({ + props: { + x: 'x' + }, + html: ` +
      A wild component appears
      +

      x

      + + `, + + ssrHtml: ` +
      A wild component appears
      +

      x

      + + `, + + test({ assert, component, target }) { + component.x = 'y'; + assert.htmlEqual( + target.innerHTML, + ` +
      A wild component appears
      +

      y

      + + ` + ); + } +}); diff --git a/test/runtime/samples/if-block-no-outro-else-with-outro/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-no-outro-else-with-outro/main.svelte similarity index 100% rename from test/runtime/samples/if-block-no-outro-else-with-outro/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-no-outro-else-with-outro/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-or/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-or/_config.js new file mode 100644 index 000000000000..46cad5eea531 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-or/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { a: true, b: false }; + }, + + html: '

      i am visible

      ', + + test({ assert, component, target }) { + component.a = false; + assert.htmlEqual(target.innerHTML, ''); + component.b = true; + assert.htmlEqual(target.innerHTML, '

      i am visible

      '); + } +}); diff --git a/test/runtime/samples/if-block-or/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-or/main.svelte similarity index 100% rename from test/runtime/samples/if-block-or/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-or/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-outro-computed-function/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-computed-function/Foo.svelte new file mode 100644 index 000000000000..19102815663d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-computed-function/Foo.svelte @@ -0,0 +1 @@ +foo \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-outro-computed-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-computed-function/_config.js new file mode 100644 index 000000000000..5b25900a38d4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-computed-function/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: true }; + }, + + html: 'foo', + + test({ assert, component, target }) { + component.foo = false; + assert.htmlEqual(target.innerHTML, 'bar'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-outro-computed-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-computed-function/main.svelte new file mode 100644 index 000000000000..adf7cc3e0b8c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-computed-function/main.svelte @@ -0,0 +1,13 @@ + + +{#if foo} + +{:else if bar()} + bar +{:else} + else +{/if} diff --git a/test/runtime/samples/if-block-outro-nested-else/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-nested-else/Component.svelte similarity index 100% rename from test/runtime/samples/if-block-outro-nested-else/Component.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-outro-nested-else/Component.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-outro-nested-else/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-nested-else/_config.js new file mode 100644 index 000000000000..0545a4528e29 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-nested-else/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + test({ component }) { + // Would cause "TypeError: Cannot read property 'o' of undefined" + component.foo = false; + } +}); diff --git a/test/runtime/samples/if-block-outro-nested-else/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-nested-else/main.svelte similarity index 100% rename from test/runtime/samples/if-block-outro-nested-else/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-outro-nested-else/main.svelte diff --git a/test/runtime/samples/if-block-outro-unique-select-block-type/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-unique-select-block-type/Component.svelte similarity index 100% rename from test/runtime/samples/if-block-outro-unique-select-block-type/Component.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-outro-unique-select-block-type/Component.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-outro-unique-select-block-type/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-unique-select-block-type/_config.js new file mode 100644 index 000000000000..31537478e6bf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-unique-select-block-type/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      +
      + ` +}); diff --git a/test/runtime/samples/if-block-outro-unique-select-block-type/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-outro-unique-select-block-type/main.svelte similarity index 100% rename from test/runtime/samples/if-block-outro-unique-select-block-type/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-outro-unique-select-block-type/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-dynamic-contents/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-dynamic-contents/_config.js new file mode 100644 index 000000000000..bd4a66ad57b7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-dynamic-contents/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: 42 }; + }, + + html: '

      42

      ', + + test({ assert, component, target }) { + component.foo = 43; + assert.htmlEqual(target.innerHTML, '

      43

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-dynamic-contents/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-dynamic-contents/main.svelte new file mode 100644 index 000000000000..57484f252f51 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-dynamic-contents/main.svelte @@ -0,0 +1,9 @@ + + +{#if show()} +

      {foo}

      +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/EEE.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/EEE.svelte new file mode 100644 index 000000000000..6132a64bc708 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/EEE.svelte @@ -0,0 +1 @@ +eee \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/RRR.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/RRR.svelte new file mode 100644 index 000000000000..724237324909 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/RRR.svelte @@ -0,0 +1 @@ +rrr \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/_config.js new file mode 100644 index 000000000000..af9782e1073b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'eee' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/main.svelte new file mode 100644 index 000000000000..d23cb6bcf2c0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else-and-outros/main.svelte @@ -0,0 +1,10 @@ + + +{#if "Eva".startsWith('E')} + +{:else} + +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else/_config.js new file mode 100644 index 000000000000..af9782e1073b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'eee' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else/main.svelte new file mode 100644 index 000000000000..cd76a8351037 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-else/main.svelte @@ -0,0 +1,5 @@ +{#if "Eva".startsWith('E')} + eee +{:else} + rrr +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-elseif-else-and-outros/RRR.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-elseif-else-and-outros/RRR.svelte new file mode 100644 index 000000000000..724237324909 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-elseif-else-and-outros/RRR.svelte @@ -0,0 +1 @@ +rrr \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-elseif-else-and-outros/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-elseif-else-and-outros/_config.js new file mode 100644 index 000000000000..af9782e1073b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-elseif-else-and-outros/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'eee' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-elseif-else-and-outros/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-elseif-else-and-outros/main.svelte new file mode 100644 index 000000000000..b60885722e55 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-static-with-elseif-else-and-outros/main.svelte @@ -0,0 +1,13 @@ + + +{#if "Eva".startsWith('E')} + eee +{:else if x} + def +{:else} + +{/if} diff --git a/test/runtime/samples/if-block-widget/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-widget/Widget.svelte similarity index 100% rename from test/runtime/samples/if-block-widget/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-widget/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block-widget/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block-widget/_config.js new file mode 100644 index 000000000000..0300270e2daf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block-widget/_config.js @@ -0,0 +1,35 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { visible: true }; + }, + + html: ` + before +

      Widget

      + after + `, + + test({ assert, component, target }) { + component.visible = false; + assert.htmlEqual( + target.innerHTML, + ` + before + + after + ` + ); + + component.visible = true; + assert.htmlEqual( + target.innerHTML, + ` + before +

      Widget

      + after + ` + ); + } +}); diff --git a/test/runtime/samples/if-block-widget/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block-widget/main.svelte similarity index 100% rename from test/runtime/samples/if-block-widget/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block-widget/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-block/_config.js new file mode 100644 index 000000000000..bb020c8dff80 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-block/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { visible: true }; + }, + + html: '

      i am visible

      ', + + test({ assert, component, target }) { + component.visible = false; + assert.htmlEqual(target.innerHTML, ''); + component.visible = true; + assert.htmlEqual(target.innerHTML, '

      i am visible

      '); + } +}); diff --git a/test/runtime/samples/if-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-block/main.svelte similarity index 100% rename from test/runtime/samples/if-block/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-block/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/if-in-keyed-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/if-in-keyed-each/_config.js new file mode 100644 index 000000000000..cd09ef002eaf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/if-in-keyed-each/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + items: [ + { id: 1, name: 'one' }, + { id: 2, name: 'two' } + ] + }; + }, + + html: ` +
        +
      • one
      • +
      • two
      • +
      + ` +}); diff --git a/test/runtime/samples/if-in-keyed-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/if-in-keyed-each/main.svelte similarity index 100% rename from test/runtime/samples/if-in-keyed-each/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/if-in-keyed-each/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute-compound/_config.js b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute-compound/_config.js new file mode 100644 index 000000000000..9574d9c02c8e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute-compound/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; +import counter from './counter.js'; + +export default test({ + get props() { + return { x: 1, y: 2 }; + }, + + html: ` +

      1

      +

      + `, + + test({ assert, component }) { + counter.count = 0; + + component.x = 3; + assert.equal(counter.count, 0); + + component.x = 4; + component.y = 5; + assert.equal(counter.count, 1); + + component.x = 5; + component.y = 5; + assert.equal(counter.count, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute-compound/counter.js b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute-compound/counter.js new file mode 100644 index 000000000000..f0fc271f84e9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute-compound/counter.js @@ -0,0 +1,3 @@ +export default { + count: 0 +}; diff --git a/test/runtime/samples/ignore-unchanged-attribute-compound/main.svelte b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute-compound/main.svelte similarity index 100% rename from test/runtime/samples/ignore-unchanged-attribute-compound/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute-compound/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute/_config.js b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute/_config.js new file mode 100644 index 000000000000..3a1850373162 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; +import counter from './counter.js'; + +export default test({ + // TODO worth it to fix? arguably it's correct to always call the function, or rather it's undefined behavior as you shouldn't rely on render side effects + // to fix it we would need to create many more signals (computeds) for this, or introduce some kind of dirty bitmask + get props() { + return { x: 1, y: 2 }; + }, + + html: ` +

      1

      +

      + `, + + test({ assert, component }) { + counter.count = 0; + + component.x = 3; + assert.equal(counter.count, 0); + + component.x = 4; + component.y = 5; + assert.equal(counter.count, 1); + + component.x = 5; + component.y = 5; + assert.equal(counter.count, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute/counter.js b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute/counter.js new file mode 100644 index 000000000000..f0fc271f84e9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute/counter.js @@ -0,0 +1,3 @@ +export default { + count: 0 +}; diff --git a/test/runtime/samples/ignore-unchanged-attribute/main.svelte b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute/main.svelte similarity index 100% rename from test/runtime/samples/ignore-unchanged-attribute/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-attribute/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-raw/_config.js b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-raw/_config.js new file mode 100644 index 000000000000..e096780b6d07 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-raw/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; +import counter from './counter.js'; + +export default test({ + get props() { + return { x: 1, y: 2 }; + }, + + html: ` +

      1

      +

      2

      + `, + + test({ assert, component }) { + counter.count = 0; + + component.x = 3; + assert.equal(counter.count, 0); + + component.x = 4; + component.y = 5; + assert.equal(counter.count, 1); + + component.x = 5; + component.y = 5; + assert.equal(counter.count, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-raw/counter.js b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-raw/counter.js new file mode 100644 index 000000000000..f0fc271f84e9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-raw/counter.js @@ -0,0 +1,3 @@ +export default { + count: 0 +}; diff --git a/test/runtime/samples/ignore-unchanged-raw/main.svelte b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-raw/main.svelte similarity index 100% rename from test/runtime/samples/ignore-unchanged-raw/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-raw/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-tag/_config.js new file mode 100644 index 000000000000..e096780b6d07 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-tag/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; +import counter from './counter.js'; + +export default test({ + get props() { + return { x: 1, y: 2 }; + }, + + html: ` +

      1

      +

      2

      + `, + + test({ assert, component }) { + counter.count = 0; + + component.x = 3; + assert.equal(counter.count, 0); + + component.x = 4; + component.y = 5; + assert.equal(counter.count, 1); + + component.x = 5; + component.y = 5; + assert.equal(counter.count, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-tag/counter.js b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-tag/counter.js new file mode 100644 index 000000000000..f0fc271f84e9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-tag/counter.js @@ -0,0 +1,3 @@ +export default { + count: 0 +}; diff --git a/test/runtime/samples/ignore-unchanged-tag/main.svelte b/packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-tag/main.svelte similarity index 100% rename from test/runtime/samples/ignore-unchanged-tag/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/ignore-unchanged-tag/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-before-after-update/ImmutableTodo.svelte b/packages/svelte/tests/runtime-legacy/samples/immutable-before-after-update/ImmutableTodo.svelte new file mode 100644 index 000000000000..7b88730481c4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-before-after-update/ImmutableTodo.svelte @@ -0,0 +1,24 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-before-after-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/immutable-before-after-update/_config.js new file mode 100644 index 000000000000..ed4b49ec1bda --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-before-after-update/_config.js @@ -0,0 +1,45 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + immutable: true, + + html: ' ', + + test({ assert, target, logs }) { + assert.deepEqual(logs, [ + '$:1', + 'beforeUpdate:1', + '$:2', + 'beforeUpdate:2', + '$:3', + 'beforeUpdate:3', + 'afterUpdate:1', + 'afterUpdate:2', + 'afterUpdate:3', + 'beforeUpdate:1', + 'beforeUpdate:2', + 'beforeUpdate:3' + ]); + + const [button1, button2] = target.querySelectorAll('button'); + + logs.length = 0; + button1.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ' ' + ); + assert.deepEqual(logs, ['$:1', 'beforeUpdate:1', 'afterUpdate:1']); + + logs.length = 0; + button2.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ' ' + ); + assert.deepEqual(logs, ['$:2', 'beforeUpdate:2', 'afterUpdate:2']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-before-after-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/immutable-before-after-update/main.svelte new file mode 100644 index 000000000000..d24abfd113f8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-before-after-update/main.svelte @@ -0,0 +1,26 @@ + + +{#each todos as todo} + toggle(todo.id)} /> +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-each-equals/_config.js b/packages/svelte/tests/runtime-legacy/samples/immutable-each-equals/_config.js new file mode 100644 index 000000000000..90fcbfe2c0c7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-each-equals/_config.js @@ -0,0 +1,16 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + immutable: true, + + test({ assert, target }) { + const btn = target.querySelector('button'); + + flushSync(() => { + btn?.click(); + }); + + assert.htmlEqual(target.innerHTML, `
      • test !!!
      `); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-each-equals/main.svelte b/packages/svelte/tests/runtime-legacy/samples/immutable-each-equals/main.svelte new file mode 100644 index 000000000000..0694d3f34f42 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-each-equals/main.svelte @@ -0,0 +1,17 @@ + + + + +
        + {#each items as item (item.id)} +
      • {item.value}
      • + {/each} +
      + diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-mutate-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/immutable-mutate-object/_config.js new file mode 100644 index 000000000000..e3cbd48d755e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-mutate-object/_config.js @@ -0,0 +1,20 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + immutable: true, + + html: ' ', + + test({ assert, target }) { + const [button1, button2] = target.querySelectorAll('button'); + + button1.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, ' '); + + button2.click(); + flushSync(); + assert.htmlEqual(target.innerHTML, ' '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-mutate-object/main.svelte b/packages/svelte/tests/runtime-legacy/samples/immutable-mutate-object/main.svelte new file mode 100644 index 000000000000..8a086c5db3fb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-mutate-object/main.svelte @@ -0,0 +1,6 @@ + + + + diff --git a/test/runtime/samples/immutable-nested/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/immutable-nested/Nested.svelte similarity index 100% rename from test/runtime/samples/immutable-nested/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/immutable-nested/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/immutable-nested/_config.js new file mode 100644 index 000000000000..a2184d21bc6f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-nested/_config.js @@ -0,0 +1,44 @@ +import { test } from '../../test'; + +export default test({ + immutable: true, + + html: ` +
      +

      Called 1 times.

      +

      baz true

      +
      + `, + + ssrHtml: ` +
      +

      Called 0 times.

      +

      baz false

      +
      `, + + test({ assert, component, target }) { + const nested = component.nested; + + assert.htmlEqual( + target.innerHTML, + ` +
      +

      Called 1 times.

      +

      baz true

      +
      + ` + ); + + // eslint-disable-next-line no-self-assign + nested.foo = nested.foo; + assert.htmlEqual( + target.innerHTML, + ` +
      +

      Called 1 times.

      +

      baz true

      +
      + ` + ); + } +}); diff --git a/test/runtime/samples/immutable-nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/immutable-nested/main.svelte similarity index 100% rename from test/runtime/samples/immutable-nested/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/immutable-nested/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-option/_config.js b/packages/svelte/tests/runtime-legacy/samples/immutable-option/_config.js new file mode 100644 index 000000000000..0ad5b4152de9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-option/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + immutable: true, + + html: '

      Called 1 times.

      ', + + test({ assert, component, target }) { + // eslint-disable-next-line no-self-assign + component.foo = component.foo; + assert.htmlEqual(target.innerHTML, '

      Called 1 times.

      '); + } +}); diff --git a/test/runtime/samples/immutable-option/main.svelte b/packages/svelte/tests/runtime-legacy/samples/immutable-option/main.svelte similarity index 100% rename from test/runtime/samples/immutable-option/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/immutable-option/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-svelte-meta-false/_config.js b/packages/svelte/tests/runtime-legacy/samples/immutable-svelte-meta-false/_config.js new file mode 100644 index 000000000000..53840a6b4a32 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-svelte-meta-false/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + immutable: true, + + html: '

      Called 1 times.

      ', + + test({ assert, component, target }) { + // eslint-disable-next-line no-self-assign + component.foo = component.foo; + assert.htmlEqual(target.innerHTML, '

      Called 2 times.

      '); + } +}); diff --git a/test/runtime/samples/immutable-svelte-meta-false/main.svelte b/packages/svelte/tests/runtime-legacy/samples/immutable-svelte-meta-false/main.svelte similarity index 100% rename from test/runtime/samples/immutable-svelte-meta-false/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/immutable-svelte-meta-false/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/immutable-svelte-meta/_config.js b/packages/svelte/tests/runtime-legacy/samples/immutable-svelte-meta/_config.js new file mode 100644 index 000000000000..6578cb392a2b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/immutable-svelte-meta/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: '

      Called 1 times.

      ', + + test({ assert, component, target }) { + // eslint-disable-next-line no-self-assign + component.foo = component.foo; + assert.htmlEqual(target.innerHTML, '

      Called 1 times.

      '); + } +}); diff --git a/test/runtime/samples/immutable-svelte-meta/main.svelte b/packages/svelte/tests/runtime-legacy/samples/immutable-svelte-meta/main.svelte similarity index 100% rename from test/runtime/samples/immutable-svelte-meta/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/immutable-svelte-meta/main.svelte diff --git a/test/runtime/samples/imported-renamed-components/ComponentOne.svelte b/packages/svelte/tests/runtime-legacy/samples/imported-renamed-components/ComponentOne.svelte similarity index 100% rename from test/runtime/samples/imported-renamed-components/ComponentOne.svelte rename to packages/svelte/tests/runtime-legacy/samples/imported-renamed-components/ComponentOne.svelte diff --git a/test/runtime/samples/imported-renamed-components/ComponentTwo.svelte b/packages/svelte/tests/runtime-legacy/samples/imported-renamed-components/ComponentTwo.svelte similarity index 100% rename from test/runtime/samples/imported-renamed-components/ComponentTwo.svelte rename to packages/svelte/tests/runtime-legacy/samples/imported-renamed-components/ComponentTwo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/imported-renamed-components/_config.js b/packages/svelte/tests/runtime-legacy/samples/imported-renamed-components/_config.js new file mode 100644 index 000000000000..a6e7c802412c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/imported-renamed-components/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'OneTwo' +}); diff --git a/test/runtime/samples/imported-renamed-components/main.svelte b/packages/svelte/tests/runtime-legacy/samples/imported-renamed-components/main.svelte similarity index 100% rename from test/runtime/samples/imported-renamed-components/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/imported-renamed-components/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/initial-state-assign/_config.js b/packages/svelte/tests/runtime-legacy/samples/initial-state-assign/_config.js new file mode 100644 index 000000000000..443eda8fa1c8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/initial-state-assign/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { bar: 'bar' }; + }, + html: ` + "foo" + "bar" + ` +}); diff --git a/test/runtime/samples/initial-state-assign/main.svelte b/packages/svelte/tests/runtime-legacy/samples/initial-state-assign/main.svelte similarity index 100% rename from test/runtime/samples/initial-state-assign/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/initial-state-assign/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-expressions-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-expressions-3/_config.js new file mode 100644 index 000000000000..c229f97e0709 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-expressions-3/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `
      + import { sprites } from './sprites.js' + + +
      + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-expressions-3/sprites.js b/packages/svelte/tests/runtime-legacy/samples/inline-expressions-3/sprites.js new file mode 100644 index 000000000000..055fdbd59a64 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-expressions-3/sprites.js @@ -0,0 +1,3 @@ +export const sprites = { + a: 'test' +}; diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-expressions-subtree/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-expressions-subtree/_config.js new file mode 100644 index 000000000000..17c573a5105c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-expressions-subtree/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'A\n
      B
      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-expressions-subtree/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-expressions-subtree/main.svelte new file mode 100644 index 000000000000..555dc8af23a1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-expressions-subtree/main.svelte @@ -0,0 +1,4 @@ + 'red')()}>A +
      + 'red')()}>B +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-expressions/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-expressions/_config.js new file mode 100644 index 000000000000..697fe1cc7129 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-expressions/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 1, b: 2 }; + }, + html: '

      1 + 2 = 3

      ', + test({ assert, component, target }) { + component.a = 3; + component.b = 4; + assert.htmlEqual(target.innerHTML, '

      3 + 4 = 7

      '); + } +}); diff --git a/test/runtime/samples/inline-expressions/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-expressions/main.svelte similarity index 100% rename from test/runtime/samples/inline-expressions/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/inline-expressions/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-become-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-become-undefined/_config.js new file mode 100644 index 000000000000..4e2d400fd505 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-become-undefined/_config.js @@ -0,0 +1,15 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const div = target.querySelector('div'); + ok(div); + const click = new window.MouseEvent('click', { bubbles: true }); + + assert.htmlEqual(target.innerHTML, '
      '); + div.dispatchEvent(click); + flushSync(); + assert.htmlEqual(target.innerHTML, '
      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-become-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-become-undefined/main.svelte new file mode 100644 index 000000000000..ee38934fc740 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-become-undefined/main.svelte @@ -0,0 +1,9 @@ + + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr-merged/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr-merged/_config.js new file mode 100644 index 000000000000..e7af775da3d7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr-merged/_config.js @@ -0,0 +1,15 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      + `, + + test({ assert, target, window }) { + const p = target.querySelector('p'); + ok(p); + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(255, 0, 0)'); + assert.equal(styles.height, '40px'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr-merged/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr-merged/main.svelte new file mode 100644 index 000000000000..59684f09de69 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr-merged/main.svelte @@ -0,0 +1,5 @@ + + +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr/_config.js new file mode 100644 index 000000000000..b667e43a7175 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr/_config.js @@ -0,0 +1,16 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      + `, + + test({ assert, target, window }) { + const p = target.querySelector('p'); + ok(p); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(255, 0, 0)'); + assert.equal(styles.height, '40px'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr/main.svelte new file mode 100644 index 000000000000..841c665cac9c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-and-style-attr/main.svelte @@ -0,0 +1,5 @@ + + +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-css-vars/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-css-vars/_config.js new file mode 100644 index 000000000000..be9f9a192ca2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-css-vars/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: '

      ', + + test({ assert, component, target }) { + component.myColor = 'blue'; + + assert.htmlEqual(target.innerHTML, '

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-css-vars/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-css-vars/main.svelte new file mode 100644 index 000000000000..45e43cb49927 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-css-vars/main.svelte @@ -0,0 +1,5 @@ + + +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-dynamic/_config.js new file mode 100644 index 000000000000..7a662121e10a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-dynamic/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      + `, + + test({ assert, component, target }) { + component.myColor = 'blue'; + assert.htmlEqual(target.innerHTML, '

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-dynamic/main.svelte new file mode 100644 index 000000000000..49891c0009b0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-dynamic/main.svelte @@ -0,0 +1,5 @@ + + +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-escape/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-escape/_config.js new file mode 100644 index 000000000000..2de8bd020f11 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-escape/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      + `, + + test({ assert, component, target }) { + component.attack = '" onload="alert(\'uhoh2\')" data-nothing="not important'; + assert.htmlEqual( + target.innerHTML, + ` +
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-escape/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-escape/main.svelte new file mode 100644 index 000000000000..bbffdf704e0f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-escape/main.svelte @@ -0,0 +1,5 @@ + + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-falsy-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-falsy-value/_config.js new file mode 100644 index 000000000000..bb7f4518d9ee --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-falsy-value/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      +

      +

      +

      +

      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-falsy-value/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-falsy-value/main.svelte new file mode 100644 index 000000000000..bed3e7c0b5a5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-falsy-value/main.svelte @@ -0,0 +1,5 @@ +

      +

      +

      +

      +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-multiple/_config.js new file mode 100644 index 000000000000..1d89642756cc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-multiple/_config.js @@ -0,0 +1,30 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      + `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + ok(p); + + let styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(255, 0, 0)'); + + component.myColor = 'pink'; + component.width = '100vh'; + component.absolute = true; + component.bold = false; + + styles = window.getComputedStyle(p); + assert.htmlEqual( + target.innerHTML, + '

      ' + ); + assert.equal(styles.color, 'rgb(255, 192, 203)'); + assert.equal(styles.width, '100vh'); + assert.equal(styles.fontWeight, '100'); + assert.equal(styles.position, 'absolute'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-multiple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-multiple/main.svelte new file mode 100644 index 000000000000..06f03206d54d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-multiple/main.svelte @@ -0,0 +1,13 @@ + + +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-null-style/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-null-style/_config.js new file mode 100644 index 000000000000..f83df4439f51 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-null-style/_config.js @@ -0,0 +1,7 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      red

      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-null-style/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-null-style/main.svelte new file mode 100644 index 000000000000..8a87a707061b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-null-style/main.svelte @@ -0,0 +1 @@ +

      red

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand-declaration-only/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand-declaration-only/_config.js new file mode 100644 index 000000000000..c62f2ad3b64e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand-declaration-only/_config.js @@ -0,0 +1,33 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

      +

      + + `, + + test({ assert, target, window }) { + const [p1, p2] = target.querySelectorAll('p'); + + assert.equal(window.getComputedStyle(p1).color, 'rgb(255, 0, 0)'); + assert.equal(window.getComputedStyle(p2).color, 'rgb(255, 0, 0)'); + + const btn = target.querySelector('button'); + btn?.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      +

      + + ` + ); + + assert.equal(window.getComputedStyle(p1).color, 'rgb(0, 128, 0)'); + assert.equal(window.getComputedStyle(p2).color, 'rgb(0, 128, 0)'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand-declaration-only/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand-declaration-only/main.svelte new file mode 100644 index 000000000000..9213a5bb2e64 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand-declaration-only/main.svelte @@ -0,0 +1,15 @@ + + +

      + +{#each [1] as _} +

      +{/each} + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand/_config.js new file mode 100644 index 000000000000..f657bc59e7f5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      +

      + `, + + test({ assert, component, target, window }) { + const [p1, p2] = target.querySelectorAll('p'); + + assert.equal(window.getComputedStyle(p1).color, 'rgb(255, 0, 0)'); + assert.equal(window.getComputedStyle(p2).color, 'rgb(255, 0, 0)'); + + component.color = 'blue'; + assert.htmlEqual( + target.innerHTML, + ` +

      +

      + ` + ); + + assert.equal(window.getComputedStyle(p1).color, 'rgb(0, 0, 255)'); + assert.equal(window.getComputedStyle(p2).color, 'rgb(0, 0, 255)'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand/main.svelte new file mode 100644 index 000000000000..b02fe3ac6d1e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-shorthand/main.svelte @@ -0,0 +1,9 @@ + + +

      + +{#each [1] as _} +

      +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr-empty/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr-empty/_config.js new file mode 100644 index 000000000000..04c9868ac378 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr-empty/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr-empty/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr-empty/main.svelte new file mode 100644 index 000000000000..c2d5cb4d3f27 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr-empty/main.svelte @@ -0,0 +1,11 @@ + + +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr/_config.js new file mode 100644 index 000000000000..626a1199008b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr/_config.js @@ -0,0 +1,40 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      + `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + ok(p); + + let styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(0, 128, 0)'); + + component.color = null; + assert.htmlEqual(target.innerHTML, '

      '); + styles = window.getComputedStyle(p); + assert.equal(styles.color, ''); + + component.spread = { style: 'color: yellow; padding: 30px;' }; + + assert.htmlEqual(target.innerHTML, '

      '); + styles = window.getComputedStyle(p); + assert.equal(styles.color, ''); + assert.equal(styles.padding, '30px'); + + component.spread = {}; + component.style = 'color: blue; background-color: green;'; + assert.htmlEqual(target.innerHTML, '

      '); + styles = window.getComputedStyle(p); + assert.equal(styles.color, ''); + assert.equal(styles.backgroundColor, 'rgb(0, 128, 0)'); + + component.color = 'purple'; + assert.htmlEqual(target.innerHTML, '

      '); + styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(128, 0, 128)'); + assert.equal(styles.backgroundColor, 'rgb(0, 128, 0)'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr/main.svelte new file mode 100644 index 000000000000..a9696df67573 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-and-attr/main.svelte @@ -0,0 +1,11 @@ + + +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-dynamic/_config.js new file mode 100644 index 000000000000..87c725ee05b1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-dynamic/_config.js @@ -0,0 +1,33 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      + `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + ok(p); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(0, 0, 255)'); + assert.equal(styles.width, '65px'); + assert.equal(p.id, 'my-id'); + + component.color = 'red'; + + assert.htmlEqual(target.innerHTML, '

      '); + + component.obj = { style: 'height: 72px;' }; + + assert.htmlEqual(target.innerHTML, '

      '); + + component.obj = { style: 'border-radius: 2px; color: orange' }; + + assert.htmlEqual(target.innerHTML, '

      '); + + component.obj = {}; + + assert.htmlEqual(target.innerHTML, '

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-dynamic/main.svelte new file mode 100644 index 000000000000..5ebb1be29f2d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread-dynamic/main.svelte @@ -0,0 +1,5 @@ + +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread/_config.js new file mode 100644 index 000000000000..8d2626f70b8a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread/_config.js @@ -0,0 +1,17 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      + `, + + test({ assert, target, window }) { + const p = target.querySelector('p'); + ok(p); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(0, 0, 255)'); + assert.equal(styles.width, '65px'); + assert.equal(p.id, 'my-id'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread/main.svelte new file mode 100644 index 000000000000..3d36d017a5d7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-spread/main.svelte @@ -0,0 +1 @@ +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable-kebab-case/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable-kebab-case/_config.js new file mode 100644 index 000000000000..299547464461 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable-kebab-case/_config.js @@ -0,0 +1,25 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      + `, + + test({ assert, target, window }) { + const div = target.querySelector('div'); + ok(div); + const styles = window.getComputedStyle(div); + + assert.equal( + // @ts-ignore + styles['background-image'], + 'url(https://raw.githubusercontent.com/sveltejs/branding/master/svelte-vertical.png)' + ); + assert.equal(styles.getPropertyValue('--css-variable'), 'rgba(0, 0, 0, 1)'); + + assert.htmlEqual( + target.innerHTML, + '
      ' + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable-kebab-case/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable-kebab-case/main.svelte new file mode 100644 index 000000000000..dbfba08d6480 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable-kebab-case/main.svelte @@ -0,0 +1,11 @@ + + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable/_config.js new file mode 100644 index 000000000000..b8b76f020255 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable/_config.js @@ -0,0 +1,26 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      + `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + ok(p); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(0, 128, 0)'); + assert.equal(styles.transform, 'translateX(45px)'); + assert.equal(styles.border, '100px solid pink'); + + component.translate_x = '100%'; + component.border_width = 20; + component.border_color = 'yellow'; + + assert.htmlEqual( + target.innerHTML, + '

      ' + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable/main.svelte new file mode 100644 index 000000000000..7ee5bfa18eb0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string-variable/main.svelte @@ -0,0 +1,7 @@ + + +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string/_config.js new file mode 100644 index 000000000000..0b3c3b53774e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string/_config.js @@ -0,0 +1,15 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      + `, + + test({ assert, target, window }) { + const p = target.querySelector('p'); + ok(p); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(255, 0, 0)'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string/main.svelte new file mode 100644 index 000000000000..11a9abb45de9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-string/main.svelte @@ -0,0 +1 @@ +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-update-object-property/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-update-object-property/_config.js new file mode 100644 index 000000000000..0b0b332ee1a9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-update-object-property/_config.js @@ -0,0 +1,24 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      + `, + + test({ assert, target, window, component }) { + const p = target.querySelector('p'); + ok(p); + const styles = window.getComputedStyle(p); + assert.equal(styles.backgroundColor, 'rgb(0, 128, 0)'); + assert.equal(styles.fontSize, '12px'); + + { + component.modify = true; + const p = target.querySelector('p'); + ok(p); + const styles = window.getComputedStyle(p); + assert.equal(styles.backgroundColor, 'rgb(0, 128, 0)'); + assert.equal(styles.fontSize, '50px'); + } + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-update-object-property/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-update-object-property/main.svelte new file mode 100644 index 000000000000..71afdcb077d4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive-update-object-property/main.svelte @@ -0,0 +1,12 @@ + + +

      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive/_config.js new file mode 100644 index 000000000000..3c8300e385ae --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive/_config.js @@ -0,0 +1,17 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      +

      +
      + `, + + test({ assert, target, window }) { + const p = target.querySelector('p'); + ok(p); + + const styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(255, 0, 0)'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-directive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive/main.svelte new file mode 100644 index 000000000000..f8d161ab66ee --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-directive/main.svelte @@ -0,0 +1,7 @@ + + +
      +

      +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-important/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-important/_config.js new file mode 100644 index 000000000000..e29afb537c8d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-important/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      red

      + `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + ok(p); + + let styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(255, 0, 0)'); + assert.equal(styles.fontSize, '20px'); + + component.color = 'green'; + + styles = window.getComputedStyle(p); + assert.equal(styles.color, 'rgb(0, 128, 0)'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-important/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-important/main.svelte new file mode 100644 index 000000000000..d55804c35e75 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-important/main.svelte @@ -0,0 +1,12 @@ + + +

      {color}

      + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-optimisation-bailout/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style-optimisation-bailout/_config.js new file mode 100644 index 000000000000..e9965b2b1e26 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-optimisation-bailout/_config.js @@ -0,0 +1,23 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      color: red;

      + `, + + test({ assert, component, target, window }) { + const p = target.querySelector('p'); + ok(p); + + let styles = window.getComputedStyle(p); + assert.equal(styles.opacity, '0.5'); + assert.equal(styles.color, 'rgb(255, 0, 0)'); + + component.styles = 'font-size: 20px'; + + styles = window.getComputedStyle(p); + assert.equal(styles.opacity, '0.5'); + assert.equal(styles.color, ''); + assert.equal(styles.fontSize, '20px'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style-optimisation-bailout/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style-optimisation-bailout/main.svelte new file mode 100644 index 000000000000..e07adaa1c9d8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style-optimisation-bailout/main.svelte @@ -0,0 +1,5 @@ + + +

      {styles}

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style/_config.js b/packages/svelte/tests/runtime-legacy/samples/inline-style/_config.js new file mode 100644 index 000000000000..b8910cd8f61c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style/_config.js @@ -0,0 +1,15 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      + `, + + test({ assert, target, window }) { + const div = target.querySelector('div'); + ok(div); + + const styles = window.getComputedStyle(div); + assert.equal(styles.color, 'rgb(255, 0, 0)'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/inline-style/main.svelte b/packages/svelte/tests/runtime-legacy/samples/inline-style/main.svelte new file mode 100644 index 000000000000..0f37a04c994f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/inline-style/main.svelte @@ -0,0 +1 @@ +
      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/innerhtml-interpolated-literal/_config.js b/packages/svelte/tests/runtime-legacy/samples/innerhtml-interpolated-literal/_config.js new file mode 100644 index 000000000000..f0a9ebdf5374 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/innerhtml-interpolated-literal/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      + +
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/innerhtml-interpolated-literal/main.svelte b/packages/svelte/tests/runtime-legacy/samples/innerhtml-interpolated-literal/main.svelte new file mode 100644 index 000000000000..8a3c9272a5b6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/innerhtml-interpolated-literal/main.svelte @@ -0,0 +1,3 @@ +
      + +
      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/innerhtml-with-comments/_config.js b/packages/svelte/tests/runtime-legacy/samples/innerhtml-with-comments/_config.js new file mode 100644 index 000000000000..efc9a74f32b2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/innerhtml-with-comments/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + Style: + Bootstrap. + + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/innerhtml-with-comments/main.svelte b/packages/svelte/tests/runtime-legacy/samples/innerhtml-with-comments/main.svelte new file mode 100644 index 000000000000..e00f7550726d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/innerhtml-with-comments/main.svelte @@ -0,0 +1,5 @@ + + Style: + + Bootstrap. + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/input-list/_config.js b/packages/svelte/tests/runtime-legacy/samples/input-list/_config.js new file mode 100644 index 000000000000..fe6a29207d4c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/input-list/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + + ` +}); diff --git a/test/runtime/samples/input-list/main.svelte b/packages/svelte/tests/runtime-legacy/samples/input-list/main.svelte similarity index 100% rename from test/runtime/samples/input-list/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/input-list/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-auto-subscription-self-assignment/_config.js b/packages/svelte/tests/runtime-legacy/samples/instrumentation-auto-subscription-self-assignment/_config.js new file mode 100644 index 000000000000..9ffebe0e9576 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-auto-subscription-self-assignment/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + html: '[]', + + test({ assert, component, target }) { + flushSync(() => component.go()); + assert.htmlEqual(target.innerHTML, '[42]'); + } +}); diff --git a/test/runtime/samples/instrumentation-auto-subscription-self-assignment/main.svelte b/packages/svelte/tests/runtime-legacy/samples/instrumentation-auto-subscription-self-assignment/main.svelte similarity index 100% rename from test/runtime/samples/instrumentation-auto-subscription-self-assignment/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/instrumentation-auto-subscription-self-assignment/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-destructuring/_config.js b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-destructuring/_config.js new file mode 100644 index 000000000000..4d111c60a819 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-destructuring/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + +

      x: 0

      + `, + + test({ assert, target, window }) { + const buttons = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(click); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + + + +

      x: 1

      + ` + ); + + buttons[1].dispatchEvent(click); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + + + +

      x: 2

      + ` + ); + } +}); diff --git a/test/runtime/samples/instrumentation-script-destructuring/main.svelte b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-destructuring/main.svelte similarity index 100% rename from test/runtime/samples/instrumentation-script-destructuring/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/instrumentation-script-destructuring/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-loop-scope/_config.js b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-loop-scope/_config.js new file mode 100644 index 000000000000..14717a95ecd9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-loop-scope/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +

      x: 0

      + `, + + test({ assert, target, window }) { + const buttons = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      x: 42

      + ` + ); + } +}); diff --git a/test/runtime/samples/instrumentation-script-loop-scope/main.svelte b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-loop-scope/main.svelte similarity index 100% rename from test/runtime/samples/instrumentation-script-loop-scope/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/instrumentation-script-loop-scope/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-multiple-assignments/_config.js b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-multiple-assignments/_config.js new file mode 100644 index 000000000000..cd13cc73acf6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-multiple-assignments/_config.js @@ -0,0 +1,34 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: 0, bar: 0 }; + }, + + html: ` + +

      foo: 0

      +

      bar: 0

      + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + button?.dispatchEvent(click); + flushSync(); + + assert.equal(component.foo, 4); + assert.equal(component.bar, 2); + + assert.htmlEqual( + target.innerHTML, + ` + +

      foo: 4

      +

      bar: 2

      + ` + ); + } +}); diff --git a/test/runtime/samples/instrumentation-script-multiple-assignments/main.svelte b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-multiple-assignments/main.svelte similarity index 100% rename from test/runtime/samples/instrumentation-script-multiple-assignments/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/instrumentation-script-multiple-assignments/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-update/_config.js new file mode 100644 index 000000000000..a7673f2573fb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-update/_config.js @@ -0,0 +1,24 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +

      x: 0

      + `, + + test({ assert, target, window }) { + const buttons = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(click); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + +

      x: 1

      + ` + ); + } +}); diff --git a/test/runtime/samples/instrumentation-script-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/instrumentation-script-update/main.svelte similarity index 100% rename from test/runtime/samples/instrumentation-script-update/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/instrumentation-script-update/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-destructuring/_config.js b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-destructuring/_config.js new file mode 100644 index 000000000000..b2c0e8083145 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-destructuring/_config.js @@ -0,0 +1,42 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + + + +

      x: 0

      + `, + + async test({ assert, target, window }) { + const buttons = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

      x: 1

      + ` + ); + + buttons[1].dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + + +

      x: 2

      + ` + ); + } +}); diff --git a/test/runtime/samples/instrumentation-template-destructuring/main.svelte b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-destructuring/main.svelte similarity index 100% rename from test/runtime/samples/instrumentation-template-destructuring/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/instrumentation-template-destructuring/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-loop-scope/_config.js b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-loop-scope/_config.js new file mode 100644 index 000000000000..14717a95ecd9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-loop-scope/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +

      x: 0

      + `, + + test({ assert, target, window }) { + const buttons = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      x: 42

      + ` + ); + } +}); diff --git a/test/runtime/samples/instrumentation-template-loop-scope/main.svelte b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-loop-scope/main.svelte similarity index 100% rename from test/runtime/samples/instrumentation-template-loop-scope/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/instrumentation-template-loop-scope/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-multiple-assignments/_config.js b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-multiple-assignments/_config.js new file mode 100644 index 000000000000..cd13cc73acf6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-multiple-assignments/_config.js @@ -0,0 +1,34 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: 0, bar: 0 }; + }, + + html: ` + +

      foo: 0

      +

      bar: 0

      + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + button?.dispatchEvent(click); + flushSync(); + + assert.equal(component.foo, 4); + assert.equal(component.bar, 2); + + assert.htmlEqual( + target.innerHTML, + ` + +

      foo: 4

      +

      bar: 2

      + ` + ); + } +}); diff --git a/test/runtime/samples/instrumentation-template-multiple-assignments/main.svelte b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-multiple-assignments/main.svelte similarity index 100% rename from test/runtime/samples/instrumentation-template-multiple-assignments/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/instrumentation-template-multiple-assignments/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-update/_config.js new file mode 100644 index 000000000000..a7673f2573fb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-update/_config.js @@ -0,0 +1,24 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +

      x: 0

      + `, + + test({ assert, target, window }) { + const buttons = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(click); + flushSync(); + assert.htmlEqual( + target.innerHTML, + ` + +

      x: 1

      + ` + ); + } +}); diff --git a/test/runtime/samples/instrumentation-template-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/instrumentation-template-update/main.svelte similarity index 100% rename from test/runtime/samples/instrumentation-template-update/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/instrumentation-template-update/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-update-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/instrumentation-update-expression/_config.js new file mode 100644 index 000000000000..a3c5b2a82544 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-update-expression/_config.js @@ -0,0 +1,38 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

      0

      + + +

      0

      + + + `, + test({ assert, target, window }) { + const [foo, bar] = target.querySelectorAll('p'); + const [button1, button2, button3, button4] = target.querySelectorAll('button'); + const event = new window.MouseEvent('click', { bubbles: true }); + + button1.dispatchEvent(event); + flushSync(); + assert.equal(foo.innerHTML, '1'); + assert.equal(bar.innerHTML, '0'); + + button2.dispatchEvent(event); + flushSync(); + assert.equal(foo.innerHTML, '2'); + assert.equal(bar.innerHTML, '0'); + + button3.dispatchEvent(event); + flushSync(); + assert.equal(foo.innerHTML, '2'); + assert.equal(bar.innerHTML, '1'); + + button4.dispatchEvent(event); + flushSync(); + assert.equal(foo.innerHTML, '2'); + assert.equal(bar.innerHTML, '2'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/instrumentation-update-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/instrumentation-update-expression/main.svelte new file mode 100644 index 000000000000..0672f6330d83 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/instrumentation-update-expression/main.svelte @@ -0,0 +1,14 @@ + + +

      {foo}

      + + + + +

      {bar.bar}

      + + + diff --git a/test/runtime/samples/internal-state/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/internal-state/Foo.svelte similarity index 100% rename from test/runtime/samples/internal-state/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/internal-state/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/internal-state/_config.js b/packages/svelte/tests/runtime-legacy/samples/internal-state/_config.js new file mode 100644 index 000000000000..b5837c6a07af --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/internal-state/_config.js @@ -0,0 +1,23 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      internal: 1

      + + `, + + async test({ assert, target, window }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click'); + + await button?.dispatchEvent(click); + + assert.htmlEqual( + target.innerHTML, + ` +

      internal: 1

      + + ` + ); + } +}); diff --git a/test/runtime/samples/internal-state/main.svelte b/packages/svelte/tests/runtime-legacy/samples/internal-state/main.svelte similarity index 100% rename from test/runtime/samples/internal-state/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/internal-state/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/invalidation-in-if-condition/_config.js b/packages/svelte/tests/runtime-legacy/samples/invalidation-in-if-condition/_config.js new file mode 100644 index 000000000000..02f43929d8e2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/invalidation-in-if-condition/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const click = new window.MouseEvent('click', { bubbles: true }); + + button.dispatchEvent(click); + flushSync(); + assert.htmlEqual(target.innerHTML, ''); + + button.dispatchEvent(click); + flushSync(); + assert.htmlEqual(target.innerHTML, ''); + + button.dispatchEvent(click); + flushSync(); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/invalidation-in-if-condition/main.svelte b/packages/svelte/tests/runtime-legacy/samples/invalidation-in-if-condition/main.svelte new file mode 100644 index 000000000000..810576695ea5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/invalidation-in-if-condition/main.svelte @@ -0,0 +1,12 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/isolated-text/_config.js b/packages/svelte/tests/runtime-legacy/samples/isolated-text/_config.js new file mode 100644 index 000000000000..5f4d8baf8478 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/isolated-text/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` + before +

      after

      + ` +}); diff --git a/test/runtime/samples/isolated-text/main.svelte b/packages/svelte/tests/runtime-legacy/samples/isolated-text/main.svelte similarity index 100% rename from test/runtime/samples/isolated-text/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/isolated-text/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-2/_config.js new file mode 100644 index 000000000000..29cfa93a7ae8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-2/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +// with reactive content beside `key` +export default test({ + html: '
      00
      ', + async test({ assert, component, target }) { + const div = target.querySelector('div'); + component.reactive = 2; + assert.htmlEqual(target.innerHTML, '
      02
      '); + assert.strictEqual(div, target.querySelector('div')); + + component.value = 5; + assert.htmlEqual(target.innerHTML, '
      52
      '); + assert.notStrictEqual(div, target.querySelector('div')); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-2/main.svelte new file mode 100644 index 000000000000..466d20b10a73 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-2/main.svelte @@ -0,0 +1,8 @@ + + +{#key value} +
      {value}{reactive}
      +{/key} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-3/_config.js new file mode 100644 index 000000000000..6439834c757a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-3/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +// key is not used in the template +export default test({ + html: '
      ', + async test({ assert, component, target }) { + const div = target.querySelector('div'); + + component.value = 5; + assert.htmlEqual(target.innerHTML, '
      '); + assert.notStrictEqual(div, target.querySelector('div')); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-3/main.svelte new file mode 100644 index 000000000000..02582d3eda59 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-3/main.svelte @@ -0,0 +1,7 @@ + + +{#key value} +
      +{/key} diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-array-immutable/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-array-immutable/_config.js new file mode 100644 index 000000000000..7332896a311b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-array-immutable/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: '
      1
      ', + async test({ assert, component, target }) { + let div = target.querySelector('div'); + await component.append(2); + assert.htmlEqual(target.innerHTML, '
      1
      '); + assert.strictEqual(div, target.querySelector('div')); + + div = target.querySelector('div'); + + component.array = [3, 4]; + assert.htmlEqual(target.innerHTML, '
      3,4
      '); + assert.notStrictEqual(div, target.querySelector('div')); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-array-immutable/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-array-immutable/main.svelte new file mode 100644 index 000000000000..e666275af4c7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-array-immutable/main.svelte @@ -0,0 +1,14 @@ + + + + +{#key array} +
      {array.join(',')}
      +{/key} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-array/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-array/_config.js new file mode 100644 index 000000000000..1552c30889fe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-array/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: '
      1
      ', + async test({ assert, component, target }) { + let div = target.querySelector('div'); + await component.append(2); + assert.htmlEqual(target.innerHTML, '
      1,2
      '); + assert.notStrictEqual(div, target.querySelector('div')); + + div = target.querySelector('div'); + + component.array = [3, 4]; + assert.htmlEqual(target.innerHTML, '
      3,4
      '); + assert.notStrictEqual(div, target.querySelector('div')); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-array/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-array/main.svelte new file mode 100644 index 000000000000..5a4054b0430d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-array/main.svelte @@ -0,0 +1,12 @@ + + +{#key array} +
      {array.join(',')}
      +{/key} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/Component1.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/Component1.svelte new file mode 100644 index 000000000000..d0ea817d547f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/Component1.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/Component2.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/Component2.svelte new file mode 100644 index 000000000000..ca04744936dd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/Component2.svelte @@ -0,0 +1,12 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/_config.js new file mode 100644 index 000000000000..837d1d112bf5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/_config.js @@ -0,0 +1,28 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +/** @type {string[]} */ +let logs = []; + +export default test({ + html: '', + get props() { + return { logs }; + }, + + before_test() { + logs = []; + }, + + test({ assert, target }) { + assert.deepEqual(logs, ['mount']); + + const button = target.querySelector('button'); + + const click = new window.MouseEvent('click', { bubbles: true }); + button?.dispatchEvent(click); + flushSync(); + + assert.deepEqual(logs, ['mount', 'unmount', 'mount']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/main.svelte new file mode 100644 index 000000000000..77fde32d9ccd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-component-slot/main.svelte @@ -0,0 +1,17 @@ + + + + {#key reset} + + {/key} + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-expression-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-expression-2/_config.js new file mode 100644 index 000000000000..99fa84e2a9b3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-expression-2/_config.js @@ -0,0 +1,27 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: '
      3
      ', + test({ assert, component, target }) { + const div = target.querySelector('div'); + + component.mutate(); + flushSync(); + + assert.htmlEqual(target.innerHTML, '
      5
      '); + assert.strictEqual(div, target.querySelector('div')); + + component.reassign(); + flushSync(); + + assert.htmlEqual(target.innerHTML, '
      7
      '); + assert.strictEqual(div, target.querySelector('div')); + + component.changeKey(); + flushSync(); + + assert.htmlEqual(target.innerHTML, '
      7
      '); + assert.notStrictEqual(div, target.querySelector('div')); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-expression-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-expression-2/main.svelte new file mode 100644 index 000000000000..5525f637615f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-expression-2/main.svelte @@ -0,0 +1,17 @@ + + +{#key obj.key} +
      {obj.value}
      +{/key} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-expression/_config.js new file mode 100644 index 000000000000..feab2f9efde9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-expression/_config.js @@ -0,0 +1,23 @@ +import { test } from '../../test'; + +export default test({ + html: '
      000
      ', + async test({ assert, component, target }) { + let div = target.querySelector('div'); + component.value = 2; + assert.htmlEqual(target.innerHTML, '
      200
      '); + assert.notStrictEqual(div, target.querySelector('div')); + + div = target.querySelector('div'); + + component.anotherValue = 5; + assert.htmlEqual(target.innerHTML, '
      250
      '); + assert.notStrictEqual(div, target.querySelector('div')); + + div = target.querySelector('div'); + + component.thirdValue = 9; + assert.htmlEqual(target.innerHTML, '
      259
      '); + assert.strictEqual(div, target.querySelector('div')); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-expression/main.svelte new file mode 100644 index 000000000000..dd752e8b8fdf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-expression/main.svelte @@ -0,0 +1,9 @@ + + +{#key value + anotherValue} +
      {value}{anotherValue}{thirdValue}
      +{/key} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-post-hydrate/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-post-hydrate/_config.js new file mode 100644 index 000000000000..7a3d9a2a9853 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-post-hydrate/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      +
      item 1something
      +
      item 2something
      +
      item 3something
      +
      + `, + test({ assert, component, target }) { + component.sortById = false; + assert.htmlEqual( + target.innerHTML, + ` +
      +
      item 3something
      +
      item 2something
      +
      item 1something
      +
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-post-hydrate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-post-hydrate/main.svelte new file mode 100644 index 000000000000..8ea316a0d7aa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-post-hydrate/main.svelte @@ -0,0 +1,23 @@ + + +
      + {#each items as item (item.id)} +
      + {#if item.name} + + {item.name} + + {/if} + something +
      + {/each} +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-static-if/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-static-if/_config.js new file mode 100644 index 000000000000..baa6ac3a7e86 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-static-if/_config.js @@ -0,0 +1,28 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
      +
      Second
      +
      + + `, + async test({ assert, target, window }) { + const button = target.querySelector('button'); + + button?.dispatchEvent(new window.Event('click', { bubbles: true })); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      +
      First
      +
      Second
      +
      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-static-if/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-static-if/main.svelte new file mode 100644 index 000000000000..cbacb77674de --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-static-if/main.svelte @@ -0,0 +1,17 @@ + + +
      + {#key slide} + {#if num} +
      First
      + {/if} + {/key} +
      Second
      +
      + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-static/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-static/_config.js new file mode 100644 index 000000000000..3e981da14721 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-static/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: '
      00
      ', + async test({ assert, component, target }) { + const div = target.querySelector('div'); + component.anotherValue = 2; + assert.htmlEqual(target.innerHTML, '
      02
      '); + assert.strictEqual(div, target.querySelector('div')); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-static/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-static/main.svelte new file mode 100644 index 000000000000..e4ee6b5d7146 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-static/main.svelte @@ -0,0 +1,8 @@ + + +{#key value} +
      {value}{anotherValue}
      +{/key} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-transition-global/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-transition-global/_config.js new file mode 100644 index 000000000000..1aa70d7deba3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-transition-global/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from '../../../../src/index-client'; +import { test } from '../../test'; + +export default test({ + html: '
      0
      ', + async test({ assert, component, target, raf }) { + component.value = 2; + + const [button] = /** @type {NodeListOf} */ ( + target.querySelectorAll('button') + ); + + raf.tick(0); + + assert.htmlEqual(target.innerHTML, '
      2
      '); + + flushSync(() => { + button.click(); + }); + + raf.tick(0); + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-transition-global/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-transition-global/main.svelte new file mode 100644 index 000000000000..408719763ddf --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-transition-global/main.svelte @@ -0,0 +1,22 @@ + + +{#if toggle} + {#key value} +
      {value}
      + {/key} +{/if} + + diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-transition-local/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-transition-local/_config.js new file mode 100644 index 000000000000..800afeb636ae --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-transition-local/_config.js @@ -0,0 +1,41 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: false, y: 1 }; + }, + + test({ assert, component, target, raf }) { + component.x = true; + + let div = /** @type {HTMLDivElement & { foo: number }} */ (target.querySelector('div')); + raf.tick(0); + assert.equal(div.foo, undefined); + + // play both in and out transition when changed with `{#key}` + component.y = 2; + assert.htmlEqual(target.innerHTML, '
      '); + const [leaving, incoming] = /** @type {NodeListOf} */ ( + target.querySelectorAll('div') + ); + + raf.tick(50); + assert.equal(leaving.foo, 0.5); + assert.equal(incoming.foo, 0.5); + + raf.tick(100); + assert.htmlEqual(target.innerHTML, '
      '); + assert.equal(leaving.foo, 0); + assert.equal(incoming.foo, 1); + + // do not play out transition when removed by `{#if}` + component.x = false; + assert.htmlEqual(target.innerHTML, ''); + + // do not play in transition when added back with `{#if}` + component.x = true; + assert.htmlEqual(target.innerHTML, '
      '); + div = /** @type {HTMLDivElement & { foo: number }} */ (target.querySelector('div')); + assert.equal(div.foo, undefined); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-transition-local/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-transition-local/main.svelte new file mode 100644 index 000000000000..05ed75b7e14b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-transition-local/main.svelte @@ -0,0 +1,19 @@ + + +{#if x} + {#key y} +
      + {/key} +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-transition/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block-transition/_config.js new file mode 100644 index 000000000000..b27ca641cb02 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-transition/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; + +export default test({ + html: '
      0
      ', + async test({ assert, component, target, raf }) { + component.value = 2; + + const [div1, div2] = /** @type {NodeListOf} */ ( + target.querySelectorAll('div') + ); + + assert.htmlEqual(div1.outerHTML, '
      0
      '); + assert.htmlEqual(div2.outerHTML, '
      2
      '); + + raf.tick(0); + + assert.equal(div1.foo, 1); + assert.equal(div1.oof, 0); + + assert.equal(div2.foo, 0); + assert.equal(div2.oof, 1); + + raf.tick(200); + + assert.htmlEqual(target.innerHTML, '
      2
      '); + assert.equal(div2, target.querySelector('div')); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block-transition/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block-transition/main.svelte new file mode 100644 index 000000000000..d7fb6ec02471 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block-transition/main.svelte @@ -0,0 +1,17 @@ + + +{#key value} +
      {value}
      +{/key} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block/_config.js b/packages/svelte/tests/runtime-legacy/samples/key-block/_config.js new file mode 100644 index 000000000000..cca8753e6da4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + html: '
      0
      0
      ', + async test({ assert, component, target }) { + let [div1, div2] = target.querySelectorAll('div'); + + component.value = 5; + assert.htmlEqual(target.innerHTML, '
      5
      0
      '); + assert.notStrictEqual(div1, target.querySelectorAll('div')[0]); + assert.strictEqual(div2, target.querySelectorAll('div')[1]); + [div1, div2] = target.querySelectorAll('div'); + + component.reactive = 10; + assert.htmlEqual(target.innerHTML, '
      5
      10
      '); + assert.strictEqual(div1, target.querySelectorAll('div')[0]); + assert.strictEqual(div2, target.querySelectorAll('div')[1]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/key-block/main.svelte b/packages/svelte/tests/runtime-legacy/samples/key-block/main.svelte new file mode 100644 index 000000000000..ac3c340770b4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/key-block/main.svelte @@ -0,0 +1,10 @@ + + +{#key value} +
      {value}
      +{/key} + +
      {reactive}
      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-bind-read-index/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/keyed-each-bind-read-index/Component.svelte new file mode 100644 index 000000000000..988c2b645752 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-bind-read-index/Component.svelte @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-bind-read-index/_config.js b/packages/svelte/tests/runtime-legacy/samples/keyed-each-bind-read-index/_config.js new file mode 100644 index 000000000000..8b5db4df4090 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-bind-read-index/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, target, logs }) { + const p = target.querySelector('p'); + assert.equal(p?.innerHTML, '1'); + assert.deepEqual(logs, [0]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-bind-read-index/main.svelte b/packages/svelte/tests/runtime-legacy/samples/keyed-each-bind-read-index/main.svelte new file mode 100644 index 000000000000..384722f5aa72 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-bind-read-index/main.svelte @@ -0,0 +1,10 @@ + + +{#each items as item, idx(item)} + +{/each} + +

      {items}

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique-update/_config.js b/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique-update/_config.js new file mode 100644 index 000000000000..6fa6f63b0a8e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique-update/_config.js @@ -0,0 +1,16 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + test({ assert, target }) { + let button = target.querySelector('button'); + + button?.click(); + + assert.throws(flushSync, /each_key_duplicate/); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique-update/main.svelte b/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique-update/main.svelte new file mode 100644 index 000000000000..0e9a377487a6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique-update/main.svelte @@ -0,0 +1,21 @@ + + + + +
        + {#each data as d (d.join(""))} +
      • {d}
      • + {/each} +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique/_config.js b/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique/_config.js new file mode 100644 index 000000000000..6e64245d861e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + error: 'each_key_duplicate\nKeyed each block has duplicate key `1` at indexes 0 and 3' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique/main.svelte b/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique/main.svelte new file mode 100644 index 000000000000..870e7beaa1c9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-dev-unique/main.svelte @@ -0,0 +1,7 @@ + + +{#each array as item (item)} + {item} +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same-2/_config.js new file mode 100644 index 000000000000..8627d28b2370 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same-2/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '
      0
      1
      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same-2/main.svelte new file mode 100644 index 000000000000..c21812be4a2e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same-2/main.svelte @@ -0,0 +1,3 @@ +{#each ["a", "b"] as result, i (i)} +
      {i}
      +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same/_config.js b/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same/_config.js new file mode 100644 index 000000000000..a1d9fe1b2654 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '1' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same/main.svelte b/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same/main.svelte new file mode 100644 index 000000000000..7a6f0e08fa07 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/keyed-each-index-same/main.svelte @@ -0,0 +1,3 @@ +{#each [1] as item, i (i)} + {item} +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-next-tick/_config.js b/packages/svelte/tests/runtime-legacy/samples/lifecycle-next-tick/_config.js new file mode 100644 index 000000000000..ee2dafbccb30 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-next-tick/_config.js @@ -0,0 +1,28 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, component, target, window }) { + const buttons = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(click); + await tick(); + assert.deepEqual(component.snapshots, ['before 0', 'after 1']); + + buttons[0].dispatchEvent(click); + await tick(); + assert.deepEqual(component.snapshots, ['before 0', 'after 1', 'before 1', 'after 2']); + + buttons[1].dispatchEvent(click); + await tick(); + assert.deepEqual(component.snapshots, [ + 'before 0', + 'after 1', + 'before 1', + 'after 2', + 'before 2', + 'after 2' + ]); + } +}); diff --git a/test/runtime/samples/lifecycle-next-tick/main.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-next-tick/main.svelte similarity index 100% rename from test/runtime/samples/lifecycle-next-tick/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/lifecycle-next-tick/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-onmount-infinite-loop/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-onmount-infinite-loop/Child.svelte new file mode 100644 index 000000000000..ef16875b6448 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-onmount-infinite-loop/Child.svelte @@ -0,0 +1 @@ +Child diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-onmount-infinite-loop/_config.js b/packages/svelte/tests/runtime-legacy/samples/lifecycle-onmount-infinite-loop/_config.js new file mode 100644 index 000000000000..8d29b5ba73d5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-onmount-infinite-loop/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component }) { + const { count } = component; + assert.deepEqual(count, 1); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-onmount-infinite-loop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-onmount-infinite-loop/main.svelte new file mode 100644 index 000000000000..65fc684a0339 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-onmount-infinite-loop/main.svelte @@ -0,0 +1,16 @@ + + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate/_config.js b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate/_config.js new file mode 100644 index 000000000000..2380c5454e1c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + before_test() { + const context = { + fillStyle: '', + fillRect() {} + }; + // @ts-ignore + HTMLCanvasElement.prototype.getContext = () => { + return context; + }; + }, + async test({ assert, target, component }) { + const canvas = /** @type {HTMLCanvasElement} */ (target.querySelector('canvas')); + const ctx = canvas.getContext('2d'); + assert.equal(ctx?.fillStyle, 'hsl(0, 100%, 40%)'); + + canvas.click(); + flushSync(); + assert.equal(ctx?.fillStyle, 'hsl(10, 100%, 40%)'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate/main.svelte new file mode 100644 index 000000000000..b22eef015c6c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate/main.svelte @@ -0,0 +1,45 @@ + + + hue += 10} /> +
      +

      click the canvas

      + + {#if show_hue} +

      hue is {hue}

      + {/if} +
      + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate2/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate2/Child.svelte new file mode 100644 index 000000000000..50fb461cb3e4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate2/Child.svelte @@ -0,0 +1,24 @@ + + +

      a: {a}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate2/_config.js b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate2/_config.js new file mode 100644 index 000000000000..1309ef8a2435 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate2/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { test, ok } from '../../test'; + +export default test({ + test({ assert, target, logs }) { + const [button1, button2] = target.querySelectorAll('button'); + ok(button1); + ok(button2); + + button1.click(); + flushSync(); + + button2.click(); + flushSync(); + + assert.deepEqual(logs, [ + 'before', + 'before 0, 0', + 'after', + 'after 0, 0', + 'before', + 'before 1, 0', + 'after', + 'after 1, 0', + 'before', + 'before 1, 1', + 'after', + 'after 1, 1' + ]); + + assert.htmlEqual( + target.innerHTML, + ` + + +

      a: 1

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate2/main.svelte new file mode 100644 index 000000000000..5b517c80ff7e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-afterUpdate2/main.svelte @@ -0,0 +1,10 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-beforeUpdate/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-beforeUpdate/Child.svelte new file mode 100644 index 000000000000..0c43f7cc2927 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-beforeUpdate/Child.svelte @@ -0,0 +1,6 @@ + + +

      welcome, dan

      diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-beforeUpdate/_config.js b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-beforeUpdate/_config.js new file mode 100644 index 000000000000..98eb7716fb5c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-beforeUpdate/_config.js @@ -0,0 +1,28 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + async test({ assert, target, logs }) { + const input = /** @type {HTMLInputElement} */ (target.querySelector('input')); + assert.equal(input?.value, 'rich'); + + assert.deepEqual(logs, []); + + const inputEvent = new window.InputEvent('input'); + input.value = 'dan'; + await input.dispatchEvent(inputEvent); + + flushSync(); + + assert.deepEqual(logs, ['name in child: dan']); + + logs.length = 0; + + input.value = 'da'; + await input.dispatchEvent(inputEvent); + + flushSync(); + + assert.deepEqual(logs, []); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-beforeUpdate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-beforeUpdate/main.svelte new file mode 100644 index 000000000000..d63945bbc724 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-beforeUpdate/main.svelte @@ -0,0 +1,18 @@ + + + + +{#if allowed} + +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/Item.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/Item.svelte new file mode 100644 index 000000000000..b2e6cd046c8e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/Item.svelte @@ -0,0 +1,28 @@ + + +
    • + {logRender()} +
    • diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/_config.js b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/_config.js new file mode 100644 index 000000000000..99f9681c4ba5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/_config.js @@ -0,0 +1,55 @@ +import { test } from '../../test'; +import order from './order.js'; + +let n = 0; + +export default test({ + get props() { + return { + n + }; + }, + before_test() { + order.length = 0; + n = 0; + }, + test({ assert, compileOptions, component }) { + assert.deepEqual(order, [ + 'parent: beforeUpdate 0', + '1: beforeUpdate 0', + '1: render 0', + '2: beforeUpdate 0', + '2: render 0', + '3: beforeUpdate 0', + '3: render 0', + 'parent: render 0', + '1: onMount 0', + '1: afterUpdate 0', + '2: onMount 0', + '2: afterUpdate 0', + '3: onMount 0', + '3: afterUpdate 0', + 'parent: onMount 0', + 'parent: afterUpdate 0' + ]); + + order.length = 0; + + component.n += 1; + + assert.deepEqual(order, [ + 'parent: beforeUpdate 1', + '1: beforeUpdate 1', + '1: render 1', + '2: beforeUpdate 1', + '2: render 1', + '3: beforeUpdate 1', + '3: render 1', + 'parent: render 1', + '1: afterUpdate 1', + '2: afterUpdate 1', + '3: afterUpdate 1', + 'parent: afterUpdate 1' + ]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/main.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/main.svelte new file mode 100644 index 000000000000..b05b1476fdcc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/main.svelte @@ -0,0 +1,33 @@ + + +{logRender()} +
        + {#each [1,2,3] as index} + + {/each} +
      + + diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/order.js b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/order.js new file mode 100644 index 000000000000..f412aeefb13d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order-for-children/order.js @@ -0,0 +1,2 @@ +/** @type {string[]} */ +export default []; diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order/_config.js b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order/_config.js new file mode 100644 index 000000000000..cc471b6a7e02 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; +import order from './order.js'; + +export default test({ + before_test() { + order.length = 0; + }, + test({ assert }) { + assert.deepEqual(order, ['beforeUpdate', 'render', 'onMount', 'afterUpdate']); + } +}); diff --git a/test/runtime/samples/lifecycle-render-order/main.svelte b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order/main.svelte similarity index 100% rename from test/runtime/samples/lifecycle-render-order/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order/order.js b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order/order.js new file mode 100644 index 000000000000..d6d1738de67e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/lifecycle-render-order/order.js @@ -0,0 +1 @@ +export default []; diff --git a/packages/svelte/tests/runtime-legacy/samples/mixed-let-export/_config.js b/packages/svelte/tests/runtime-legacy/samples/mixed-let-export/_config.js new file mode 100644 index 000000000000..1df4d41c9eb3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/mixed-let-export/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 42 }; + }, + + html: ` + 42 + ` +}); diff --git a/test/runtime/samples/mixed-let-export/main.svelte b/packages/svelte/tests/runtime-legacy/samples/mixed-let-export/main.svelte similarity index 100% rename from test/runtime/samples/mixed-let-export/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/mixed-let-export/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-bind/_config.js b/packages/svelte/tests/runtime-legacy/samples/module-context-bind/_config.js new file mode 100644 index 000000000000..8cce427bbc46 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-bind/_config.js @@ -0,0 +1,6 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], + html: '
      object
      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-bind/main.svelte b/packages/svelte/tests/runtime-legacy/samples/module-context-bind/main.svelte new file mode 100644 index 000000000000..1580102bd8fe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-bind/main.svelte @@ -0,0 +1,11 @@ + + + + +
      {typeof bar}
      diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-export-referenced-in-template/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/module-context-export-referenced-in-template/Foo.svelte new file mode 100644 index 000000000000..4750e6253b7a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-export-referenced-in-template/Foo.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-export-referenced-in-template/_config.js b/packages/svelte/tests/runtime-legacy/samples/module-context-export-referenced-in-template/_config.js new file mode 100644 index 000000000000..9e74b75e2780 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-export-referenced-in-template/_config.js @@ -0,0 +1,6 @@ +import { test } from '../../test'; + +// test itself might look weird, but it tests that the compilation output doesn't contain a dangling `export;` due to false hoisting +export default test({ + html: '

      (42)(99)

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-export-referenced-in-template/main.svelte b/packages/svelte/tests/runtime-legacy/samples/module-context-export-referenced-in-template/main.svelte new file mode 100644 index 000000000000..01d6bb51d285 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-export-referenced-in-template/main.svelte @@ -0,0 +1,6 @@ + + +

      ({foo()})({bar})

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-export/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/module-context-export/Foo.svelte new file mode 100644 index 000000000000..86f110f48180 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-export/Foo.svelte @@ -0,0 +1,7 @@ + + diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-export/_config.js b/packages/svelte/tests/runtime-legacy/samples/module-context-export/_config.js new file mode 100644 index 000000000000..65dbd6043d21 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-export/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      (42)(99)

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-export/main.svelte b/packages/svelte/tests/runtime-legacy/samples/module-context-export/main.svelte new file mode 100644 index 000000000000..60c130ca2f5e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-export/main.svelte @@ -0,0 +1,6 @@ + + +

      ({foo})({bar})

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-with-instance-script/_config.js b/packages/svelte/tests/runtime-legacy/samples/module-context-with-instance-script/_config.js new file mode 100644 index 000000000000..65dbd6043d21 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-with-instance-script/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      (42)(99)

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context-with-instance-script/main.svelte b/packages/svelte/tests/runtime-legacy/samples/module-context-with-instance-script/main.svelte new file mode 100644 index 000000000000..1db102a4484b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context-with-instance-script/main.svelte @@ -0,0 +1,9 @@ + + + + +

      ({foo})({bar})

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context/_config.js b/packages/svelte/tests/runtime-legacy/samples/module-context/_config.js new file mode 100644 index 000000000000..daca0d42618a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      42

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/module-context/main.svelte b/packages/svelte/tests/runtime-legacy/samples/module-context/main.svelte new file mode 100644 index 000000000000..2e1ae663fb22 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/module-context/main.svelte @@ -0,0 +1,5 @@ + + +

      {foo}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/mutation-correct-return-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/mutation-correct-return-value/_config.js new file mode 100644 index 000000000000..c07346d55d0a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/mutation-correct-return-value/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client'], + test({ assert, logs }) { + assert.deepEqual(logs, [true]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/mutation-correct-return-value/main.svelte b/packages/svelte/tests/runtime-legacy/samples/mutation-correct-return-value/main.svelte new file mode 100644 index 000000000000..2ad07e1253c9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/mutation-correct-return-value/main.svelte @@ -0,0 +1,4 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/mutation-tracking-across-sibling-scopes/_config.js b/packages/svelte/tests/runtime-legacy/samples/mutation-tracking-across-sibling-scopes/_config.js new file mode 100644 index 000000000000..fbbc749b6d22 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/mutation-tracking-across-sibling-scopes/_config.js @@ -0,0 +1,18 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, component, target }) { + assert.htmlEqual(component.div.innerHTML, '
      +
      -
      '); + + const event = new window.Event('change'); + const input = target.querySelector('input'); + ok(input); + + input.checked = false; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual(component.div.innerHTML, '
      -
      -
      '); + } +}); diff --git a/test/runtime/samples/mutation-tracking-across-sibling-scopes/main.svelte b/packages/svelte/tests/runtime-legacy/samples/mutation-tracking-across-sibling-scopes/main.svelte similarity index 100% rename from test/runtime/samples/mutation-tracking-across-sibling-scopes/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/mutation-tracking-across-sibling-scopes/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/names-deconflicted-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/names-deconflicted-nested/_config.js new file mode 100644 index 000000000000..60ba057f4600 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/names-deconflicted-nested/_config.js @@ -0,0 +1,23 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + array: [ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0] + ] + }; + }, + + html: ` +
      + [ 0, 0 ][ 0, 1 ][ 0, 2 ] +
      + [ 1, 0 ][ 1, 1 ][ 1, 2 ] +
      + [ 2, 0 ][ 2, 1 ][ 2, 2 ] +
      + ` +}); diff --git a/test/runtime/samples/names-deconflicted-nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/names-deconflicted-nested/main.svelte similarity index 100% rename from test/runtime/samples/names-deconflicted-nested/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/names-deconflicted-nested/main.svelte diff --git a/test/runtime/samples/names-deconflicted/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/names-deconflicted/Widget.svelte similarity index 100% rename from test/runtime/samples/names-deconflicted/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/names-deconflicted/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/names-deconflicted/_config.js b/packages/svelte/tests/runtime-legacy/samples/names-deconflicted/_config.js new file mode 100644 index 000000000000..6c17ded013a4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/names-deconflicted/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: '

      1: foo

      2: bar

      3: baz

      ', + + test({ assert, component, target }) { + component.widgets = [{ name: 'bish' }, { name: 'bosh' }]; + + assert.htmlEqual(target.innerHTML, '

      1: bish

      2: bosh

      '); + } +}); diff --git a/test/runtime/samples/names-deconflicted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/names-deconflicted/main.svelte similarity index 100% rename from test/runtime/samples/names-deconflicted/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/names-deconflicted/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/namespace-html/_config.js b/packages/svelte/tests/runtime-legacy/samples/namespace-html/_config.js new file mode 100644 index 000000000000..3be9f0e92539 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/namespace-html/_config.js @@ -0,0 +1,30 @@ +import { ok, test } from '../../test'; + +// Checks that the template function is correct when there's a svg before a div +export default test({ + html: ` + + hellooooo + + + + + + +
      hi
      + `, + + test({ assert, target }) { + const svg = target.querySelector('svg'); + ok(svg); + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + + const math = target.querySelector('math'); + ok(math); + assert.equal(math.namespaceURI, 'http://www.w3.org/1998/Math/MathML'); + + const div = target.querySelector('div'); + ok(div); + assert.equal(div.namespaceURI, 'http://www.w3.org/1999/xhtml'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/namespace-html/main.svelte b/packages/svelte/tests/runtime-legacy/samples/namespace-html/main.svelte new file mode 100644 index 000000000000..a020c61533e6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/namespace-html/main.svelte @@ -0,0 +1,9 @@ + + hellooooo + + + + + + +
      hi
      diff --git a/packages/svelte/tests/runtime-legacy/samples/nbsp-div/_config.js b/packages/svelte/tests/runtime-legacy/samples/nbsp-div/_config.js new file mode 100644 index 000000000000..4d378e51cf55 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/nbsp-div/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + html: `
       hello
      +
       hello  
      +
       hello   hello
      `, + + test({ assert, target }) { + const divList = target.querySelectorAll('div'); + assert.equal(divList[0].textContent?.charCodeAt(0), 160); + assert.equal(divList[1].textContent?.charCodeAt(0), 160); + assert.equal(divList[1].textContent?.charCodeAt(6), 160); + assert.equal(divList[1].textContent?.charCodeAt(7), 160); + assert.equal(divList[2].textContent?.charCodeAt(0), 160); + assert.equal(divList[2].textContent?.charCodeAt(6), 160); + assert.equal(divList[2].textContent?.charCodeAt(7), 32); //normal space + assert.equal(divList[2].textContent?.charCodeAt(8), 160); + } +}); diff --git a/test/runtime/samples/nbsp-div/main.svelte b/packages/svelte/tests/runtime-legacy/samples/nbsp-div/main.svelte similarity index 100% rename from test/runtime/samples/nbsp-div/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/nbsp-div/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/nbsp/_config.js b/packages/svelte/tests/runtime-legacy/samples/nbsp/_config.js new file mode 100644 index 000000000000..dea12fced385 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/nbsp/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: ' ', + + test({ assert, target }) { + const text = target.querySelector('span')?.textContent; + assert.equal(text?.charCodeAt(0), 160); + } +}); diff --git a/test/runtime/samples/nbsp/main.svelte b/packages/svelte/tests/runtime-legacy/samples/nbsp/main.svelte similarity index 100% rename from test/runtime/samples/nbsp/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/nbsp/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment-2/_config.js new file mode 100644 index 000000000000..a8451373c470 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment-2/_config.js @@ -0,0 +1,46 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

      1

      +

      2

      +

      3

      +

      4

      +

      5

      +

      6

      + +

      Bag'ol stores

      +

      6

      +

      +

      + + + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + const clickEvent = new window.Event('click', { bubbles: true }); + button?.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      7

      +

      8

      +

      9

      +

      10

      +

      11

      +

      12

      + +

      Bag'ol stores

      +

      12

      +

      14

      +

      15

      + + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment-2/main.svelte new file mode 100644 index 000000000000..5dc3d50cc238 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment-2/main.svelte @@ -0,0 +1,42 @@ + + +

      {firstNonStore}

      +

      {secondNonStore}

      +

      {thirdNonStore}

      +

      {$firstStore}

      +

      {$secondStore}

      +

      {$thirdStore}

      + +

      Bag'ol stores

      +

      {get($bagOlStores[5])}

      +

      {get($bagOlStores[6])}

      +

      {get($bagOlStores[7])}

      + + diff --git a/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment/_config.js b/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment/_config.js new file mode 100644 index 000000000000..79b68dd9317e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment/_config.js @@ -0,0 +1,46 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

      1

      +

      2

      +

      3

      +

      4

      +

      5

      +

      6

      + +

      Bag'ol stores

      +

      4

      +

      5

      +

      6

      + + + `, + + test({ assert, target, window }) { + const button = target.querySelector('button'); + const clickEvent = new window.Event('click', { bubbles: true }); + button?.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      7

      +

      8

      +

      9

      +

      10

      +

      11

      +

      12

      + +

      Bag'ol stores

      +

      14

      +

      13

      +

      12

      + + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment/main.svelte b/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment/main.svelte new file mode 100644 index 000000000000..57d0f46fafb3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/nested-destructure-assignment/main.svelte @@ -0,0 +1,48 @@ + + +

      {firstNonStore}

      +

      {secondNonStore}

      +

      {thirdNonStore}

      +

      {$firstStore}

      +

      {$secondStore}

      +

      {$thirdStore}

      + +

      Bag'ol stores

      +

      {get($bagOlStores.firstStore)}

      +

      {get($bagOlStores.secondStore)}

      +

      {get($bagOlStores.thirdStore)}

      + + diff --git a/packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-each/_config.js new file mode 100644 index 000000000000..324d3bcd51e3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-each/_config.js @@ -0,0 +1,46 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + visible: false, + rows: [1, 2, 3], + cols: ['a', 'b', 'c'] + }; + }, + + html: '', + + compileOptions: { + dev: true + }, + + test({ assert, component, target, raf }) { + component.visible = true; + assert.htmlEqual( + target.innerHTML, + ` +
      +
      1, a
      +
      1, b
      +
      1, c
      +
      +
      +
      2, a
      +
      2, b
      +
      2, c
      +
      +
      +
      3, a
      +
      3, b
      +
      3, c
      +
      + ` + ); + + component.visible = false; + raf.tick(0); + raf.tick(100); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/nested-transition-detach-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-each/main.svelte similarity index 100% rename from test/runtime/samples/nested-transition-detach-each/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-each/main.svelte diff --git a/test/runtime/samples/nested-transition-detach-if-false/Folder.svelte b/packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-if-false/Folder.svelte similarity index 100% rename from test/runtime/samples/nested-transition-detach-if-false/Folder.svelte rename to packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-if-false/Folder.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-if-false/_config.js b/packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-if-false/_config.js new file mode 100644 index 000000000000..bf5abfcb29e2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-if-false/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
    • + a +
        +
      • + a/b +
          +
        • a/b/c
        • +
        +
      • +
      +
    • + `, + + test({ assert, component, target }) { + component.folder.open = false; + assert.htmlEqual( + target.innerHTML, + ` +
    • + a +
    • + ` + ); + } +}); diff --git a/test/runtime/samples/nested-transition-detach-if-false/main.svelte b/packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-if-false/main.svelte similarity index 100% rename from test/runtime/samples/nested-transition-detach-if-false/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/nested-transition-detach-if-false/main.svelte diff --git a/test/runtime/samples/nested-transition-if-block-not-remounted/Span.svelte b/packages/svelte/tests/runtime-legacy/samples/nested-transition-if-block-not-remounted/Span.svelte similarity index 100% rename from test/runtime/samples/nested-transition-if-block-not-remounted/Span.svelte rename to packages/svelte/tests/runtime-legacy/samples/nested-transition-if-block-not-remounted/Span.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/nested-transition-if-block-not-remounted/_config.js b/packages/svelte/tests/runtime-legacy/samples/nested-transition-if-block-not-remounted/_config.js new file mode 100644 index 000000000000..cfe6e321b53d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/nested-transition-if-block-not-remounted/_config.js @@ -0,0 +1,25 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { x: true, value: 'one' }; + }, + + html: ` +
      + + x +
      + `, + + test({ component, target }) { + const div = target.querySelector('div'); + ok(div); + + div.appendChild = div.insertBefore = () => { + throw new Error('DOM was mutated'); + }; + + component.value = 'two'; + } +}); diff --git a/test/runtime/samples/nested-transition-if-block-not-remounted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/nested-transition-if-block-not-remounted/main.svelte similarity index 100% rename from test/runtime/samples/nested-transition-if-block-not-remounted/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/nested-transition-if-block-not-remounted/main.svelte diff --git a/test/runtime/samples/observable-auto-subscribe/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/observable-auto-subscribe/Nested.svelte similarity index 100% rename from test/runtime/samples/observable-auto-subscribe/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/observable-auto-subscribe/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/observable-auto-subscribe/_config.js b/packages/svelte/tests/runtime-legacy/samples/observable-auto-subscribe/_config.js new file mode 100644 index 000000000000..3494b9818b3f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/observable-auto-subscribe/_config.js @@ -0,0 +1,55 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +/** @type {string | number} */ +let value = 'initial'; + +/** @type {Array<((value: any) => void)>} */ +let subscribers = []; +const observable = { + /** @param {(value: any) => void} fn */ + subscribe: (fn) => { + subscribers.push(fn); + + fn(value); + + return { + unsubscribe: () => { + const i = subscribers.indexOf(fn); + subscribers.splice(i, 1); + } + }; + } +}; + +export default test({ + before_test() { + value = 'initial'; + subscribers = []; + }, + + get props() { + return { observable, visible: false }; + }, + + html: '', + + async test({ assert, component, target }) { + assert.equal(subscribers.length, 0); + + component.visible = true; + + assert.equal(subscribers.length, 1); + assert.htmlEqual(target.innerHTML, '

      value: initial

      '); + value = 42; + subscribers.forEach((fn) => { + fn(value); + }); + flushSync(); + assert.htmlEqual(target.innerHTML, '

      value: 42

      '); + + component.visible = false; + + assert.equal(subscribers.length, 0); + } +}); diff --git a/test/runtime/samples/observable-auto-subscribe/main.svelte b/packages/svelte/tests/runtime-legacy/samples/observable-auto-subscribe/main.svelte similarity index 100% rename from test/runtime/samples/observable-auto-subscribe/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/observable-auto-subscribe/main.svelte diff --git a/test/runtime/samples/ondestroy-before-cleanup/Top.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-before-cleanup/Top.svelte similarity index 100% rename from test/runtime/samples/ondestroy-before-cleanup/Top.svelte rename to packages/svelte/tests/runtime-legacy/samples/ondestroy-before-cleanup/Top.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-before-cleanup/_config.js b/packages/svelte/tests/runtime-legacy/samples/ondestroy-before-cleanup/_config.js new file mode 100644 index 000000000000..3ae386072ebe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-before-cleanup/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; +import container from './container.js'; + +export default test({ + test({ assert, component, target }) { + container.div = null; + + const div = target.querySelector('div'); + + component.visible = false; + assert.equal(container.div, div); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-before-cleanup/container.js b/packages/svelte/tests/runtime-legacy/samples/ondestroy-before-cleanup/container.js new file mode 100644 index 000000000000..5a41b50de504 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-before-cleanup/container.js @@ -0,0 +1,3 @@ +export default { + div: null +}; diff --git a/test/runtime/samples/ondestroy-before-cleanup/main.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-before-cleanup/main.svelte similarity index 100% rename from test/runtime/samples/ondestroy-before-cleanup/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/ondestroy-before-cleanup/main.svelte diff --git a/test/runtime/samples/ondestroy-deep/A.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/A.svelte similarity index 100% rename from test/runtime/samples/ondestroy-deep/A.svelte rename to packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/A.svelte diff --git a/test/runtime/samples/ondestroy-deep/B.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/B.svelte similarity index 100% rename from test/runtime/samples/ondestroy-deep/B.svelte rename to packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/B.svelte diff --git a/test/runtime/samples/ondestroy-deep/C.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/C.svelte similarity index 100% rename from test/runtime/samples/ondestroy-deep/C.svelte rename to packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/C.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/_config.js b/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/_config.js new file mode 100644 index 000000000000..96e388a7e114 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; +import { destroyed, reset } from './destroyed.js'; + +export default test({ + before_test() { + reset(); + }, + + test({ assert, component }) { + component.visible = false; + assert.deepEqual(destroyed, ['C', 'B', 'A']); + }, + + test_ssr({ assert }) { + assert.deepEqual(destroyed, ['C', 'B', 'A']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/destroyed.js b/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/destroyed.js new file mode 100644 index 000000000000..1afebed3bdc6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/destroyed.js @@ -0,0 +1,4 @@ +/** @type {string[]} */ +export const destroyed = []; + +export const reset = () => (destroyed.length = 0); diff --git a/test/runtime/samples/ondestroy-deep/main.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/main.svelte similarity index 100% rename from test/runtime/samples/ondestroy-deep/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/ondestroy-deep/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-2/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-2/Component.svelte new file mode 100644 index 000000000000..73347c4d7ff1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-2/Component.svelte @@ -0,0 +1,11 @@ + + +{my_prop.foo} diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-2/_config.js new file mode 100644 index 000000000000..81005cf73760 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-2/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + async test({ assert, target, logs }) { + const [btn1] = target.querySelectorAll('button'); + + flushSync(() => { + btn1.click(); + }); + + assert.deepEqual(logs, ['bar']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-2/main.svelte new file mode 100644 index 000000000000..f38b37fb7f7c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-2/main.svelte @@ -0,0 +1,15 @@ + + + + +{#if value !== undefined} + +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-3/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-3/Component.svelte new file mode 100644 index 000000000000..5bfb7771289d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-3/Component.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-3/_config.js new file mode 100644 index 000000000000..0eb68310cbb6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-3/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + async test({ target }) { + const [btn1] = target.querySelectorAll('button'); + + btn1.click(); + flushSync(); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-3/main.svelte new file mode 100644 index 000000000000..9c72d2c48ac1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access-3/main.svelte @@ -0,0 +1,16 @@ + + +{#if state} + {@const attributes = { title: state.title }} + +{/if} + diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access/Component.svelte new file mode 100644 index 000000000000..761f303c2e0c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access/Component.svelte @@ -0,0 +1,12 @@ + + +

      {count}

      + + diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access/_config.js b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access/_config.js new file mode 100644 index 000000000000..2ffb7e653f15 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access/_config.js @@ -0,0 +1,68 @@ +import { test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + async test({ assert, target, logs }) { + const [btn1, btn2, btn3] = target.querySelectorAll('button'); + let ps = [...target.querySelectorAll('p')]; + + for (const p of ps) { + assert.equal(p.innerHTML, '0'); + } + + flushSync(() => { + btn1.click(); + }); + + // prop update normally if we are not unmounting + for (const p of ps) { + assert.equal(p.innerHTML, '1'); + } + + flushSync(() => { + btn3.click(); + }); + + // binding still works and update the value correctly + for (const p of ps) { + assert.equal(p.innerHTML, '0'); + } + + flushSync(() => { + btn1.click(); + }); + + flushSync(() => { + btn1.click(); + }); + + console.warn(logs); + + // the five components guarded by `count < 2` unmount and log + assert.deepEqual(logs, [1, true, 1, true, 1, true, 1, true, 1, true]); + + flushSync(() => { + btn2.click(); + }); + + // the three components guarded by `show` unmount and log + assert.deepEqual(logs, [ + 1, + true, + 1, + true, + 1, + true, + 1, + true, + 1, + true, + 2, + true, + 2, + true, + 2, + true + ]); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access/main.svelte b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access/main.svelte new file mode 100644 index 000000000000..73a7501e9db2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/ondestroy-prop-access/main.svelte @@ -0,0 +1,41 @@ + + + + + + +{#if count < 2} + +{/if} + + +{#if count < 2} + +{/if} + + +{#if count < 2} + +{/if} + + +{#if show} + +{/if} + + + + + + + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/onmount-async/_config.js b/packages/svelte/tests/runtime-legacy/samples/onmount-async/_config.js new file mode 100644 index 000000000000..f47bee71df87 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/onmount-async/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/test/runtime/samples/onmount-async/main.svelte b/packages/svelte/tests/runtime-legacy/samples/onmount-async/main.svelte similarity index 100% rename from test/runtime/samples/onmount-async/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/onmount-async/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/onmount-external/_config.js b/packages/svelte/tests/runtime-legacy/samples/onmount-external/_config.js new file mode 100644 index 000000000000..6cf976bd483e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/onmount-external/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, logs }) { + assert.deepEqual(logs, ['mounted']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/onmount-external/main.svelte b/packages/svelte/tests/runtime-legacy/samples/onmount-external/main.svelte new file mode 100644 index 000000000000..e2e7dad8dc23 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/onmount-external/main.svelte @@ -0,0 +1,13 @@ + + + diff --git a/test/runtime/samples/onmount-fires-when-ready-nested/ParentWidget.svelte b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/ParentWidget.svelte similarity index 100% rename from test/runtime/samples/onmount-fires-when-ready-nested/ParentWidget.svelte rename to packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/ParentWidget.svelte diff --git a/test/runtime/samples/onmount-fires-when-ready-nested/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/Widget.svelte similarity index 100% rename from test/runtime/samples/onmount-fires-when-ready-nested/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/_config.js b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/_config.js new file mode 100644 index 000000000000..4f0f7b5b034d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // uses oncreate + + html: '

      true

      \n

      true

      ' +}); diff --git a/test/runtime/samples/onmount-fires-when-ready-nested/main.svelte b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/main.svelte similarity index 100% rename from test/runtime/samples/onmount-fires-when-ready-nested/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready-nested/main.svelte diff --git a/test/runtime/samples/onmount-fires-when-ready/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/Widget.svelte similarity index 100% rename from test/runtime/samples/onmount-fires-when-ready/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/_config.js b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/_config.js new file mode 100644 index 000000000000..9cb2d1716b2a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // uses oncreate + + html: '

      true

      ', + + test({ assert, component, target }) { + component.foo = true; + assert.htmlEqual(target.innerHTML, '

      true

      \n

      true

      '); + } +}); diff --git a/test/runtime/samples/onmount-fires-when-ready/main.svelte b/packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/main.svelte similarity index 100% rename from test/runtime/samples/onmount-fires-when-ready/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/onmount-fires-when-ready/main.svelte diff --git a/test/runtime/samples/onmount-sibling-order/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/onmount-sibling-order/Nested.svelte similarity index 100% rename from test/runtime/samples/onmount-sibling-order/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/onmount-sibling-order/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/onmount-sibling-order/_config.js b/packages/svelte/tests/runtime-legacy/samples/onmount-sibling-order/_config.js new file mode 100644 index 000000000000..ba0c5b0abb07 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/onmount-sibling-order/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; +import result from './result.js'; + +export default test({ + test({ assert }) { + assert.deepEqual(result, ['onMount foo', 'onMount bar']); + + result.pop(); + result.pop(); + } +}); diff --git a/test/runtime/samples/onmount-sibling-order/main.svelte b/packages/svelte/tests/runtime-legacy/samples/onmount-sibling-order/main.svelte similarity index 100% rename from test/runtime/samples/onmount-sibling-order/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/onmount-sibling-order/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/onmount-sibling-order/result.js b/packages/svelte/tests/runtime-legacy/samples/onmount-sibling-order/result.js new file mode 100644 index 000000000000..d6d1738de67e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/onmount-sibling-order/result.js @@ -0,0 +1 @@ +export default []; diff --git a/packages/svelte/tests/runtime-legacy/samples/option-without-select/_config.js b/packages/svelte/tests/runtime-legacy/samples/option-without-select/_config.js new file mode 100644 index 000000000000..6b56eaf1de0b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/option-without-select/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: 'hello' }; + }, + + html: "", + + test({ assert, component, target }) { + component.foo = 'goodbye'; + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/option-without-select/main.svelte b/packages/svelte/tests/runtime-legacy/samples/option-without-select/main.svelte similarity index 100% rename from test/runtime/samples/option-without-select/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/option-without-select/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/paren-wrapped-expressions/_config.js b/packages/svelte/tests/runtime-legacy/samples/paren-wrapped-expressions/_config.js new file mode 100644 index 000000000000..d7481bd7a016 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/paren-wrapped-expressions/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 'foo', b: true, c: [1, 2, 3] }; + }, + + html: ` + foo + + true + 1 + 2 + 3 + ` +}); diff --git a/test/runtime/samples/paren-wrapped-expressions/main.svelte b/packages/svelte/tests/runtime-legacy/samples/paren-wrapped-expressions/main.svelte similarity index 100% rename from test/runtime/samples/paren-wrapped-expressions/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/paren-wrapped-expressions/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/pre-tag/.editorconfig b/packages/svelte/tests/runtime-legacy/samples/pre-tag/.editorconfig new file mode 100644 index 000000000000..fa948941d5fc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/pre-tag/.editorconfig @@ -0,0 +1,2 @@ +[main.svelte] +trim_trailing_whitespace = unset diff --git a/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js new file mode 100644 index 000000000000..d7e1fe9d43a3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/pre-tag/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'server'], // output is correct, but test suite chokes on the extra ssr comment which is harmless + withoutNormalizeHtml: 'only-strip-comments', // because whitespace inside pre tags is significant + // Note how we're testing against target.innerHTML which already removed the redundant first newline + html: `
        A
      +  B
      +  
      +    C
      +    D
      +  
      +  E
      +  F
      +
      A + B C + D E + F
          A
      +    B
      +    
      +      C
      +      D
      +    
      +    E
      +    F
      +  
      leading newline
        leading newline and spaces
      +leading newlines
      without spaces
        with spaces  
      ${' '}
      +newline after leading space
      +
      +multiple leading newlines
      ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/pre-tag/main.svelte b/packages/svelte/tests/runtime-legacy/samples/pre-tag/main.svelte new file mode 100644 index 000000000000..6ab8b161de40 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/pre-tag/main.svelte @@ -0,0 +1,56 @@ +
      +  A
      +  B
      +  
      +    C
      +    D
      +  
      +  E
      +  F
      +
      + +
      + A + B + + C + D + + E + F +
      + +
      +
      +    A
      +    B
      +    
      +      C
      +      D
      +    
      +    E
      +    F
      +  
      +
      + +
      +
      +leading newline
      +
      +  leading newline and spaces
      +
      +
      +leading newlines
      +
      + +
      +
      without spaces
      +
        with spaces  
      +
       
      +newline after leading space
      +
      + +
      +
      +
      +multiple leading newlines
      diff --git a/packages/svelte/tests/runtime-legacy/samples/preload/_config.js b/packages/svelte/tests/runtime-legacy/samples/preload/_config.js new file mode 100644 index 000000000000..61a8373294fd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/preload/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, mod }) { + assert.deepEqual(mod.preload({ foo: 1 }), { bar: 2 }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/preload/main.svelte b/packages/svelte/tests/runtime-legacy/samples/preload/main.svelte new file mode 100644 index 000000000000..b285d423fc13 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/preload/main.svelte @@ -0,0 +1,7 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/preserve-comments/_config.js b/packages/svelte/tests/runtime-legacy/samples/preserve-comments/_config.js new file mode 100644 index 000000000000..b94abcbfa93e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/preserve-comments/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // a separate SSR test exists + + compileOptions: { + preserveComments: true + }, + + html: ` +

      before

      + +

      after

      + ` +}); diff --git a/test/server-side-rendering/samples/comment/main.svelte b/packages/svelte/tests/runtime-legacy/samples/preserve-comments/main.svelte similarity index 100% rename from test/server-side-rendering/samples/comment/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/preserve-comments/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/preserve-whitespaces/_config.js b/packages/svelte/tests/runtime-legacy/samples/preserve-whitespaces/_config.js new file mode 100644 index 000000000000..9b96d814b7e8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/preserve-whitespaces/_config.js @@ -0,0 +1,40 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + preserveWhitespace: true + }, + + html: `
        A
      +  B
      +  
      +    C
      +    D
      +  
      +  E
      +  F
      +
      + +
      + A + B + + C + D + + E + F +
      + +
      +
          A
      +    B
      +    
      +      C
      +      D
      +    
      +    E
      +    F
      +  
      +
      ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/preserve-whitespaces/main.svelte b/packages/svelte/tests/runtime-legacy/samples/preserve-whitespaces/main.svelte new file mode 100644 index 000000000000..ef603b988389 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/preserve-whitespaces/main.svelte @@ -0,0 +1,34 @@ +
      +  A
      +  B
      +  
      +    C
      +    D
      +  
      +  E
      +  F
      +
      + +
      + A + B + + C + D + + E + F +
      + +
      +
      +    A
      +    B
      +    
      +      C
      +      D
      +    
      +    E
      +    F
      +  
      +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-accessors/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-accessors/_config.js new file mode 100644 index 000000000000..9f4935521468 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-accessors/_config.js @@ -0,0 +1,23 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + accessors: false, + + test({ assert, component }) { + assert.equal(component.foo1, 42); + assert.equal(component.foo2(), 42); + assert.equal(component.bar, undefined); + + assert.throws(() => { + component.foo1 = null; + }, /Cannot set property foo1 of/); + + assert.throws(() => { + component.foo2 = null; + }, /Cannot set property foo2 of/); + } +}); diff --git a/test/runtime/samples/prop-accessors/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-accessors/main.svelte similarity index 100% rename from test/runtime/samples/prop-accessors/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/prop-accessors/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-const/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-const/Nested.svelte new file mode 100644 index 000000000000..392bc7555d92 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-const/Nested.svelte @@ -0,0 +1,7 @@ + + +

      a: {a}

      +

      b: {b}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-const/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-const/_config.js new file mode 100644 index 000000000000..804ee53342ec --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-const/_config.js @@ -0,0 +1,29 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 3, b: 4 }; + }, + + html: ` +

      a: 3

      +

      b: 2

      + `, + + test({ assert, component, target }) { + component.$set({ + a: 5, + b: 6 + }); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      a: 5

      +

      b: 2

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-const/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-const/main.svelte new file mode 100644 index 000000000000..e9184c8da4d9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-const/main.svelte @@ -0,0 +1,8 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-exports/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-exports/_config.js new file mode 100644 index 000000000000..1f8ca2d11218 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-exports/_config.js @@ -0,0 +1,33 @@ +import { test } from '../../test'; +import { writable } from 'svelte/store'; + +export default test({ + get props() { + return { + s1: writable(42), + s2: writable(43), + p1: 2, + p3: 3, + a1: writable(1), + a2: 4, + a6: writable(29), + for: 'loop', + continue: '...' + }; + }, + + html: ` + $s1=42 + $s2=43 + p1=2 + p3=3 + $v1=1 + v2=4 + vi1=4 + $vs1=1 + vl0=hello + vl1=test + $s3=29 + loop... + ` +}); diff --git a/test/runtime/samples/prop-exports/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-exports/main.svelte similarity index 100% rename from test/runtime/samples/prop-exports/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/prop-exports/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-no-change/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-no-change/Nested.svelte new file mode 100644 index 000000000000..d678e90e4880 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-no-change/Nested.svelte @@ -0,0 +1,6 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-no-change/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-no-change/_config.js new file mode 100644 index 000000000000..905c2a6226b2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-no-change/_config.js @@ -0,0 +1,11 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, logs, target }) { + assert.deepEqual(logs, ['primitive', 'object']); + target.querySelector('button')?.click(); + flushSync(); + assert.deepEqual(logs, ['primitive', 'object', 'object']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-no-change/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-no-change/main.svelte new file mode 100644 index 000000000000..f5b3d030c6e2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-no-change/main.svelte @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/test/runtime/samples/prop-not-action/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-not-action/Nested.svelte similarity index 100% rename from test/runtime/samples/prop-not-action/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/prop-not-action/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-not-action/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-not-action/_config.js new file mode 100644 index 000000000000..0d8b3b5ccd16 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-not-action/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { currentUser: { name: 'world' } }; + }, + + html: ` +

      Hello world!

      + ` +}); diff --git a/test/runtime/samples/prop-not-action/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-not-action/main.svelte similarity index 100% rename from test/runtime/samples/prop-not-action/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/prop-not-action/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-p-is-null/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-p-is-null/Child.svelte new file mode 100644 index 000000000000..f65cd15e3b01 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-p-is-null/Child.svelte @@ -0,0 +1,6 @@ + + +{x} {y} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-p-is-null/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-p-is-null/_config.js new file mode 100644 index 000000000000..71e42947055b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-p-is-null/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '0 0' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-p-is-null/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-p-is-null/main.svelte new file mode 100644 index 000000000000..e4389862c9ca --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-p-is-null/main.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-quoted/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-quoted/Nested.svelte new file mode 100644 index 000000000000..681f7126b2fb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-quoted/Nested.svelte @@ -0,0 +1 @@ +{$$props['x-y-z']} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-quoted/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-quoted/_config.js new file mode 100644 index 000000000000..13409f7b0d4c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-quoted/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: 1 }; + }, + + html: '1', + + async test({ assert, component, target }) { + component.foo = 2; + assert.htmlEqual(target.innerHTML, '2'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-quoted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-quoted/main.svelte new file mode 100644 index 000000000000..02490177621c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-quoted/main.svelte @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-subscribable/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-subscribable/_config.js new file mode 100644 index 000000000000..533d30494017 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-subscribable/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; +import { writable } from 'svelte/store'; + +export default test({ + get props() { + return { b: writable(42) }; + }, + + html: ` + 42 + ` +}); diff --git a/test/runtime/samples/prop-subscribable/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-subscribable/main.svelte similarity index 100% rename from test/runtime/samples/prop-subscribable/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/prop-subscribable/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-without-semicolon-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-without-semicolon-b/_config.js new file mode 100644 index 000000000000..e124ac269627 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-without-semicolon-b/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { name: 'world' }; + }, + + html: '

      Hello world!

      ' +}); diff --git a/test/runtime/samples/prop-without-semicolon-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-without-semicolon-b/main.svelte similarity index 100% rename from test/runtime/samples/prop-without-semicolon-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/prop-without-semicolon-b/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/prop-without-semicolon/_config.js b/packages/svelte/tests/runtime-legacy/samples/prop-without-semicolon/_config.js new file mode 100644 index 000000000000..240263603d28 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/prop-without-semicolon/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      Hello world!

      ' +}); diff --git a/test/runtime/samples/prop-without-semicolon/main.svelte b/packages/svelte/tests/runtime-legacy/samples/prop-without-semicolon/main.svelte similarity index 100% rename from test/runtime/samples/prop-without-semicolon/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/prop-without-semicolon/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/_config.js new file mode 100644 index 000000000000..91133f0bf4b7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 1, b: 2 }; + }, + + html: ` +

      a: 1

      +

      b: 2

      +

      c: 3

      + `, + + test({ assert, component, target }) { + component.$set({ a: 4 }); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      a: 4

      +

      b: 2

      +

      c: 6

      + ` + ); + + component.$set({ b: 5 }); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      a: 4

      +

      b: 5

      +

      c: 9

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/main.svelte new file mode 100644 index 000000000000..1c40f4a3442d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-b/main.svelte @@ -0,0 +1,8 @@ + + +

      a: {a}

      +

      b: {$$props.b}

      +

      c: {c}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/Child.svelte new file mode 100644 index 000000000000..dc6326f8c4e8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/Child.svelte @@ -0,0 +1,11 @@ + + +{data ? '' : null} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/_config.js b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/_config.js new file mode 100644 index 000000000000..363c850c8bdb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/_config.js @@ -0,0 +1,10 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + test({ assert, logs, target }) { + target.querySelector('button')?.click(); + flushSync(); + assert.deepEqual(logs, ['should fire once']); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/main.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/main.svelte new file mode 100644 index 000000000000..00c6a5f71c93 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-destroy/main.svelte @@ -0,0 +1,17 @@ + + + + +{#if active} + +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-only-with-change/Comp.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive-only-with-change/Comp.svelte new file mode 100644 index 000000000000..0eaf8a40d48a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-only-with-change/Comp.svelte @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-only-with-change/_config.js b/packages/svelte/tests/runtime-legacy/samples/props-reactive-only-with-change/_config.js new file mode 100644 index 000000000000..e048fbdf714f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-only-with-change/_config.js @@ -0,0 +1,36 @@ +import { test } from '../../test'; + +/** @type {string[]} */ +let callbacks = []; + +export default test({ + get props() { + return { + /** @param {string} value */ + callback: (value) => callbacks.push(value), + val1: '1', + val2: '2' + }; + }, + + before_test() { + callbacks = []; + }, + + async test({ assert, component }) { + assert.equal(callbacks.length, 2); + assert.equal(JSON.stringify(callbacks), '["1","2"]'); + + component.val1 = '3'; + assert.equal(callbacks.length, 3); + assert.equal(JSON.stringify(callbacks), '["1","2","1"]'); + + component.val1 = '4'; + assert.equal(callbacks.length, 4); + assert.equal(JSON.stringify(callbacks), '["1","2","1","1"]'); + + component.val2 = '5'; + assert.equal(callbacks.length, 5); + assert.equal(JSON.stringify(callbacks), '["1","2","1","1","2"]'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-only-with-change/main.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive-only-with-change/main.svelte new file mode 100644 index 000000000000..73ddd137f5bc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-only-with-change/main.svelte @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-slot/Comp.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive-slot/Comp.svelte new file mode 100644 index 000000000000..bf9e12a58a80 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-slot/Comp.svelte @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/props-reactive-slot/_config.js new file mode 100644 index 000000000000..85edf41dae92 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-slot/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

      hi

      + + `, + + test({ assert, target, window }) { + const btn = target.querySelector('button'); + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + + btn?.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      changed

      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive-slot/main.svelte new file mode 100644 index 000000000000..84777bf8abe0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive-slot/main.svelte @@ -0,0 +1,13 @@ + + + +

      + {props.someprop} +

      +
      + + \ No newline at end of file diff --git a/test/runtime/samples/props-reactive/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive/Nested.svelte similarity index 100% rename from test/runtime/samples/props-reactive/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/props-reactive/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/props-reactive/_config.js new file mode 100644 index 000000000000..f28bca8ebcfc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reactive/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 1, b: 2, c: 3, d: 4 }; + }, + + html: ` +

      4

      + `, + + test({ assert, component, target }) { + component.d = 5; + + assert.htmlEqual( + target.innerHTML, + ` +

      5

      + ` + ); + } +}); diff --git a/test/runtime/samples/props-reactive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reactive/main.svelte similarity index 100% rename from test/runtime/samples/props-reactive/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/props-reactive/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reassign/App.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reassign/App.svelte new file mode 100644 index 000000000000..7434b53fb18c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reassign/App.svelte @@ -0,0 +1,6 @@ + + +

      {$$props.a} {$$props.b}

      + diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reassign/_config.js b/packages/svelte/tests/runtime-legacy/samples/props-reassign/_config.js new file mode 100644 index 000000000000..b9ddd3923854 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reassign/_config.js @@ -0,0 +1,38 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +

      0

      + + `, + + test({ assert, target }) { + const [btn1, btn2] = target.querySelectorAll('button'); + + btn1.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      2

      + + ` + ); + + btn2.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      4 b

      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/props-reassign/main.svelte b/packages/svelte/tests/runtime-legacy/samples/props-reassign/main.svelte new file mode 100644 index 000000000000..376650369732 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props-reassign/main.svelte @@ -0,0 +1,7 @@ + + + + diff --git a/test/runtime/samples/props/RenderProps.svelte b/packages/svelte/tests/runtime-legacy/samples/props/RenderProps.svelte similarity index 100% rename from test/runtime/samples/props/RenderProps.svelte rename to packages/svelte/tests/runtime-legacy/samples/props/RenderProps.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/props/_config.js b/packages/svelte/tests/runtime-legacy/samples/props/_config.js new file mode 100644 index 000000000000..018df08d558b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/props/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 1 }; + }, + + html: ` +

      {"x":1}

      + `, + + test({ assert, component, target }) { + component.x = 2; + + assert.htmlEqual( + target.innerHTML, + ` +

      {"x":2}

      + ` + ); + } +}); diff --git a/test/runtime/samples/props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/props/main.svelte similarity index 100% rename from test/runtime/samples/props/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/props/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-child/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-child/_config.js new file mode 100644 index 000000000000..76b24468124f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-child/_config.js @@ -0,0 +1,20 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { raw: 'foo' }; + }, + + test({ assert, component, target, variant }) { + const span = target.querySelector('span'); + ok(span); + if (variant === 'dom') { + assert.ok(!span.previousSibling); + } else { + assert.equal(span.previousSibling?.textContent, '1tbe2lq'); // hash of the value + } + + component.raw = 'bar'; + assert.htmlEqual(target.innerHTML, '
      bar
      '); + } +}); diff --git a/test/runtime/samples/raw-anchor-first-child/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-child/main.svelte similarity index 100% rename from test/runtime/samples/raw-anchor-first-child/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-child/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-last-child/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-last-child/_config.js new file mode 100644 index 000000000000..dc436917378d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-last-child/_config.js @@ -0,0 +1,22 @@ +import { test, ok } from '../../test'; + +export default test({ + get props() { + return { raw: 'foo' }; + }, + + test({ assert, component, target, variant }) { + const span = target.querySelector('span'); + ok(span); + if (variant === 'dom') { + assert.ok(!span.previousSibling); + } else { + // hydration: previous is the ssr comment + assert.ok(!span.previousSibling?.previousSibling); + } + // next is the anchor + assert.ok(!span.nextSibling?.nextSibling); + + component.raw = 'bar'; + } +}); diff --git a/test/runtime/samples/raw-anchor-first-last-child/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-last-child/main.svelte similarity index 100% rename from test/runtime/samples/raw-anchor-first-last-child/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/raw-anchor-first-last-child/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-anchor-last-child/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-last-child/_config.js new file mode 100644 index 000000000000..e951de968d7c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-last-child/_config.js @@ -0,0 +1,18 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { raw: 'foo' }; + }, + + test({ assert, component, target }) { + const span = target.querySelector('span'); + ok(span); + + // In Svelte 5 we have an anchor after the raw fragment + assert.ok(span.nextSibling); + assert.ok(!span.nextSibling?.nextSibling); + + component.raw = 'bar'; + } +}); diff --git a/test/runtime/samples/raw-anchor-last-child/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-last-child/main.svelte similarity index 100% rename from test/runtime/samples/raw-anchor-last-child/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/raw-anchor-last-child/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-anchor-next-previous-sibling/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-next-previous-sibling/_config.js new file mode 100644 index 000000000000..95b3d77926de --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-next-previous-sibling/_config.js @@ -0,0 +1,24 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { raw: 'foo' }; + }, + + test({ assert, component, target, variant }) { + const span = target.querySelector('span'); + if (variant === 'dom') { + assert.equal(span?.previousSibling?.nodeName, 'BR'); + // next.next because of comment anchor before which @html is inserted + assert.equal(span?.nextSibling?.nextSibling?.nodeName, 'BR'); + } else { + // ssr comments inbetween + assert.equal(span?.previousSibling?.nodeName, '#comment'); + assert.equal(span?.previousSibling?.previousSibling?.nodeName, 'BR'); + assert.equal(span?.nextSibling?.nodeName, '#comment'); + assert.equal(span?.nextSibling?.nextSibling?.nodeName, 'BR'); + } + + component.raw = 'bar'; + } +}); diff --git a/test/runtime/samples/raw-anchor-next-previous-sibling/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-next-previous-sibling/main.svelte similarity index 100% rename from test/runtime/samples/raw-anchor-next-previous-sibling/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/raw-anchor-next-previous-sibling/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-anchor-next-sibling/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-next-sibling/_config.js new file mode 100644 index 000000000000..e7640621c1f1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-next-sibling/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { raw: 'foo' }; + }, + + test({ assert, component, target, variant }) { + const span = target.querySelector('span'); + if (variant === 'dom') { + assert.equal(span?.previousSibling?.nodeName, 'BR'); + } else { + // ssr comment inbetween + assert.equal(span?.previousSibling?.nodeName, '#comment'); + assert.equal(span?.previousSibling?.previousSibling?.nodeName, 'BR'); + } + + component.raw = 'bar'; + } +}); diff --git a/test/runtime/samples/raw-anchor-next-sibling/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-next-sibling/main.svelte similarity index 100% rename from test/runtime/samples/raw-anchor-next-sibling/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/raw-anchor-next-sibling/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-anchor-previous-sibling/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-previous-sibling/_config.js new file mode 100644 index 000000000000..e7640621c1f1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-previous-sibling/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { raw: 'foo' }; + }, + + test({ assert, component, target, variant }) { + const span = target.querySelector('span'); + if (variant === 'dom') { + assert.equal(span?.previousSibling?.nodeName, 'BR'); + } else { + // ssr comment inbetween + assert.equal(span?.previousSibling?.nodeName, '#comment'); + assert.equal(span?.previousSibling?.previousSibling?.nodeName, 'BR'); + } + + component.raw = 'bar'; + } +}); diff --git a/test/runtime/samples/raw-anchor-previous-sibling/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-anchor-previous-sibling/main.svelte similarity index 100% rename from test/runtime/samples/raw-anchor-previous-sibling/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/raw-anchor-previous-sibling/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustache-as-root/RawMustache.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-as-root/RawMustache.svelte new file mode 100644 index 000000000000..d94954f49b24 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-as-root/RawMustache.svelte @@ -0,0 +1,5 @@ + + +{@html content} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustache-as-root/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-as-root/_config.js new file mode 100644 index 000000000000..63a4b8aed3ac --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-as-root/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

      Another first line

      +

      This line should be last.

      + `, + test({ assert, target, window }) { + const btn = target.querySelector('button'); + ok(btn); + + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + + btn.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      First line

      +

      This line should be last.

      + ` + ); + + btn.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      Another first line

      +

      This line should be last.

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustache-as-root/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-as-root/main.svelte new file mode 100644 index 000000000000..7ccce0cd9be9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-as-root/main.svelte @@ -0,0 +1,17 @@ + + + + + + +

      This line should be last.

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustache-before-element/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-before-element/_config.js new file mode 100644 index 000000000000..d13ffc11edfd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-before-element/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      xbaz

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustache-before-element/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-before-element/main.svelte new file mode 100644 index 000000000000..69c1d0107d5d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-before-element/main.svelte @@ -0,0 +1 @@ +

      {@html 'x'}baz

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-head/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-head/_config.js new file mode 100644 index 000000000000..48854da3cc8e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-head/_config.js @@ -0,0 +1,30 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const btn = target.querySelector('button'); + ok(btn); + + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + + assert.htmlEqual( + window.document.head.innerHTML, + '' + ); + + flushSync(() => btn.dispatchEvent(clickEvent)); + + assert.htmlEqual( + window.document.head.innerHTML, + '' + ); + + flushSync(() => btn.dispatchEvent(clickEvent)); + + assert.htmlEqual( + window.document.head.innerHTML, + '' + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-head/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-head/main.svelte new file mode 100644 index 000000000000..25b9fdeee93c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-head/main.svelte @@ -0,0 +1,16 @@ + + + + + + {@html content} + + diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-slot/Component.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-slot/Component.svelte new file mode 100644 index 000000000000..fcabccae4898 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-slot/Component.svelte @@ -0,0 +1,2 @@ + +

      This line should be last.

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-slot/_config.js new file mode 100644 index 000000000000..63a4b8aed3ac --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-slot/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

      Another first line

      +

      This line should be last.

      + `, + test({ assert, target, window }) { + const btn = target.querySelector('button'); + ok(btn); + + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + + btn.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      First line

      +

      This line should be last.

      + ` + ); + + btn.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      Another first line

      +

      This line should be last.

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-slot/main.svelte new file mode 100644 index 000000000000..a022a68e9597 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustache-inside-slot/main.svelte @@ -0,0 +1,17 @@ + + + + + + {@html content} + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustaches-preserved/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-mustaches-preserved/_config.js new file mode 100644 index 000000000000..ce66bf29d8d8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustaches-preserved/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { raw: '

      does not change

      ' }; + }, + + html: '

      does not change

      ', + + test({ assert, component, target }) { + const p = target.querySelector('p'); + + component.raw = '

      does not change

      '; + assert.htmlEqual(target.innerHTML, '

      does not change

      '); + assert.strictEqual(target.querySelector('p'), p); + } +}); diff --git a/test/runtime/samples/raw-mustaches-preserved/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-mustaches-preserved/main.svelte similarity index 100% rename from test/runtime/samples/raw-mustaches-preserved/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/raw-mustaches-preserved/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustaches-td-tr/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-mustaches-td-tr/_config.js new file mode 100644 index 000000000000..3aee9ca65583 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustaches-td-tr/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { raw: '12' }; + }, + + html: ` + + + + + + + + + +
      57
      12
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustaches-td-tr/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-mustaches-td-tr/main.svelte new file mode 100644 index 000000000000..07d7299e439c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustaches-td-tr/main.svelte @@ -0,0 +1,12 @@ + + + + + + + + {@html raw} + +
      57
      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-mustaches/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-mustaches/_config.js new file mode 100644 index 000000000000..83c017961f50 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-mustaches/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + raw: 'raw html!!!\\o/' + }; + }, + + html: 'beforeraw html!!!\\o/after', + + test({ assert, component, target }) { + component.raw = ''; + assert.htmlEqual(target.innerHTML, 'beforeafter'); + component.raw = 'how about unclosed elements?'; + assert.htmlEqual(target.innerHTML, 'beforehow about unclosed elements?after'); + } +}); diff --git a/test/runtime/samples/raw-mustaches/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-mustaches/main.svelte similarity index 100% rename from test/runtime/samples/raw-mustaches/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/raw-mustaches/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-svg/_config.js b/packages/svelte/tests/runtime-legacy/samples/raw-svg/_config.js new file mode 100644 index 000000000000..3d13f8ed4043 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-svg/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, component, target }) { + component.show = true; + assert.htmlEqual(target.innerHTML, ''); + assert.instanceOf(target.querySelector('svg'), SVGElement); + assert.instanceOf(target.querySelector('circle'), SVGElement); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/raw-svg/main.svelte b/packages/svelte/tests/runtime-legacy/samples/raw-svg/main.svelte new file mode 100644 index 000000000000..248fa9125dea --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/raw-svg/main.svelte @@ -0,0 +1,7 @@ + + +{#if show} + {@html ''} +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-assignment-rhs/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-assignment-rhs/_config.js new file mode 100644 index 000000000000..9c7aea862005 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-assignment-rhs/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      1 1

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-assignment-rhs/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-assignment-rhs/main.svelte new file mode 100644 index 000000000000..2f83d54a5649 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-assignment-rhs/main.svelte @@ -0,0 +1,7 @@ + + +

      {foo} {bar}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-2/_config.js new file mode 100644 index 000000000000..f073c43f7cdc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-2/_config.js @@ -0,0 +1,12 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +// destructure to store value +export default test({ + html: '

      2 2 xxx 5 6 9 10 2

      ', + async test({ assert, target, component }) { + component.update(); + await tick(); + assert.htmlEqual(target.innerHTML, '

      11 11 yyy 12 13 14 15 11

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-2/main.svelte new file mode 100644 index 000000000000..c1bf63d9cd79 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-2/main.svelte @@ -0,0 +1,29 @@ + + +

      {foo} {$eid} {$u.name} {$v} {$w} {$x} {$y} {$z}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/_config.js new file mode 100644 index 000000000000..1a67e46b38a2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { store } from './store.js'; + +export default test({ + html: '

      0

      ', + before_test() { + store.reset(); + }, + test({ assert, target }) { + store.set(42); + flushSync(); + + assert.htmlEqual(target.innerHTML, '

      42

      '); + + assert.equal(store.numberOfTimesSubscribeCalled(), 1); + }, + test_ssr({ assert }) { + assert.equal(store.numberOfTimesSubscribeCalled(), 1); + assert.equal(store.isSubscribed(), false); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/main.svelte new file mode 100644 index 000000000000..3486dedaf1e5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/main.svelte @@ -0,0 +1,5 @@ + + +

      {$store}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/store.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/store.js new file mode 100644 index 000000000000..e01d832a0cd1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store-3/store.js @@ -0,0 +1,30 @@ +import { writable } from 'svelte/store'; +const _store = writable(0); +let count = 0; +let is_subscribed = false; + +export const store = { + ..._store, + + /** @param {(value: any) => void} fn */ + subscribe(fn) { + count++; + is_subscribed = true; + const unsub = _store.subscribe(fn); + return () => { + is_subscribed = false; + unsub(); + }; + }, + reset() { + count = 0; + is_subscribed = false; + _store.set(0); + }, + numberOfTimesSubscribeCalled() { + return count; + }, + isSubscribed() { + return is_subscribed; + } +}; diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store/_config.js new file mode 100644 index 000000000000..d23ffc4f9d62 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store/_config.js @@ -0,0 +1,12 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +// destructure to store +export default test({ + html: '

      2 2 xxx 5 6 9 10 2

      ', + async test({ assert, target, component }) { + component.update(); + await tick(); + assert.htmlEqual(target.innerHTML, '

      11 11 yyy 12 13 14 15 11

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store/main.svelte new file mode 100644 index 000000000000..cd4922353522 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration-with-store/main.svelte @@ -0,0 +1,29 @@ + + +

      {foo} {$eid} {u.name} {v} {$w} {$x} {$y} {$z}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration/_config.js new file mode 100644 index 000000000000..f88dd2e73f09 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      2 2

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration/main.svelte new file mode 100644 index 000000000000..dec1a490af49 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-complex-declaration/main.svelte @@ -0,0 +1,9 @@ + + +

      {foo} {eid}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-declaration/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-declaration/_config.js new file mode 100644 index 000000000000..9c7aea862005 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-declaration/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      1 1

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-declaration/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-declaration/main.svelte new file mode 100644 index 000000000000..edac4427bb08 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-declaration/main.svelte @@ -0,0 +1,9 @@ + + +

      {foo} {bar}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-for-loop-head/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-for-loop-head/_config.js new file mode 100644 index 000000000000..e461355b9668 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-for-loop-head/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      0 0

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-for-loop-head/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-for-loop-head/main.svelte new file mode 100644 index 000000000000..b007f6fe8b89 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-in-for-loop-head/main.svelte @@ -0,0 +1,14 @@ + + +

      {foo1} {foo2}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/_config.js new file mode 100644 index 000000000000..7c1547538418 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/_config.js @@ -0,0 +1,17 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: '', + + test({ assert, target, logs }) { + assert.deepEqual(logs, [2, 1]); + + const button = target.querySelector('button'); + + flushSync(() => button?.click()); + assert.deepEqual(logs, [2, 1, 2, 1]); + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/main.svelte new file mode 100644 index 000000000000..50b91246ffed --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-assignment-prevent-loop/main.svelte @@ -0,0 +1,20 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-block-break/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-block-break/_config.js new file mode 100644 index 000000000000..444aa8299603 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-block-break/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      1 2

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-block-break/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-block-break/main.svelte new file mode 100644 index 000000000000..5b0aa005c035 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-block-break/main.svelte @@ -0,0 +1,14 @@ + + +

      {foo} {bar}

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-compound-operator/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-compound-operator/_config.js new file mode 100644 index 000000000000..9eecf4a7a575 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-compound-operator/_config.js @@ -0,0 +1,39 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

      count: 0

      + `, + + async test({ assert, component, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + const button = target.querySelector('button'); + ok(button); + + button.dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 2); + assert.htmlEqual( + target.innerHTML, + ` + +

      count: 2

      + ` + ); + + button.dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 6); + assert.htmlEqual( + target.innerHTML, + ` + +

      count: 6

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-compound-operator/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-compound-operator/main.svelte new file mode 100644 index 000000000000..52654aed59df --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-compound-operator/main.svelte @@ -0,0 +1,8 @@ + + + +

      count: {x}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-function-called-reassigned/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-function-called-reassigned/_config.js new file mode 100644 index 000000000000..dacf6ffbc56d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-function-called-reassigned/_config.js @@ -0,0 +1,38 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +/** @type {string[]} */ +let value; +let called = 0; + +/** @param {string[]} _value */ +function callback(_value) { + called++; + value = _value; +} + +export default test({ + get props() { + return { callback }; + }, + before_test() { + called = 0; + }, + test({ assert, target, window }) { + assert.equal(called, 1); + + const input = target.querySelector('input'); + ok(input); + + const event = new window.Event('input'); + input.value = 'h'; + input.dispatchEvent(event); + flushSync(); + + assert.equal(called, 2); + assert.equal(value.length, 3); + assert.equal(value[0], 'h'); + assert.equal(value[1], '2'); + assert.equal(value[2], '3'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-function-called-reassigned/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-function-called-reassigned/main.svelte new file mode 100644 index 000000000000..10a3c79d1498 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-function-called-reassigned/main.svelte @@ -0,0 +1,10 @@ + + +{#each refs as ref} + +{/each} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-function-inline/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-function-inline/_config.js new file mode 100644 index 000000000000..1665a8c5e289 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-function-inline/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: '

      0

      ', + + test({ assert, component, target }) { + component.selected = 3; + assert.htmlEqual(target.innerHTML, '

      3

      '); + } +}); diff --git a/test/runtime/samples/reactive-function-inline/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-function-inline/main.svelte similarity index 100% rename from test/runtime/samples/reactive-function-inline/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-function-inline/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-function/_config.js new file mode 100644 index 000000000000..543c616c2688 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-function/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + html: '

      50

      ', + + test({ assert, component, target }) { + component.range = [50, 100]; + assert.htmlEqual(target.innerHTML, '

      75

      '); + + component.range = [50, 60]; + assert.htmlEqual(target.innerHTML, '

      55

      '); + + component.x = 8; + assert.htmlEqual(target.innerHTML, '

      58

      '); + } +}); diff --git a/test/runtime/samples/reactive-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-function/main.svelte similarity index 100% rename from test/runtime/samples/reactive-function/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-function/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-2/_config.js new file mode 100644 index 000000000000..e7898f8729d1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-2/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      prop value

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-2/data.js b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-2/data.js new file mode 100644 index 000000000000..56fb86982c77 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-2/data.js @@ -0,0 +1,3 @@ +export const obj = { + prop: 'prop value' +}; diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-2/main.svelte new file mode 100644 index 000000000000..2582974b71b3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-2/main.svelte @@ -0,0 +1,8 @@ + + +

      {prop}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-module/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-module/_config.js new file mode 100644 index 000000000000..a5dedc15fcc6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-module/_config.js @@ -0,0 +1,17 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import state from './state.js'; + +export default test({ + html: '', + + before_test() { + state.count = 0; + }, + + test({ assert, target }) { + const button = target.querySelector('button'); + flushSync(() => button?.click()); + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-module/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-module/main.svelte new file mode 100644 index 000000000000..18db8a7a3137 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-module/main.svelte @@ -0,0 +1,9 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-module/state.js b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-module/state.js new file mode 100644 index 000000000000..f0fc271f84e9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement-module/state.js @@ -0,0 +1,3 @@ +export default { + count: 0 +}; diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/_config.js new file mode 100644 index 000000000000..ea3ab4b356a0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/_config.js @@ -0,0 +1,52 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; +import { reset_numbers } from './data'; + +export default test({ + html: ` + import +

      1 + 2 + 3 + 4 = 10

      + local +

      1 + 2 + 3 + 4 = 10

      + + `, + before_test() { + reset_numbers(); + }, + async test({ assert, target, window }) { + const btn = target.querySelector('button'); + ok(btn); + + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + + flushSync(() => { + btn.dispatchEvent(clickEvent); + }); + + assert.htmlEqual( + target.innerHTML, + ` + import +

      1 + 2 + 3 + 4 + 5 = 15

      + local +

      1 + 2 + 3 + 4 + 5 = 15

      + + ` + ); + + flushSync(() => { + btn.dispatchEvent(clickEvent); + }); + + assert.htmlEqual( + target.innerHTML, + ` + import +

      1 + 2 + 3 + 4 + 5 + 6 = 21

      + local +

      1 + 2 + 3 + 4 + 5 + 6 = 21

      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/data.js b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/data.js new file mode 100644 index 000000000000..a45bb6931044 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/data.js @@ -0,0 +1,5 @@ +export let numbers = [1, 2, 3, 4]; + +export function reset_numbers() { + numbers = [1, 2, 3, 4]; +} diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/main.svelte new file mode 100644 index 000000000000..daded0494f4b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-import-statement/main.svelte @@ -0,0 +1,19 @@ + + +import

      {numbers.join(' + ')} = {sum}

      +local

      {local_numbers.join(' + ')} = {local_sum}

      + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-statement-indirect/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-indirect/_config.js new file mode 100644 index 000000000000..4cc21b0db9d2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-indirect/_config.js @@ -0,0 +1,24 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

      2

      + + `, + test({ assert, target }) { + target + .querySelector('button') + ?.dispatchEvent(new window.MouseEvent('click', { bubbles: true })); + + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      4

      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-statement-indirect/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-indirect/main.svelte new file mode 100644 index 000000000000..ab75c19127cd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-indirect/main.svelte @@ -0,0 +1,11 @@ + + +

      {indirect_double}

      + diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-statement-module-vars/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-module-vars/_config.js new file mode 100644 index 000000000000..168876c525ca --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-module-vars/_config.js @@ -0,0 +1,25 @@ +import { test } from '../../test'; + +export default test({ + html: ` + a: moduleA + b: moduleB + moduleA: moduleA + moduleB: moduleB + `, + async test({ assert, target, component }) { + await component.updateModuleA(); + + assert.htmlEqual( + target.innerHTML, + ` + a: moduleA + b: moduleB + moduleA: moduleA + moduleB: moduleB + ` + ); + + component.reset(); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-statement-module-vars/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-module-vars/main.svelte new file mode 100644 index 000000000000..9bb31b0ea7a8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-module-vars/main.svelte @@ -0,0 +1,20 @@ + + +a: {a} +b: {b} +moduleA: {moduleA} +moduleB: {moduleB} diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-statement-store/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-store/_config.js new file mode 100644 index 000000000000..99007bfdd995 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-store/_config.js @@ -0,0 +1,12 @@ +import { tick } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ``, + async test({ assert, target }) { + target.querySelector('button')?.click(); + await tick(); + + assert.htmlEqual(target.innerHTML, ``); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-statement-store/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-store/main.svelte new file mode 100644 index 000000000000..62a06751d311 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-statement-store/main.svelte @@ -0,0 +1,16 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-update-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-update-expression/_config.js new file mode 100644 index 000000000000..38494fee8a1e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-update-expression/_config.js @@ -0,0 +1,41 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + +

      count: 1

      + `, + + test({ assert, component, target, window }) { + const click = new window.MouseEvent('click', { bubbles: true }); + const button = target.querySelector('button'); + ok(button); + + assert.equal(component.x, 1); + + button.dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 3); + assert.htmlEqual( + target.innerHTML, + ` + +

      count: 3

      + ` + ); + + button.dispatchEvent(click); + flushSync(); + + assert.equal(component.x, 5); + assert.htmlEqual( + target.innerHTML, + ` + +

      count: 5

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-update-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-update-expression/main.svelte new file mode 100644 index 000000000000..0e0b45ddd684 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-update-expression/main.svelte @@ -0,0 +1,12 @@ + + + +

      count: {x}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-properties/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-properties/_config.js new file mode 100644 index 000000000000..fed7568b628f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-properties/_config.js @@ -0,0 +1,37 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ``, + test({ assert, target }) { + const [button1, button2, button3, button4] = target.querySelectorAll('button'); + + button1.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + `` + ); + + button2.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + `` + ); + + button3.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + `` + ); + + button4.click(); + flushSync(); + assert.htmlEqual( + target.innerHTML, + `` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-properties/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-properties/main.svelte new file mode 100644 index 000000000000..2ff764892ed2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-properties/main.svelte @@ -0,0 +1,15 @@ + + +{#each array as row, i} + {#each row as item, j} + + {/each} +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-property/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-property/_config.js new file mode 100644 index 000000000000..d40c663f1ebe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-property/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      Hello world!

      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-property/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-property/main.svelte new file mode 100644 index 000000000000..58e0fdb03c39 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-assign-property/main.svelte @@ -0,0 +1,6 @@ + + +

      Hello {user.name}!

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce-precedence/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce-precedence/_config.js new file mode 100644 index 000000000000..ce97031cbbd5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce-precedence/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      true

      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce-precedence/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce-precedence/main.svelte new file mode 100644 index 000000000000..fc73456e9eac --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce-precedence/main.svelte @@ -0,0 +1 @@ +

      {1 === 1}

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce/_config.js new file mode 100644 index 000000000000..dc1c1c015739 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + html: '1-1', + + test: ({ assert, component, target }) => { + component.a.b[0] = 2; + component.a = component.a; // eslint-disable-line no-self-assign + + assert.htmlEqual(target.innerHTML, '2-2'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce/main.svelte new file mode 100644 index 000000000000..b7b67e91a64b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-coerce/main.svelte @@ -0,0 +1,7 @@ + + +{a.b}-{identity(a.b)} diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-dependency-not-referenced/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-dependency-not-referenced/_config.js new file mode 100644 index 000000000000..3b31ee766e33 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-dependency-not-referenced/_config.js @@ -0,0 +1,41 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

      42

      +

      42

      + `, + + test({ assert, component, target }) { + component.updateStore(undefined); + flushSync(); + + assert.htmlEqual(target.innerHTML, '

      42

      '); + + component.updateStore(33); + flushSync(); + + assert.htmlEqual(target.innerHTML, '

      33

      42

      '); + + component.updateStore(undefined); + flushSync(); + + assert.htmlEqual(target.innerHTML, '

      42

      '); + + component.updateVar(undefined); + flushSync(); + + assert.htmlEqual(target.innerHTML, '

      '); + + component.updateVar(33); + flushSync(); + + assert.htmlEqual(target.innerHTML, '

      33

      '); + + component.updateVar(undefined); + flushSync(); + + assert.htmlEqual(target.innerHTML, '

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-dependency-not-referenced/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-value-dependency-not-referenced/main.svelte new file mode 100644 index 000000000000..57e6ba84f35e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-dependency-not-referenced/main.svelte @@ -0,0 +1,19 @@ + + +

      { value }

      +

      { value2 }

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-function-hoist-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function-hoist-b/_config.js new file mode 100644 index 000000000000..a2f2927078ee --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function-hoist-b/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + `, + + async test({ assert, target, window }) { + const event = new window.MouseEvent('click', { bubbles: true }); + const button = target.querySelector('button'); + + await button?.dispatchEvent(event); + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-value-function-hoist-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function-hoist-b/main.svelte similarity index 100% rename from test/runtime/samples/reactive-value-function-hoist-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-value-function-hoist-b/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-function-hoist/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function-hoist/_config.js new file mode 100644 index 000000000000..5cfb42290220 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function-hoist/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + // TODO: This passes but unclear what the test is actually testing + html: ` + + `, + + async test({ assert, target, window }) { + const event = new window.MouseEvent('click', { bubbles: true }); + const button = target.querySelector('button'); + + await button?.dispatchEvent(event); + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-value-function-hoist/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function-hoist/main.svelte similarity index 100% rename from test/runtime/samples/reactive-value-function-hoist/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-value-function-hoist/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-function/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function/_config.js new file mode 100644 index 000000000000..5317ab496fb5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function/_config.js @@ -0,0 +1,13 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: '1-2', + + test({ assert, component, target }) { + component.update(); + flushSync(); + + assert.htmlEqual(target.innerHTML, '3-4'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-function/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function/main.svelte new file mode 100644 index 000000000000..4830070e062c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-function/main.svelte @@ -0,0 +1,14 @@ + + +{foo()}-{bar()} diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-mutate-const/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-mutate-const/_config.js new file mode 100644 index 000000000000..03d973fc0bd7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-mutate-const/_config.js @@ -0,0 +1,25 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +
      {}
      + `, + + test({ assert, target }) { + const button = target.querySelector('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + button?.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +
      {"foo":42}
      + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-value-mutate-const/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-value-mutate-const/main.svelte similarity index 100% rename from test/runtime/samples/reactive-value-mutate-const/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-value-mutate-const/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-value-mutate/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-value-mutate/_config.js new file mode 100644 index 000000000000..eb7cccad2593 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-value-mutate/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '{"bar":42}' +}); diff --git a/test/runtime/samples/reactive-value-mutate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-value-mutate/main.svelte similarity index 100% rename from test/runtime/samples/reactive-value-mutate/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-value-mutate/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-deconflicted/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-deconflicted/_config.js new file mode 100644 index 000000000000..b599b1410f32 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-deconflicted/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + html: 'waiting', + + test({ assert, component, target }) { + component.x = 'ready'; + assert.htmlEqual( + target.innerHTML, + ` + ready + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-values-deconflicted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-deconflicted/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-deconflicted/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-deconflicted/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-exported/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-exported/_config.js new file mode 100644 index 000000000000..96b7879491b4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-exported/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 1 }; + }, + + html: ` +

      1 1 1

      + `, + + test({ assert, component }) { + assert.equal(component.y, 1); + assert.equal(component.z, 1); + + component.x = 2; + assert.equal(component.y, 2); + assert.equal(component.z, 2); + } +}); diff --git a/test/runtime/samples/reactive-values-exported/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-exported/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-exported/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-exported/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-fixed/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-fixed/_config.js new file mode 100644 index 000000000000..c327efb9ffff --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-fixed/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      4

      + `, + + test({ assert, target }) { + assert.htmlEqual( + target.innerHTML, + ` +

      4

      + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-values-fixed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-fixed/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-fixed/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-fixed/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-function-dependency/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-function-dependency/_config.js new file mode 100644 index 000000000000..da11da237b72 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-function-dependency/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: '

      2

      ', + + test({ assert, component, target }) { + component.y = 2; + assert.equal(component.x, 4); + assert.htmlEqual(target.innerHTML, '

      4

      '); + } +}); diff --git a/test/runtime/samples/reactive-values-function-dependency/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-function-dependency/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-function-dependency/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-function-dependency/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit-destructured/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit-destructured/_config.js new file mode 100644 index 000000000000..1be63ef4b31a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit-destructured/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { coords: [0, 0], numbers: { answer: 42 } }; + }, + + html: ` +

      0,0

      +

      42

      + `, + + test({ assert, component, target }) { + component.coords = [1, 2]; + assert.htmlEqual( + target.innerHTML, + ` +

      1,2

      +

      42

      + ` + ); + + component.numbers = { answer: 43 }; + assert.htmlEqual( + target.innerHTML, + ` +

      1,2

      +

      43

      + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-values-implicit-destructured/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit-destructured/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-implicit-destructured/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit-destructured/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit-self-dependency/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit-self-dependency/_config.js new file mode 100644 index 000000000000..492a381fe3cc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit-self-dependency/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      1 / 1

      + `, + + test({ assert, component, target }) { + component.num = 3; + + assert.htmlEqual( + target.innerHTML, + ` +

      3 / 3

      + ` + ); + + component.num = 2; + + assert.htmlEqual( + target.innerHTML, + ` +

      2 / 3

      + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-values-implicit-self-dependency/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit-self-dependency/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-implicit-self-dependency/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit-self-dependency/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit/_config.js new file mode 100644 index 000000000000..f8eedcb13a4d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      1 + 2 = 3

      +

      3 * 3 = 9

      + `, + + test({ assert, component, target }) { + component.a = 3; + assert.htmlEqual( + target.innerHTML, + ` +

      3 + 2 = 5

      +

      5 * 5 = 25

      + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-values-implicit/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-implicit/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-implicit/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-no-dependencies/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-no-dependencies/_config.js new file mode 100644 index 000000000000..4d00f59fae41 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-no-dependencies/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      10 - 90

      + `, + + test({ assert, component, target }) { + component.width = 50; + assert.htmlEqual( + target.innerHTML, + ` +

      10 - 40

      + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-values-no-dependencies/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-no-dependencies/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-no-dependencies/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-no-dependencies/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-no-implicit-member-expression/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-no-implicit-member-expression/_config.js new file mode 100644 index 000000000000..2bd5dff5c9cc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-no-implicit-member-expression/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, window }) { + assert.equal(window.document.title, 'foo'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-no-implicit-member-expression/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-no-implicit-member-expression/main.svelte new file mode 100644 index 000000000000..a631d4d9f88c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-no-implicit-member-expression/main.svelte @@ -0,0 +1,3 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical-declaration-order-independent/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical-declaration-order-independent/_config.js new file mode 100644 index 000000000000..07cf371b6e68 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical-declaration-order-independent/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      2+2=4

      + `, + + test({ assert, target }) { + assert.htmlEqual( + target.innerHTML, + ` +

      2+2=4

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical-declaration-order-independent/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical-declaration-order-independent/main.svelte new file mode 100644 index 000000000000..766ca7aa86db --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical-declaration-order-independent/main.svelte @@ -0,0 +1,7 @@ + + +

      {a}+{b}={c}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical/_config.js new file mode 100644 index 000000000000..f120d76aeeb0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical/_config.js @@ -0,0 +1,22 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 42 }; + }, + + html: ` +

      42 42

      + `, + + test({ assert, component, target }) { + component.x = 43; + + assert.htmlEqual( + target.innerHTML, + ` +

      43 43

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical/main.svelte new file mode 100644 index 000000000000..9862cc32d5ea --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-non-cyclical/main.svelte @@ -0,0 +1,13 @@ + + +

      {a} {b}

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-overwrite/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-overwrite/_config.js new file mode 100644 index 000000000000..830700d143ef --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-overwrite/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      doubled: 2

      + `, + + test({ assert, component, target }) { + component.a = 2; + + assert.equal(component.doubled, 4); + assert.htmlEqual( + target.innerHTML, + ` +

      doubled: 4

      + ` + ); + + component.doubled = 3; + + assert.equal(component.doubled, 3); + assert.htmlEqual( + target.innerHTML, + ` +

      doubled: 3

      + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-values-overwrite/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-overwrite/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-overwrite/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-overwrite/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-second-order/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-second-order/_config.js new file mode 100644 index 000000000000..d14ae0afc1f2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-second-order/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component }) { + assert.equal(component.qux, 2); + + component.foo = 2; + assert.equal(component.qux, 4); + } +}); diff --git a/test/runtime/samples/reactive-values-second-order/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-second-order/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-second-order/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-second-order/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-self-dependency-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-self-dependency-b/_config.js new file mode 100644 index 000000000000..81d74e864105 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-self-dependency-b/_config.js @@ -0,0 +1,27 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      count: 0

      + `, + + test({ assert, component, target }) { + component.count = 5; + + assert.htmlEqual( + target.innerHTML, + ` +

      count: 5

      + ` + ); + + component.count = 50; + + assert.htmlEqual( + target.innerHTML, + ` +

      count: 9

      + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-values-self-dependency-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-self-dependency-b/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-self-dependency-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-self-dependency-b/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-self-dependency/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-self-dependency/_config.js new file mode 100644 index 000000000000..d5a0beb8f8e1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-self-dependency/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      1 + 2 = 3

      +

      Times calculated: 1

      + `, + + test({ assert, component, target }) { + component.a = 3; + + assert.htmlEqual( + target.innerHTML, + ` +

      3 + 2 = 5

      +

      Times calculated: 2

      + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-values-self-dependency/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-self-dependency/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-self-dependency/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-self-dependency/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-store-destructured-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-store-destructured-undefined/_config.js new file mode 100644 index 000000000000..e05f103f90bc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-store-destructured-undefined/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      +

      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-store-destructured-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-store-destructured-undefined/main.svelte new file mode 100644 index 000000000000..152e0e3e2e2a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-store-destructured-undefined/main.svelte @@ -0,0 +1,9 @@ + + +

      {foo1}

      +

      {foo2}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-subscript-assignment/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-subscript-assignment/_config.js new file mode 100644 index 000000000000..aa5c6ab8f245 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-subscript-assignment/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component }) { + assert.deepEqual(component.foo, {}); + component.bar = 'hello'; + assert.deepEqual(component.foo, { hello: true }); + component.bar = 'world'; + assert.deepEqual(component.foo, { hello: true, world: true }); + component.bar = false; + assert.deepEqual(component.foo, { hello: true, world: true }); + } +}); diff --git a/test/runtime/samples/reactive-values-subscript-assignment/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-subscript-assignment/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values-subscript-assignment/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values-subscript-assignment/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-text-node/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-text-node/_config.js new file mode 100644 index 000000000000..e97a046f68c1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-text-node/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; +import { create_deferred } from '../../../helpers'; +import { flushSync } from 'svelte'; + +/** @type {ReturnType} */ +let deferred; + +export default test({ + before_test() { + deferred = create_deferred(); + }, + + get props() { + return { deferred }; + }, + + html: '
      same text
      ', + + async test({ assert, target }) { + await deferred.promise; + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      same text text
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-text-node/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-text-node/main.svelte new file mode 100644 index 000000000000..9e19f14f8661 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-text-node/main.svelte @@ -0,0 +1,10 @@ + + +
      {text} text
      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-uninitialised/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values-uninitialised/_config.js new file mode 100644 index 000000000000..6221a999f6d4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-uninitialised/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '

      aca

      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values-uninitialised/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values-uninitialised/main.svelte new file mode 100644 index 000000000000..2cacc411d236 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values-uninitialised/main.svelte @@ -0,0 +1,12 @@ + + +

      {a}{b}{c}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/reactive-values/_config.js b/packages/svelte/tests/runtime-legacy/samples/reactive-values/_config.js new file mode 100644 index 000000000000..b1b055b2c375 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/reactive-values/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      1 + 2 = 3

      +

      3 * 3 = 9

      + `, + + test({ assert, component, target }) { + component.a = 3; + assert.equal(component.c, 5); + assert.equal(component.cSquared, 25); + assert.htmlEqual( + target.innerHTML, + ` +

      3 + 2 = 5

      +

      5 * 5 = 25

      + ` + ); + } +}); diff --git a/test/runtime/samples/reactive-values/main.svelte b/packages/svelte/tests/runtime-legacy/samples/reactive-values/main.svelte similarity index 100% rename from test/runtime/samples/reactive-values/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/reactive-values/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/renamed-instance-exports/_config.js b/packages/svelte/tests/runtime-legacy/samples/renamed-instance-exports/_config.js new file mode 100644 index 000000000000..29860bb9df8c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/renamed-instance-exports/_config.js @@ -0,0 +1,18 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + test({ assert, component }) { + assert.equal(component.bar1, 42); + assert.equal(component.bar2, 42); + assert.throws(() => { + component.bar1 = 100; + }, /Cannot set property bar1 of .+ which has only a getter/); + component.bar2 = 100; + assert.equal(component.bar1, 42); + assert.equal(component.bar2, 100); + } +}); diff --git a/test/runtime/samples/renamed-instance-exports/main.svelte b/packages/svelte/tests/runtime-legacy/samples/renamed-instance-exports/main.svelte similarity index 100% rename from test/runtime/samples/renamed-instance-exports/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/renamed-instance-exports/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-delete/App.svelte b/packages/svelte/tests/runtime-legacy/samples/rest-props-delete/App.svelte new file mode 100644 index 000000000000..e7857f28e9dc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-delete/App.svelte @@ -0,0 +1,12 @@ + + + + +{JSON.stringify($$restProps)} diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-delete/_config.js b/packages/svelte/tests/runtime-legacy/samples/rest-props-delete/_config.js new file mode 100644 index 000000000000..853af731f989 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-delete/_config.js @@ -0,0 +1,15 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: `\n{"a":1,"b":2}`, + + test({ assert, target }) { + const [btn1] = target.querySelectorAll('button'); + + btn1.click(); + flushSync(); + + assert.htmlEqual(target.innerHTML, `\n{"b":2}`); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-delete/main.svelte b/packages/svelte/tests/runtime-legacy/samples/rest-props-delete/main.svelte new file mode 100644 index 000000000000..461848a3b307 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-delete/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-no-alias/_config.js b/packages/svelte/tests/runtime-legacy/samples/rest-props-no-alias/_config.js new file mode 100644 index 000000000000..8bfc1cc660c9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-no-alias/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + props: { + x: 1, + y: 2, + z: 3 + }, + html: `
      {"x":1,"z":3}
      `, + + async test({ assert, target, component }) { + component.y = 4; + assert.htmlEqual(target.innerHTML, `
      {"x":1,"z":3}
      `); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-no-alias/main.svelte b/packages/svelte/tests/runtime-legacy/samples/rest-props-no-alias/main.svelte new file mode 100644 index 000000000000..b5b98388b9e8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-no-alias/main.svelte @@ -0,0 +1,6 @@ + + +
      {JSON.stringify($$restProps)}
      diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-reassign/App.svelte b/packages/svelte/tests/runtime-legacy/samples/rest-props-reassign/App.svelte new file mode 100644 index 000000000000..3121bb9da330 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-reassign/App.svelte @@ -0,0 +1,6 @@ + + +

      {$$restProps.a} {$$restProps.b} {$$restProps.c}

      + diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-reassign/_config.js b/packages/svelte/tests/runtime-legacy/samples/rest-props-reassign/_config.js new file mode 100644 index 000000000000..694ba871ed5d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-reassign/_config.js @@ -0,0 +1,38 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` + +

      0 c

      + + `, + + test({ assert, target }) { + const [btn1, btn2] = target.querySelectorAll('button'); + + btn1.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      1 c

      + + ` + ); + + btn2.click(); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      1 b c

      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-reassign/main.svelte b/packages/svelte/tests/runtime-legacy/samples/rest-props-reassign/main.svelte new file mode 100644 index 000000000000..376650369732 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-reassign/main.svelte @@ -0,0 +1,7 @@ + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-without-props/App.svelte b/packages/svelte/tests/runtime-legacy/samples/rest-props-without-props/App.svelte new file mode 100644 index 000000000000..5197cb59b49d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-without-props/App.svelte @@ -0,0 +1,12 @@ + +
      Length: {length}
      +
      Values: {values.join(',')}
      + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-without-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/rest-props-without-props/_config.js new file mode 100644 index 000000000000..a210563ec38c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-without-props/_config.js @@ -0,0 +1,70 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 3, b: 4, c: 5, d: 6 }; + }, + html: ` +
      Length: 3
      +
      Values: 4,5,1
      +
      + + `, + test({ assert, target, window }) { + const [btn1, btn2, btn3, btn4] = target.querySelectorAll('button'); + const clickEvent = new window.Event('click', { bubbles: true }); + + btn1.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      Length: 3
      +
      Values: 4,5,1
      +
      + + ` + ); + + btn2.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      Length: 3
      +
      Values: 34,5,1
      +
      + + ` + ); + + btn3.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      Length: 3
      +
      Values: 34,5,31
      +
      + + ` + ); + + btn4.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      Length: 4
      +
      Values: 34,5,31,2
      +
      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props-without-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/rest-props-without-props/main.svelte new file mode 100644 index 000000000000..21b2690584ef --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props-without-props/main.svelte @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props/App.svelte b/packages/svelte/tests/runtime-legacy/samples/rest-props/App.svelte new file mode 100644 index 000000000000..56edc0b7e49d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props/App.svelte @@ -0,0 +1,13 @@ + +
      Length: {length}
      +
      Values: {values.join(',')}
      + +
      +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/rest-props/_config.js new file mode 100644 index 000000000000..969843b83b7f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props/_config.js @@ -0,0 +1,76 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + get props() { + return { a: 3, b: 4, c: 5, d: 6 }; + }, + html: ` +
      Length: 3
      +
      Values: 4,5,1
      +
      +
      + + `, + + test({ assert, target, window }) { + const [btn1, btn2, btn3, btn4] = target.querySelectorAll('button'); + const clickEvent = new window.Event('click', { bubbles: true }); + + btn1.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      Length: 3
      +
      Values: 4,5,1
      +
      +
      + + ` + ); + + btn2.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      Length: 3
      +
      Values: 34,5,1
      +
      +
      + + ` + ); + + btn3.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      Length: 3
      +
      Values: 34,5,31
      +
      +
      + + ` + ); + + btn4.dispatchEvent(clickEvent); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      Length: 4
      +
      Values: 34,5,31,2
      +
      +
      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/rest-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/rest-props/main.svelte new file mode 100644 index 000000000000..21b2690584ef --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/rest-props/main.svelte @@ -0,0 +1,25 @@ + + + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/script-style-non-top-level/_config.js b/packages/svelte/tests/runtime-legacy/samples/script-style-non-top-level/_config.js new file mode 100644 index 000000000000..586a9208c523 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/script-style-non-top-level/_config.js @@ -0,0 +1,10 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      + + +
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/script-style-non-top-level/main.svelte b/packages/svelte/tests/runtime-legacy/samples/script-style-non-top-level/main.svelte new file mode 100644 index 000000000000..ddca05eed9c2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/script-style-non-top-level/main.svelte @@ -0,0 +1,4 @@ +
      + + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/select-bind-array/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-bind-array/_config.js new file mode 100644 index 000000000000..73b40871f6d8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-bind-array/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +const items = [{ id: 'a' }, { id: 'b' }]; + +export default test({ + get props() { + return { foo: 'b', items }; + }, + + test({ assert, component, target }) { + const options = target.querySelectorAll('option'); + + assert.equal(options[0].selected, false); + assert.equal(options[1].selected, true); + + component.foo = items[0].id; + + assert.equal(options[0].selected, true); + assert.equal(options[1].selected, false); + } +}); diff --git a/test/runtime/samples/select-bind-array/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-bind-array/main.svelte similarity index 100% rename from test/runtime/samples/select-bind-array/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/select-bind-array/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/select-bind-in-array/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-bind-in-array/_config.js new file mode 100644 index 000000000000..cb7e06b7a518 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-bind-in-array/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +const items = [{ id: 'a' }, { id: 'b' }]; + +export default test({ + get props() { + return { items }; + }, + + test({ assert, component }) { + const items = component.items; + + assert.equal(items[0].id, 'a'); + assert.equal(items[1].id, 'b'); + } +}); diff --git a/test/runtime/samples/select-bind-in-array/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-bind-in-array/main.svelte similarity index 100% rename from test/runtime/samples/select-bind-in-array/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/select-bind-in-array/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/select-change-handler/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-change-handler/_config.js new file mode 100644 index 000000000000..66cadb34f5bd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-change-handler/_config.js @@ -0,0 +1,25 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { + options: [{ id: 'a' }, { id: 'b' }, { id: 'c' }], + selected: 'b' + }; + }, + + test({ assert, component, target, window }) { + const select = target.querySelector('select'); + ok(select); + assert.equal(select.value, 'b'); + + const event = new window.Event('change'); + + select.value = 'c'; + select.dispatchEvent(event); + + assert.equal(select.value, 'c'); + assert.equal(component.lastChangedTo, 'c'); + assert.equal(component.selected, 'c'); + } +}); diff --git a/test/runtime/samples/select-change-handler/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-change-handler/main.svelte similarity index 100% rename from test/runtime/samples/select-change-handler/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/select-change-handler/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js new file mode 100644 index 000000000000..335c46d53db4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-in-each/_config.js @@ -0,0 +1,32 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` + + selected: a + `, + + test({ assert, target }) { + const select = target.querySelector('select'); + ok(select); + const event = new window.Event('change'); + select.value = 'b'; + select.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + selected: b + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/select-in-each/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-in-each/main.svelte new file mode 100644 index 000000000000..a908efad1800 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-in-each/main.svelte @@ -0,0 +1,11 @@ + + +{#each entries as entry} + + selected: {entry.selected} +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/select-lazy-options/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-lazy-options/_config.js new file mode 100644 index 000000000000..88a8281f4414 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-lazy-options/_config.js @@ -0,0 +1,18 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + async test({ assert, target }) { + target.querySelector('button')?.click(); + flushSync(); + await Promise.resolve(); + + const options = target.querySelectorAll('option'); + assert.equal(options[0].selected, false); + assert.equal(options[1].selected, true); + assert.equal(options[2].selected, false); + assert.equal(options[3].selected, false); + assert.equal(options[4].selected, true); + assert.equal(options[5].selected, false); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/select-lazy-options/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-lazy-options/main.svelte new file mode 100644 index 000000000000..5d4b51c371d2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-lazy-options/main.svelte @@ -0,0 +1,33 @@ + + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread-and-bind/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread-and-bind/_config.js new file mode 100644 index 000000000000..fc855da7068c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread-and-bind/_config.js @@ -0,0 +1,14 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component, target }) { + const options = target.querySelectorAll('option'); + + assert.equal(options[0].selected, true); + assert.equal(options[1].selected, false); + + component.value = ['2']; + assert.equal(options[0].selected, false); + assert.equal(options[1].selected, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread-and-bind/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread-and-bind/main.svelte new file mode 100644 index 000000000000..45ef4d2f056c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread-and-bind/main.svelte @@ -0,0 +1,8 @@ + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread/_config.js new file mode 100644 index 000000000000..0619b1468e5b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component, target }) { + const options = target.querySelectorAll('option'); + + assert.equal(options[0].selected, true); + assert.equal(options[1].selected, false); + + // Shouldn't change the value because the value is not bound. + component.value = ['2']; + assert.equal(options[0].selected, true); + assert.equal(options[1].selected, false); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread/main.svelte new file mode 100644 index 000000000000..306f6f9a245d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-multiple-spread/main.svelte @@ -0,0 +1,7 @@ + + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/select-no-whitespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-no-whitespace/_config.js new file mode 100644 index 000000000000..c318d9da4e25 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-no-whitespace/_config.js @@ -0,0 +1,8 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, target }) { + const select = target.querySelector('select'); + assert.equal(select?.childNodes.length, 3); + } +}); diff --git a/test/runtime/samples/select-no-whitespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-no-whitespace/main.svelte similarity index 100% rename from test/runtime/samples/select-no-whitespace/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/select-no-whitespace/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object-multiple/_config.js new file mode 100644 index 000000000000..b737d420610a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object-multiple/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +const items = [{ id: 'a' }, { id: 'b' }]; + +export default test({ + get props() { + return { foo: [items[0]], items }; + }, + + test({ assert, component, target }) { + const options = target.querySelectorAll('option'); + + assert.equal(options[0].selected, true); + assert.equal(options[1].selected, false); + + component.foo = [component.items[1]]; + + assert.equal(options[0].selected, false); + assert.equal(options[1].selected, true); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object-multiple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object-multiple/main.svelte new file mode 100644 index 000000000000..830e1e74d5d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object-multiple/main.svelte @@ -0,0 +1,9 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object/_config.js new file mode 100644 index 000000000000..fde9c5625b83 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object/_config.js @@ -0,0 +1,21 @@ +import { test } from '../../test'; + +const items = [{ id: 'a' }, { id: 'b' }]; + +export default test({ + get props() { + return { foo: items[0], items }; + }, + + test({ assert, component, target }) { + const options = target.querySelectorAll('option'); + + assert.equal(options[0].selected, true); + assert.equal(options[1].selected, false); + + component.foo = component.items[1]; + + assert.equal(options[0].selected, false); + assert.equal(options[1].selected, true); + } +}); diff --git a/test/runtime/samples/select-one-way-bind-object/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object/main.svelte similarity index 100% rename from test/runtime/samples/select-one-way-bind-object/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/select-one-way-bind-object/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind/_config.js new file mode 100644 index 000000000000..31451a5429ee --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: 'a' }; + }, + + test({ assert, component, target }) { + const options = target.querySelectorAll('option'); + + assert.equal(options[0].selected, true); + assert.equal(options[1].selected, false); + + component.foo = 'b'; + + assert.equal(options[0].selected, false); + assert.equal(options[1].selected, true); + } +}); diff --git a/test/runtime/samples/select-one-way-bind/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-one-way-bind/main.svelte similarity index 100% rename from test/runtime/samples/select-one-way-bind/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/select-one-way-bind/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/select-options-spread-attributes/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-options-spread-attributes/_config.js new file mode 100644 index 000000000000..df0e94b7da72 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-options-spread-attributes/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/select-options-spread-attributes/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-options-spread-attributes/main.svelte new file mode 100644 index 000000000000..cabaf2ea0a7f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-options-spread-attributes/main.svelte @@ -0,0 +1,3 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/select-props/_config.js b/packages/svelte/tests/runtime-legacy/samples/select-props/_config.js new file mode 100644 index 000000000000..eb295e330738 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select-props/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component, window }) { + const selects = document.querySelectorAll('select'); + + const event1 = new window.Event('change'); + selects[0].value = 'b'; + selects[0].dispatchEvent(event1); + + const event2 = new window.Event('change'); + selects[1].value = 'b'; + selects[1].dispatchEvent(event2); + + assert.deepEqual(component.log, [1, 2]); + } +}); diff --git a/test/runtime/samples/select-props/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select-props/main.svelte similarity index 100% rename from test/runtime/samples/select-props/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/select-props/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/select/_config.js b/packages/svelte/tests/runtime-legacy/samples/select/_config.js new file mode 100644 index 000000000000..eb25616c17b9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/select/_config.js @@ -0,0 +1,30 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { item: { name: 'One', key: 'a' } }; + }, + + html: ` + + `, + + test({ assert, target }) { + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + + assert.equal(target.querySelector('select')?.value, 'a'); + } +}); diff --git a/test/runtime/samples/select/main.svelte b/packages/svelte/tests/runtime-legacy/samples/select/main.svelte similarity index 100% rename from test/runtime/samples/select/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/select/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/self-reference-component/Countdown.svelte b/packages/svelte/tests/runtime-legacy/samples/self-reference-component/Countdown.svelte new file mode 100644 index 000000000000..21178f25676a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/self-reference-component/Countdown.svelte @@ -0,0 +1,7 @@ + + +{#if count > 0} + +{/if} \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/self-reference-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/self-reference-component/_config.js new file mode 100644 index 000000000000..76536334b732 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/self-reference-component/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '5 4 3 2 1 0' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/self-reference-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/self-reference-component/main.svelte new file mode 100644 index 000000000000..0125e76e3fb7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/self-reference-component/main.svelte @@ -0,0 +1,10 @@ + + +{count} + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/self-reference-tree/_config.js b/packages/svelte/tests/runtime-legacy/samples/self-reference-tree/_config.js new file mode 100644 index 000000000000..5d8bacdb15f7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/self-reference-tree/_config.js @@ -0,0 +1,57 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + file: { + name: '/', + type: 'folder', + children: [ + { name: 'foo.jpg', type: 'image' }, + { name: 'bar.jpg', type: 'image' }, + { + name: 'baz', + type: 'folder', + children: [ + { name: '.DS_Store', type: 'junk' }, + { name: 'README.md', type: 'markdown' } + ] + } + ] + } + }; + }, + + html: ` +
      + / + +
        +
      • +
        + foo.jpg +
        +
      • +
        + bar.jpg +
        +
      • +
        + baz +
          +
        • +
          + .DS_Store +
          +
        • +
          + README.md +
          +
        • +
        +
        +
      • +
      +
      + ` +}); diff --git a/test/runtime/samples/self-reference-tree/main.svelte b/packages/svelte/tests/runtime-legacy/samples/self-reference-tree/main.svelte similarity index 100% rename from test/runtime/samples/self-reference-tree/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/self-reference-tree/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/self-reference/_config.js b/packages/svelte/tests/runtime-legacy/samples/self-reference/_config.js new file mode 100644 index 000000000000..ca4e11bf69e1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/self-reference/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { depth: 5 }; + }, + + html: ` + 5 + 4 + 3 + 2 + 1 + 0 + ` +}); diff --git a/test/runtime/samples/self-reference/main.svelte b/packages/svelte/tests/runtime-legacy/samples/self-reference/main.svelte similarity index 100% rename from test/runtime/samples/self-reference/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/self-reference/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/semicolon-hoisting/_config.js b/packages/svelte/tests/runtime-legacy/samples/semicolon-hoisting/_config.js new file mode 100644 index 000000000000..653ccc21927f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/semicolon-hoisting/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/semicolon-hoisting/main.svelte b/packages/svelte/tests/runtime-legacy/samples/semicolon-hoisting/main.svelte new file mode 100644 index 000000000000..234fa715d212 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/semicolon-hoisting/main.svelte @@ -0,0 +1,6 @@ + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/set-in-oncreate/_config.js b/packages/svelte/tests/runtime-legacy/samples/set-in-oncreate/_config.js new file mode 100644 index 000000000000..e68fc225d494 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/set-in-oncreate/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // uses oncreate + + html: '

      2

      ' +}); diff --git a/test/runtime/samples/set-in-oncreate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/set-in-oncreate/main.svelte similarity index 100% rename from test/runtime/samples/set-in-oncreate/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/set-in-oncreate/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/set-in-onstate-dedupes-renders/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/set-in-onstate-dedupes-renders/Widget.svelte new file mode 100644 index 000000000000..9a82a270722a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/set-in-onstate-dedupes-renders/Widget.svelte @@ -0,0 +1,12 @@ + + +
      {foo.x}
      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/set-in-onstate-dedupes-renders/_config.js b/packages/svelte/tests/runtime-legacy/samples/set-in-onstate-dedupes-renders/_config.js new file mode 100644 index 000000000000..f49209e53378 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/set-in-onstate-dedupes-renders/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + test({ component }) { + component.foo = { x: 2 }; + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/set-in-onstate-dedupes-renders/main.svelte b/packages/svelte/tests/runtime-legacy/samples/set-in-onstate-dedupes-renders/main.svelte new file mode 100644 index 000000000000..22c0cc825a83 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/set-in-onstate-dedupes-renders/main.svelte @@ -0,0 +1,12 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/set-in-onstate/_config.js b/packages/svelte/tests/runtime-legacy/samples/set-in-onstate/_config.js new file mode 100644 index 000000000000..a940a024b50e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/set-in-onstate/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      1

      +

      2

      + `, + + test({ assert, component, target }) { + component.foo = 2; + assert.htmlEqual( + target.innerHTML, + ` +

      2

      +

      4

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/set-in-onstate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/set-in-onstate/main.svelte new file mode 100644 index 000000000000..2c2353b2a016 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/set-in-onstate/main.svelte @@ -0,0 +1,11 @@ + + +

      {foo}

      +

      {bar}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/set-null-text-node/_config.js b/packages/svelte/tests/runtime-legacy/samples/set-null-text-node/_config.js new file mode 100644 index 000000000000..750ace567f1b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/set-null-text-node/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {number | null} */ + foo: null + }; + }, + + html: 'foo is ', + + test({ assert, component, target }) { + component.foo = 42; + assert.htmlEqual(target.innerHTML, 'foo is 42'); + + component.foo = null; + assert.htmlEqual(target.innerHTML, 'foo is '); + } +}); diff --git a/test/runtime/samples/set-null-text-node/main.svelte b/packages/svelte/tests/runtime-legacy/samples/set-null-text-node/main.svelte similarity index 100% rename from test/runtime/samples/set-null-text-node/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/set-null-text-node/main.svelte diff --git a/test/runtime/samples/set-prevents-loop/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/set-prevents-loop/Foo.svelte similarity index 100% rename from test/runtime/samples/set-prevents-loop/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/set-prevents-loop/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/set-prevents-loop/_config.js b/packages/svelte/tests/runtime-legacy/samples/set-prevents-loop/_config.js new file mode 100644 index 000000000000..f47bee71df87 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/set-prevents-loop/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/test/runtime/samples/set-prevents-loop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/set-prevents-loop/main.svelte similarity index 100% rename from test/runtime/samples/set-prevents-loop/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/set-prevents-loop/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/set-undefined-attr/_config.js b/packages/svelte/tests/runtime-legacy/samples/set-undefined-attr/_config.js new file mode 100644 index 000000000000..c7373116852e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/set-undefined-attr/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: "
      ", + + ssrHtml: "
      " +}); diff --git a/test/runtime/samples/set-undefined-attr/main.svelte b/packages/svelte/tests/runtime-legacy/samples/set-undefined-attr/main.svelte similarity index 100% rename from test/runtime/samples/set-undefined-attr/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/set-undefined-attr/main.svelte diff --git a/test/runtime/samples/shorthand-method-in-template/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/shorthand-method-in-template/Foo.svelte similarity index 100% rename from test/runtime/samples/shorthand-method-in-template/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/shorthand-method-in-template/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/shorthand-method-in-template/_config.js b/packages/svelte/tests/runtime-legacy/samples/shorthand-method-in-template/_config.js new file mode 100644 index 000000000000..69bd65817199 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/shorthand-method-in-template/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '42' +}); diff --git a/test/runtime/samples/shorthand-method-in-template/main.svelte b/packages/svelte/tests/runtime-legacy/samples/shorthand-method-in-template/main.svelte similarity index 100% rename from test/runtime/samples/shorthand-method-in-template/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/shorthand-method-in-template/main.svelte diff --git a/test/runtime/samples/sigil-component-attribute/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/sigil-component-prop/Widget.svelte similarity index 100% rename from test/runtime/samples/sigil-component-attribute/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/sigil-component-prop/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/sigil-component-prop/_config.js b/packages/svelte/tests/runtime-legacy/samples/sigil-component-prop/_config.js new file mode 100644 index 000000000000..cc15d2a2bfbe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/sigil-component-prop/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + get props() { + return { foo: 'foo' }; + }, + html: '
      foo @ foo # foo
      ' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/sigil-component-prop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/sigil-component-prop/main.svelte new file mode 100644 index 000000000000..28c66c5bd6e8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/sigil-component-prop/main.svelte @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/sigil-expression-function-body/_config.js b/packages/svelte/tests/runtime-legacy/samples/sigil-expression-function-body/_config.js new file mode 100644 index 000000000000..6a6e468471c8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/sigil-expression-function-body/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '@foo' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/sigil-expression-function-body/main.svelte b/packages/svelte/tests/runtime-legacy/samples/sigil-expression-function-body/main.svelte new file mode 100644 index 000000000000..074496d6f488 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/sigil-expression-function-body/main.svelte @@ -0,0 +1 @@ +{(() => '@foo')()} diff --git a/packages/svelte/tests/runtime-legacy/samples/sigil-static-at/_config.js b/packages/svelte/tests/runtime-legacy/samples/sigil-static-at/_config.js new file mode 100644 index 000000000000..6a6e468471c8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/sigil-static-at/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '@foo' +}); diff --git a/test/runtime/samples/sigil-static-@/main.svelte b/packages/svelte/tests/runtime-legacy/samples/sigil-static-at/main.svelte similarity index 100% rename from test/runtime/samples/sigil-static-@/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/sigil-static-at/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/sigil-static-hash/_config.js b/packages/svelte/tests/runtime-legacy/samples/sigil-static-hash/_config.js new file mode 100644 index 000000000000..b39cbf2b4ff9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/sigil-static-hash/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '#foo' +}); diff --git a/test/runtime/samples/sigil-static-#/main.svelte b/packages/svelte/tests/runtime-legacy/samples/sigil-static-hash/main.svelte similarity index 100% rename from test/runtime/samples/sigil-static-#/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/sigil-static-hash/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/single-static-element/_config.js b/packages/svelte/tests/runtime-legacy/samples/single-static-element/_config.js new file mode 100644 index 000000000000..6612be02675c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/single-static-element/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'test' +}); diff --git a/test/runtime/samples/single-static-element/main.svelte b/packages/svelte/tests/runtime-legacy/samples/single-static-element/main.svelte similarity index 100% rename from test/runtime/samples/single-static-element/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/single-static-element/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/single-text-node/_config.js b/packages/svelte/tests/runtime-legacy/samples/single-text-node/_config.js new file mode 100644 index 000000000000..25b5e84cd4f4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/single-text-node/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'text' +}); diff --git a/test/runtime/samples/single-text-node/main.svelte b/packages/svelte/tests/runtime-legacy/samples/single-text-node/main.svelte similarity index 100% rename from test/runtime/samples/single-text-node/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/single-text-node/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-children-prop/A.svelte b/packages/svelte/tests/runtime-legacy/samples/slot-children-prop/A.svelte new file mode 100644 index 000000000000..32735e38d6fa --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-children-prop/A.svelte @@ -0,0 +1,6 @@ + + +{children} + diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-children-prop/_config.js b/packages/svelte/tests/runtime-legacy/samples/slot-children-prop/_config.js new file mode 100644 index 000000000000..48b7168f308c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-children-prop/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `foo bar foo` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-children-prop/main.svelte b/packages/svelte/tests/runtime-legacy/samples/slot-children-prop/main.svelte new file mode 100644 index 000000000000..63c5cc3aae74 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-children-prop/main.svelte @@ -0,0 +1,9 @@ + + + + bar + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-if-block-update-no-anchor/_config.js b/packages/svelte/tests/runtime-legacy/samples/slot-if-block-update-no-anchor/_config.js new file mode 100644 index 000000000000..1ee12868a171 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-if-block-update-no-anchor/_config.js @@ -0,0 +1,12 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { enabled: false }; + }, + test({ assert, target, component }) { + assert.htmlEqual(target.innerHTML, ''); + component.enabled = true; + assert.htmlEqual(target.innerHTML, 'enabled'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-if-block-update-no-anchor/main.svelte b/packages/svelte/tests/runtime-legacy/samples/slot-if-block-update-no-anchor/main.svelte new file mode 100644 index 000000000000..7960f35bc9cd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-if-block-update-no-anchor/main.svelte @@ -0,0 +1,9 @@ + + + + + {#if enabled}enabled{/if} + + diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-in-custom-element/_config.js b/packages/svelte/tests/runtime-legacy/samples/slot-in-custom-element/_config.js new file mode 100644 index 000000000000..cd56b57c7490 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-in-custom-element/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` + +
      header header header
      +
      + ` +}); diff --git a/test/runtime/samples/slot-in-custom-element/main.svelte b/packages/svelte/tests/runtime-legacy/samples/slot-in-custom-element/main.svelte similarity index 100% rename from test/runtime/samples/slot-in-custom-element/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/slot-in-custom-element/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-in-dynamic-element/_config.js b/packages/svelte/tests/runtime-legacy/samples/slot-in-dynamic-element/_config.js new file mode 100644 index 000000000000..e5e7c45095db --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-in-dynamic-element/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` + +
      header header header
      +
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-in-dynamic-element/main.svelte b/packages/svelte/tests/runtime-legacy/samples/slot-in-dynamic-element/main.svelte new file mode 100644 index 000000000000..38d7cd233e80 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-in-dynamic-element/main.svelte @@ -0,0 +1,7 @@ + + + +
      header header header
      +
      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/_config.js b/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/_config.js new file mode 100644 index 000000000000..f48317749c45 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: `
      5
      ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/inner.svelte b/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/inner.svelte new file mode 100644 index 000000000000..c9b3506291c0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/inner.svelte @@ -0,0 +1,3 @@ +
      + +
      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/main.svelte b/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/main.svelte new file mode 100644 index 000000000000..366234f33b53 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/main.svelte @@ -0,0 +1,9 @@ + + + +
      + {foo} +
      +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/outer.svelte b/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/outer.svelte new file mode 100644 index 000000000000..95f819eb1507 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-let-forwarding/outer.svelte @@ -0,0 +1,9 @@ + + + + + {foo} + + diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-svg/_config.js b/packages/svelte/tests/runtime-legacy/samples/slot-svg/_config.js new file mode 100644 index 000000000000..de80ebe35153 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-svg/_config.js @@ -0,0 +1,9 @@ +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, target }) { + const circle = target.querySelector('circle'); + ok(circle); + assert.equal(circle.namespaceURI, 'http://www.w3.org/2000/svg'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-svg/main.svelte b/packages/svelte/tests/runtime-legacy/samples/slot-svg/main.svelte new file mode 100644 index 000000000000..faf271a00f15 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-svg/main.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/slot-svg/points.svelte b/packages/svelte/tests/runtime-legacy/samples/slot-svg/points.svelte new file mode 100644 index 000000000000..eb580cf793c2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot-svg/points.svelte @@ -0,0 +1,3 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/slot/A.svelte b/packages/svelte/tests/runtime-legacy/samples/slot/A.svelte new file mode 100644 index 000000000000..35a05a209a94 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot/A.svelte @@ -0,0 +1,31 @@ + + + + + +$$slots: {toString($$slots)} + +{#if $$slots.b} +
      + +
      +{:else} + Slot b is not available +{/if} diff --git a/packages/svelte/tests/runtime-legacy/samples/slot/_config.js b/packages/svelte/tests/runtime-legacy/samples/slot/_config.js new file mode 100644 index 000000000000..58eccd05c48b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + html: ` + byeworld + hello world + $$slots: {"a":true,"default":true} + Slot b is not available + + bye world + hello world + $$slots: {"a":true,"b":true,"default":true} +
      hello world
      + `, + + async test({ assert, component }) { + assert.equal(component.getA(), ''); + assert.equal(component.getB(), 'foo'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/slot/main.svelte b/packages/svelte/tests/runtime-legacy/samples/slot/main.svelte new file mode 100644 index 000000000000..4e53108ce042 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/slot/main.svelte @@ -0,0 +1,23 @@ + + +
      + hello world + bye + world + + + + hello world + hello world + bye world + diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-2/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-2/Widget.svelte new file mode 100644 index 000000000000..ae27aeb5e531 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-2/Widget.svelte @@ -0,0 +1,13 @@ + + +

      foo: {foo}

      +

      baz: {baz} ({typeof baz})

      +

      qux: {qux}

      +

      quux: {quux}

      +

      selected: {selected}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component-2/_config.js new file mode 100644 index 000000000000..81a941a0e368 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-2/_config.js @@ -0,0 +1,92 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + list: [ + { + foo: 'lol', + baz: 40 + 2, + qux: 5, + quux: 'core' + }, + { + foo: 'lolzz', + baz: 50 + 2, + qux: 1, + quux: 'quuxx' + } + ] + }; + }, + + html: ` +
      +

      foo: lol

      +

      baz: 42 (number)

      +

      qux: 0

      +

      quux: core

      +

      selected: true

      +

      foo: lolzz

      +

      baz: 52 (number)

      +

      qux: 0

      +

      quux: quuxx

      +

      selected: false

      +
      + `, + + test({ assert, component, target }) { + component.list = [ + { + foo: 'lol', + baz: 40 + 3, + qux: 8, + quux: 'heart' + }, + { + foo: 'lolzz', + baz: 50 + 3, + qux: 8, + quux: 'heartxx' + } + ]; + + assert.htmlEqual( + target.innerHTML, + ` +
      +

      foo: lol

      +

      baz: 43 (number)

      +

      qux: 0

      +

      quux: heart

      +

      selected: true

      +

      foo: lolzz

      +

      baz: 53 (number)

      +

      qux: 0

      +

      quux: heartxx

      +

      selected: false

      +
      + ` + ); + + component.qux = 1; + + assert.htmlEqual( + target.innerHTML, + ` +
      +

      foo: lol

      +

      baz: 43 (number)

      +

      qux: 1

      +

      quux: heart

      +

      selected: false

      +

      foo: lolzz

      +

      baz: 53 (number)

      +

      qux: 1

      +

      quux: heartxx

      +

      selected: true

      +
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-2/main.svelte new file mode 100644 index 000000000000..436e11f9c50d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-2/main.svelte @@ -0,0 +1,12 @@ + + +
      + {#each list as item, index (item.foo)} + + {/each} +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object-multiple-dependencies/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object-multiple-dependencies/Widget.svelte new file mode 100644 index 000000000000..3433ffc24360 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object-multiple-dependencies/Widget.svelte @@ -0,0 +1,11 @@ + + +

      foo: {foo}

      +

      baz: {baz}

      +

      qux: {qux}

      +

      corge: {corge}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object-multiple-dependencies/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object-multiple-dependencies/_config.js new file mode 100644 index 000000000000..cbc93cceb850 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object-multiple-dependencies/_config.js @@ -0,0 +1,61 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { props: { foo: 'lol', baz: 40 + 2 } }; + }, + + html: ` +

      foo: lol

      +

      baz: 42

      +

      qux: named

      +

      corge: b

      + `, + + test({ assert, component, target }) { + const html = ` +

      foo:

      +

      baz:

      +

      qux: named

      +

      corge: b

      + `; + + // test undefined + // @ts-ignore + component.props = undefined; + assert.htmlEqual(target.innerHTML, html); + + // set object props + // @ts-ignore + component.props = this.props.props; + // @ts-ignore + assert.htmlEqual(target.innerHTML, this.html); + + // test null + // @ts-ignore + component.props = null; + assert.htmlEqual(target.innerHTML, html); + + // set object props + // @ts-ignore + component.props = this.props.props; + // @ts-ignore + assert.htmlEqual(target.innerHTML, this.html); + + // test boolean + // @ts-ignore + component.props = true; + assert.htmlEqual(target.innerHTML, html); + + // set object props + // @ts-ignore + component.props = this.props.props; + // @ts-ignore + assert.htmlEqual(target.innerHTML, this.html); + + // test number + // @ts-ignore + component.props = 123; + assert.htmlEqual(target.innerHTML, html); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object-multiple-dependencies/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object-multiple-dependencies/main.svelte new file mode 100644 index 000000000000..5f9f9cbff02a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object-multiple-dependencies/main.svelte @@ -0,0 +1,13 @@ + + +
      + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object/Widget.svelte new file mode 100644 index 000000000000..bc168d495672 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object/Widget.svelte @@ -0,0 +1,9 @@ + + +

      foo: {foo}

      +

      baz: {baz}

      +

      qux: {qux}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object/_config.js new file mode 100644 index 000000000000..759ed2b048e4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object/_config.js @@ -0,0 +1,59 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { props: { foo: 'lol', baz: 40 + 2 } }; + }, + + html: ` +

      foo: lol

      +

      baz: 42

      +

      qux: named

      + `, + + test({ assert, component, target }) { + const html = ` +

      foo:

      +

      baz:

      +

      qux: named

      + `; + + // test undefined + // @ts-ignore + component.props = undefined; + assert.htmlEqual(target.innerHTML, html); + + // set object props + // @ts-ignore + component.props = this.props.props; + // @ts-ignore + assert.htmlEqual(target.innerHTML, this.html); + + // test null + // @ts-ignore + component.props = null; + assert.htmlEqual(target.innerHTML, html); + + // set object props + // @ts-ignore + component.props = this.props.props; + // @ts-ignore + assert.htmlEqual(target.innerHTML, this.html); + + // test boolean + // @ts-ignore + component.props = true; + assert.htmlEqual(target.innerHTML, html); + + // set object props + // @ts-ignore + component.props = this.props.props; + // @ts-ignore + assert.htmlEqual(target.innerHTML, this.html); + + // test number + // @ts-ignore + component.props = 123; + assert.htmlEqual(target.innerHTML, html); + } +}); diff --git a/test/runtime/samples/spread-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object/main.svelte similarity index 100% rename from test/runtime/samples/spread-component/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-non-object/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-undefined/_config.js new file mode 100644 index 000000000000..636163911a6f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-undefined/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { props: { a: 1 } }; + }, + + html: '', + + test({ assert, component, target }) { + component.props = { + a: 2 + }; + + assert.htmlEqual(target.innerHTML, ''); + } +}); diff --git a/test/runtime/samples/spread-component-dynamic-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-undefined/main.svelte similarity index 100% rename from test/runtime/samples/spread-component-dynamic-undefined/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic-undefined/main.svelte diff --git a/test/runtime/samples/spread-component-dynamic/Foo.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic/Foo.svelte similarity index 100% rename from test/runtime/samples/spread-component-dynamic/Foo.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic/Foo.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic/_config.js new file mode 100644 index 000000000000..1440ac072cdd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic/_config.js @@ -0,0 +1,19 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { props: { a: 1 } }; + }, + + html: ` +

      a: 1

      + `, + + test({ assert, component, target }) { + component.props = { + a: 2 + }; + + assert.htmlEqual(target.innerHTML, '

      a: 2

      '); + } +}); diff --git a/test/runtime/samples/spread-component-dynamic/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic/main.svelte similarity index 100% rename from test/runtime/samples/spread-component-dynamic/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-component-dynamic/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-immutable/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-immutable/Widget.svelte new file mode 100644 index 000000000000..c57eff55ebc0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-immutable/Widget.svelte @@ -0,0 +1 @@ +Hello World! \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-immutable/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component-immutable/_config.js new file mode 100644 index 000000000000..047171285e62 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-immutable/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +const obj = { + x: 1, + y: 2, + z: 3 +}; + +export default test({ + get props() { + return { obj }; + }, + + test({ assert }) { + assert.deepEqual(obj, { x: 1, y: 2, z: 3 }); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-immutable/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-immutable/main.svelte new file mode 100644 index 000000000000..44e09548568e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-immutable/main.svelte @@ -0,0 +1,7 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-literal/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-literal/Widget.svelte new file mode 100644 index 000000000000..e00796baf3ef --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-literal/Widget.svelte @@ -0,0 +1,5 @@ + + +

      foo: {foo}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-literal/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component-literal/_config.js new file mode 100644 index 000000000000..86fe68a02b59 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-literal/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      foo: bar

      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-literal/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-literal/main.svelte new file mode 100644 index 000000000000..13fdf99b696a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-literal/main.svelte @@ -0,0 +1,7 @@ + + +
      + +
      diff --git a/test/runtime/samples/spread-component-multiple-dependencies/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-multiple-dependencies/Widget.svelte similarity index 100% rename from test/runtime/samples/spread-component-multiple-dependencies/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-component-multiple-dependencies/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-multiple-dependencies/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component-multiple-dependencies/_config.js new file mode 100644 index 000000000000..25108a534ddc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-multiple-dependencies/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: 'b baz', + test({ assert, component, target }) { + component.foo = true; + assert.htmlEqual(target.innerHTML, 'a baz'); + } +}); diff --git a/test/runtime/samples/spread-component-multiple-dependencies/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-multiple-dependencies/main.svelte similarity index 100% rename from test/runtime/samples/spread-component-multiple-dependencies/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-component-multiple-dependencies/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-side-effects/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-side-effects/Widget.svelte new file mode 100644 index 000000000000..69349e66b42a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-side-effects/Widget.svelte @@ -0,0 +1,9 @@ + + +

      i: {i}

      +

      foo: {foo}

      +

      qux: {qux}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-side-effects/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component-side-effects/_config.js new file mode 100644 index 000000000000..4655f0764db0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-side-effects/_config.js @@ -0,0 +1,26 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return {}; + }, + + html: ` +

      i: 1

      +

      foo: foo

      +

      qux: named

      + `, + + test({ assert, component, target }) { + component.foo = 'lol'; + + assert.htmlEqual( + target.innerHTML, + ` +

      i: 2

      +

      foo: lol

      +

      qux: named

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-side-effects/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-side-effects/main.svelte new file mode 100644 index 000000000000..8c2dcfd2c317 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-side-effects/main.svelte @@ -0,0 +1,16 @@ + + +
      + +
      diff --git a/test/runtime/samples/spread-component-with-bind/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-with-bind/Widget.svelte similarity index 100% rename from test/runtime/samples/spread-component-with-bind/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-component-with-bind/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component-with-bind/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component-with-bind/_config.js new file mode 100644 index 000000000000..3dbf2d3e58b7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component-with-bind/_config.js @@ -0,0 +1,31 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + html: ` +

      foo

      + + `, + + ssrHtml: ` +

      foo

      + + `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + input.value = 'bar'; + input.dispatchEvent(new window.Event('input')); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      bar

      + + ` + ); + } +}); diff --git a/test/runtime/samples/spread-component-with-bind/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component-with-bind/main.svelte similarity index 100% rename from test/runtime/samples/spread-component-with-bind/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-component-with-bind/main.svelte diff --git a/test/runtime/samples/spread-component/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component/Widget.svelte similarity index 100% rename from test/runtime/samples/spread-component/Widget.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-component/Widget.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-component/_config.js new file mode 100644 index 000000000000..5d8830594a64 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component/_config.js @@ -0,0 +1,40 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + props: { + foo: 'lol', + baz: 40 + 2, + qux: `this is a ${'piece of'} string`, + quux: 'core' + } + }; + }, + + html: ` +

      foo: lol

      +

      baz: 42 (number)

      +

      qux: named

      +

      quux: core

      + `, + + test({ assert, component, target }) { + component.props = { + foo: 'wut', + baz: 40 + 3, + qux: `this is a ${'rather boring'} string`, + quux: 'heart' + }; + + assert.htmlEqual( + target.innerHTML, + ` +

      foo: wut

      +

      baz: 43 (number)

      +

      qux: named

      +

      quux: heart

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-component/main.svelte new file mode 100644 index 000000000000..3ca281903e3a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-component/main.svelte @@ -0,0 +1,9 @@ + + +
      + +
      diff --git a/test/runtime/samples/spread-each-component/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-each-component/Nested.svelte similarity index 100% rename from test/runtime/samples/spread-each-component/Nested.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-each-component/Nested.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-each-component/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-each-component/_config.js new file mode 100644 index 000000000000..4498fb40ba1f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-each-component/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      +
      + `, + + get props() { + return { + things: [ + { a: 1, b: 2 }, + { a: 3, b: 4 } + ] + }; + }, + + test({ assert, component, target }) { + const { things } = component; + + component.things = things.reverse(); + + assert.htmlEqual( + target.innerHTML, + ` +
      +
      + ` + ); + } +}); diff --git a/test/runtime/samples/spread-each-component/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-each-component/main.svelte similarity index 100% rename from test/runtime/samples/spread-each-component/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-each-component/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-each-element/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-each-element/_config.js new file mode 100644 index 000000000000..841be0896be2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-each-element/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      +
      + `, + + get props() { + return { + things: [ + { 'data-a': 1, 'data-b': 2 }, + { 'data-c': 3, 'data-d': 4 } + ] + }; + }, + + test({ assert, component, target }) { + const { things } = component; + + component.things = things.reverse(); + + assert.htmlEqual( + target.innerHTML, + ` +
      +
      + ` + ); + } +}); diff --git a/test/runtime/samples/spread-each-element/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-each-element/main.svelte similarity index 100% rename from test/runtime/samples/spread-each-element/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-each-element/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-boolean/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-boolean/_config.js new file mode 100644 index 000000000000..5219f3804834 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-boolean/_config.js @@ -0,0 +1,23 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { props: { disabled: true } }; + }, + + html: ` + + `, + + test({ assert, component, target }) { + const button = target.querySelector('button'); + ok(button); + + assert.ok(button.disabled); + + component.props = { disabled: false }; + + assert.htmlEqual(target.innerHTML, ''); + assert.ok(!button.disabled); + } +}); diff --git a/test/runtime/samples/spread-element-boolean/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-boolean/main.svelte similarity index 100% rename from test/runtime/samples/spread-element-boolean/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-element-boolean/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-class/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-class/_config.js new file mode 100644 index 000000000000..03177213b594 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-class/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: "
      hello
      ", + test({ assert, component, target }) { + component.blah = 'goodbye'; + assert.htmlEqual(target.innerHTML, "
      goodbye
      "); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-class/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-class/main.svelte new file mode 100644 index 000000000000..9d6ff48e1b05 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-class/main.svelte @@ -0,0 +1,14 @@ + + +
      {blah}
      + + diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-bind-group-with-value-attr/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-bind-group-with-value-attr/_config.js new file mode 100644 index 000000000000..747e15f378a1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-bind-group-with-value-attr/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { props: { 'data-foo': 'bar' } }; + }, + + html: '', + + async test({ assert, target }) { + const input = /** @type {HTMLInputElement & { __value: string }} */ ( + target.querySelector('input') + ); + assert.equal(input.value, 'abc'); + assert.equal(input.__value, 'abc'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-bind-group-with-value-attr/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-bind-group-with-value-attr/main.svelte new file mode 100644 index 000000000000..ce6b76f0932f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-bind-group-with-value-attr/main.svelte @@ -0,0 +1,6 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-each-block-keyed/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-each-block-keyed/_config.js new file mode 100644 index 000000000000..cb418a6af3ba --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-each-block-keyed/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + test({ assert, component, target }) { + const [input1, input2] = target.querySelectorAll('input'); + assert.equal(input1.value, 'value1'); + assert.equal(input2.value, 'value2'); + + component.items = component.items.reverse(); + assert.equal(input1.value, 'value1'); + assert.equal(input2.value, 'value2'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-each-block-keyed/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-each-block-keyed/main.svelte new file mode 100644 index 000000000000..b89a40049567 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-each-block-keyed/main.svelte @@ -0,0 +1,7 @@ + + +{#each items as item (item)} + +{/each} diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select-multiple/_config.js new file mode 100644 index 000000000000..cdbf94ace594 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select-multiple/_config.js @@ -0,0 +1,45 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, component, target, window }) { + const [input1, input2] = target.querySelectorAll('input'); + const select = target.querySelector('select'); + ok(select); + const [option1, option2] = /** @type {NodeListOf} */ (select.childNodes); + + let selections = Array.from(select.selectedOptions); + assert.equal(selections.length, 2); + assert.ok(selections.includes(option1)); + assert.ok(selections.includes(option2)); + + const event = new window.Event('change'); + + input1.checked = false; + input1.dispatchEvent(event); + flushSync(); + + selections = Array.from(select.selectedOptions); + assert.equal(selections.length, 1); + assert.ok(!selections.includes(option1)); + assert.ok(selections.includes(option2)); + + input2.checked = false; + input2.dispatchEvent(event); + flushSync(); + input1.checked = true; + input1.dispatchEvent(event); + flushSync(); + selections = Array.from(select.selectedOptions); + assert.equal(selections.length, 1); + assert.ok(selections.includes(option1)); + assert.ok(!selections.includes(option2)); + + component.spread = { value: ['Hello', 'World'] }; + + selections = Array.from(select.selectedOptions); + assert.equal(selections.length, 2); + assert.ok(selections.includes(option1)); + assert.ok(selections.includes(option2)); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select-multiple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select-multiple/main.svelte new file mode 100644 index 000000000000..d2fb12dd204d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select-multiple/main.svelte @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select/_config.js new file mode 100644 index 000000000000..12161a7747b8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select/_config.js @@ -0,0 +1,29 @@ +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + const select = target.querySelector('select'); + ok(select); + const [option1, option2] = select; + + let selections = Array.from(select.selectedOptions); + + assert.equal(selections.length, 1); + assert.ok(!selections.includes(option1)); + assert.ok(selections.includes(option2)); + + component.value = 'Hello'; + + selections = Array.from(select.selectedOptions); + assert.equal(selections.length, 1); + assert.ok(selections.includes(option1)); + assert.ok(!selections.includes(option2)); + + component.spread = { value: 'World' }; + + selections = Array.from(select.selectedOptions); + assert.equal(selections.length, 1); + assert.ok(!selections.includes(option1)); + assert.ok(selections.includes(option2)); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select/main.svelte new file mode 100644 index 000000000000..41554d794f71 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-select/main.svelte @@ -0,0 +1,9 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value-undefined/_config.js new file mode 100644 index 000000000000..cc8488915a54 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value-undefined/_config.js @@ -0,0 +1,16 @@ +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + const input = target.querySelector('input'); + ok(input); + + component.value = undefined; + + assert.equal(input.value, ''); + + component.value = 'foobar'; + + assert.equal(input.value, 'foobar'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value-undefined/main.svelte new file mode 100644 index 000000000000..5c9121dc031a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value-undefined/main.svelte @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/InputOne.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/InputOne.svelte new file mode 100644 index 000000000000..92ecb7b9a98a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/InputOne.svelte @@ -0,0 +1,18 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/InputTwo.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/InputTwo.svelte new file mode 100644 index 000000000000..33ec0622a46a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/InputTwo.svelte @@ -0,0 +1,19 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/_config.js new file mode 100644 index 000000000000..46d493418175 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/_config.js @@ -0,0 +1,73 @@ +import { test } from '../../test'; + +export default test({ + async test({ assert, component, target, window }) { + const [input1, input2] = target.querySelectorAll('input'); + + // we are not able emulate user interaction in jsdom, + // therefore, jsdom could not validate minlength / maxlength + + // we simulate user input with + // setting input.value + dispatchEvent + + // and we determine if svelte does not set the `input.value` again by + // spying on the setter of `input.value` + + const spy1 = spyOnValueSetter(input1, input1.value); + const spy2 = spyOnValueSetter(input2, input2.value); + + const event = new window.Event('input'); + + input1.value = '12345'; + spy1.reset(); + await input1.dispatchEvent(event); + + // In Svelte 5, the value will always fire as the effects for setting + // the value and spreading happen in different parts. + + // assert.ok(!spy1.isSetCalled()); + + input2.value = '12345'; + spy2.reset(); + await input2.dispatchEvent(event); + + // Same as above. + // assert.ok(!spy2.isSetCalled()); + + spy1.reset(); + component.val1 = '56789'; + assert.ok(spy1.isSetCalled()); + + spy2.reset(); + component.val2 = '56789'; + // Same as above. + // assert.ok(spy2.isSetCalled()); + } +}); + +/** + * @param {HTMLInputElement} input + * @param {string} initialValue + */ +function spyOnValueSetter(input, initialValue) { + let value = initialValue; + let isSet = false; + Object.defineProperty(input, 'value', { + get() { + return value; + }, + set(_value) { + value = _value; + isSet = true; + } + }); + + return { + isSetCalled() { + return isSet; + }, + reset() { + isSet = false; + } + }; +} diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/main.svelte new file mode 100644 index 000000000000..bb5f0e00bf48 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/main.svelte @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/utils.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/utils.js new file mode 100644 index 000000000000..ee941bda5545 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input-value/utils.js @@ -0,0 +1,6 @@ +export function omit(obj, ...keysToOmit) { + return Object.keys(obj).reduce((acc, key) => { + if (keysToOmit.indexOf(key) === -1) acc[key] = obj[key]; + return acc; + }, {}); +} diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-input/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-input/_config.js new file mode 100644 index 000000000000..5f7b1cde2dc8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-input/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { props: { 'data-foo': 'bar' } }; + }, + + html: '' +}); diff --git a/test/runtime/samples/spread-element-input/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-input/main.svelte similarity index 100% rename from test/runtime/samples/spread-element-input/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-element-input/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-multiple-dependencies/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-multiple-dependencies/_config.js new file mode 100644 index 000000000000..70ca3d908ff4 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-multiple-dependencies/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: "
      ", + test({ assert, component, target }) { + component.foo = true; + assert.htmlEqual(target.innerHTML, "
      "); + } +}); diff --git a/test/runtime/samples/spread-element-multiple-dependencies/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-multiple-dependencies/main.svelte similarity index 100% rename from test/runtime/samples/spread-element-multiple-dependencies/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-element-multiple-dependencies/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-multiple/_config.js new file mode 100644 index 000000000000..f15ede7a53b6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-multiple/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { + /** @type {Record} */ + a: { 'data-one': 1, 'data-two': 2 }, + /** @type {Record} */ + c: { 'data-b': 'overridden' }, + d: 'deeeeee' + }; + }, + + html: ` +
      test
      + `, + + test({ assert, component, target }) { + component.a = { + 'data-one': 10 + }; + component.c = { + 'data-c': 'new' + }; + component.d = 'DEEEEEE'; + + assert.htmlEqual( + target.innerHTML, + '
      test
      ' + ); + } +}); diff --git a/test/runtime/samples/spread-element-multiple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-multiple/main.svelte similarity index 100% rename from test/runtime/samples/spread-element-multiple/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/spread-element-multiple/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-readonly/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-readonly/_config.js new file mode 100644 index 000000000000..57f88880e993 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-readonly/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + mode: ['client', 'hydrate'], // DOM and SSR output is different, a separate SSR test exists + html: '', + + test({ assert, target }) { + const div = /** @type {HTMLDivElement & { value: string }} */ (target.querySelector('input')); + assert.equal(div.value, 'bar'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-readonly/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-readonly/main.svelte new file mode 100644 index 000000000000..fc8c849396bc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-readonly/main.svelte @@ -0,0 +1,9 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-removal/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-removal/_config.js new file mode 100644 index 000000000000..cff03c22165e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-removal/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-removal/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-removal/main.svelte new file mode 100644 index 000000000000..f6adc82c80ab --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-removal/main.svelte @@ -0,0 +1 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-scope/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-scope/_config.js new file mode 100644 index 000000000000..525b27712c2f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-scope/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` +
      red
      +
      red
      +
      red and bold
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-scope/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-scope/main.svelte new file mode 100644 index 000000000000..7a25f90939d1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-scope/main.svelte @@ -0,0 +1,10 @@ + + +
      red
      + +
      red
      + +
      red and bold
      diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-select-value-undefined/Select.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-select-value-undefined/Select.svelte new file mode 100644 index 000000000000..6f5dadf00101 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-select-value-undefined/Select.svelte @@ -0,0 +1,12 @@ + + + +

      {label}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-select-value-undefined/_config.js b/packages/svelte/tests/runtime-legacy/samples/spread-element-select-value-undefined/_config.js new file mode 100644 index 000000000000..cce86ffeddf3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-select-value-undefined/_config.js @@ -0,0 +1,14 @@ +import { ok, test } from '../../test'; + +export default test({ + async test({ assert, component, target }) { + const select = target.querySelector('select'); + ok(select); + + assert.equal(select.value, '1'); + + component.label = 'hoge'; + + assert.equal(select.value, '1'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/spread-element-select-value-undefined/main.svelte b/packages/svelte/tests/runtime-legacy/samples/spread-element-select-value-undefined/main.svelte new file mode 100644 index 000000000000..57a2e3cf3eba --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/spread-element-select-value-undefined/main.svelte @@ -0,0 +1,11 @@ + + + + Dirty: false + Valid: false + `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + input.value = 'foo'; + const inputEvent = new window.InputEvent('input'); + + flushSync(() => input.dispatchEvent(inputEvent)); + + assert.htmlEqual( + target.innerHTML, + ` + + Dirty: true + Valid: true + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-event-callback/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-event-callback/main.svelte new file mode 100644 index 000000000000..eca7c202cdf3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-event-callback/main.svelte @@ -0,0 +1,29 @@ + + + + +Dirty: {$validity.dirty} +Valid: {$validity.valid} diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-immediate-multiple-vars/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-immediate-multiple-vars/_config.js new file mode 100644 index 000000000000..caf8e23a0113 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-immediate-multiple-vars/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      42

      + `, + + async test({ assert, component }) { + assert.equal(component.initial_foo, 42); + } +}); diff --git a/test/runtime/samples/store-auto-subscribe-immediate-multiple-vars/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-immediate-multiple-vars/main.svelte similarity index 100% rename from test/runtime/samples/store-auto-subscribe-immediate-multiple-vars/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-immediate-multiple-vars/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-immediate/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-immediate/_config.js new file mode 100644 index 000000000000..caf8e23a0113 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-immediate/_config.js @@ -0,0 +1,11 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      42

      + `, + + async test({ assert, component }) { + assert.equal(component.initial_foo, 42); + } +}); diff --git a/test/runtime/samples/store-auto-subscribe-immediate/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-immediate/main.svelte similarity index 100% rename from test/runtime/samples/store-auto-subscribe-immediate/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-immediate/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-implicit/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-implicit/_config.js new file mode 100644 index 000000000000..a6be345b6b25 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-implicit/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; +import { writable } from 'svelte/store'; + +export default test({ + get props() { + return { count: writable(0) }; + }, + + html: ` + + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const click = new window.MouseEvent('click', { bubbles: true }); + + button.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + + component.count.set(42); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/store-auto-subscribe-implicit/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-implicit/main.svelte similarity index 100% rename from test/runtime/samples/store-auto-subscribe-implicit/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-implicit/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/App.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/App.svelte new file mode 100644 index 000000000000..250305b62c4d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/App.svelte @@ -0,0 +1,8 @@ + +
      {value}
      +
      {$store}
      diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/_config.js new file mode 100644 index 000000000000..d380150e55d8 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +
      Hello World
      +
      Hello World
      + `, + + test({ assert, component, target }) { + component.update_value('Hi Svelte'); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +
      Hi Svelte
      +
      Hi Svelte
      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/main.svelte new file mode 100644 index 000000000000..4e771617bbfb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration-2/main.svelte @@ -0,0 +1,12 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration/_config.js new file mode 100644 index 000000000000..f1ebc998da13 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration/_config.js @@ -0,0 +1,38 @@ +import { ok, test } from '../../test'; +import { writable } from 'svelte/store'; +import { flushSync } from 'svelte'; + +export default test({ + get props() { + return { count: writable(0) }; + }, + + html: ` + + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const click = new window.MouseEvent('click', { bubbles: true }); + + flushSync(() => button.dispatchEvent(click)); + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + + flushSync(() => component.count.set(42)); + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/store-auto-subscribe-in-reactive-declaration/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration/main.svelte similarity index 100% rename from test/runtime/samples/store-auto-subscribe-in-reactive-declaration/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-reactive-declaration/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-script/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-script/_config.js new file mode 100644 index 000000000000..ea9faae17802 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-script/_config.js @@ -0,0 +1,29 @@ +import { ok, test } from '../../test'; +import { writable } from 'svelte/store'; + +let count = writable(0); + +export default test({ + get props() { + count = writable(0); + return { count }; + }, + + html: ` + + `, + + async test({ assert, component, target, window }) { + assert.equal(component.get_count(), 0); + + const button = target.querySelector('button'); + ok(button); + const click = new window.MouseEvent('click', { bubbles: true }); + + await button.dispatchEvent(click); + assert.equal(component.get_count(), 1); + + await count.set(42); + assert.equal(component.get_count(), 42); + } +}); diff --git a/test/runtime/samples/store-auto-subscribe-in-script/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-script/main.svelte similarity index 100% rename from test/runtime/samples/store-auto-subscribe-in-script/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-in-script/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-missing-global-script/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-missing-global-script/_config.js new file mode 100644 index 000000000000..805ae4b096a7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-missing-global-script/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + error: 'missingGlobal is not defined' +}); diff --git a/test/runtime/samples/store-auto-subscribe-missing-global-script/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-missing-global-script/main.svelte similarity index 100% rename from test/runtime/samples/store-auto-subscribe-missing-global-script/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-missing-global-script/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-missing-global-template/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-missing-global-template/_config.js new file mode 100644 index 000000000000..805ae4b096a7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-missing-global-template/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + error: 'missingGlobal is not defined' +}); diff --git a/test/runtime/samples/store-auto-subscribe-missing-global-template/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-missing-global-template/main.svelte similarity index 100% rename from test/runtime/samples/store-auto-subscribe-missing-global-template/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-missing-global-template/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-nullish/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-nullish/_config.js new file mode 100644 index 000000000000..84ba03b50323 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-nullish/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; +import { writable } from 'svelte/store'; + +export default test({ + html: ` +

      + `, + async test({ assert, component, target }) { + component.store = writable('foo'); + assert.htmlEqual( + target.innerHTML, + ` +

      foo

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-nullish/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-nullish/main.svelte new file mode 100644 index 000000000000..9c1ed4a56094 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-nullish/main.svelte @@ -0,0 +1,5 @@ + + +

      {$store}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-removed-store/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-removed-store/_config.js new file mode 100644 index 000000000000..6878dd1bfc4e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-removed-store/_config.js @@ -0,0 +1,31 @@ +import { test } from '../../test'; +import { writable } from 'svelte/store'; + +export default test({ + html: ` +

      + `, + test({ assert, component, target }) { + component.store = writable('foo'); + assert.htmlEqual( + target.innerHTML, + ` +

      foo

      + ` + ); + component.store = undefined; + assert.htmlEqual( + target.innerHTML, + ` +

      + ` + ); + component.store = writable('bar'); + assert.htmlEqual( + target.innerHTML, + ` +

      bar

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-removed-store/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-removed-store/main.svelte new file mode 100644 index 000000000000..9c1ed4a56094 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe-removed-store/main.svelte @@ -0,0 +1,5 @@ + + +

      {$store}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe/_config.js new file mode 100644 index 000000000000..a6be345b6b25 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe/_config.js @@ -0,0 +1,40 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; +import { writable } from 'svelte/store'; + +export default test({ + get props() { + return { count: writable(0) }; + }, + + html: ` + + `, + + test({ assert, component, target, window }) { + const button = target.querySelector('button'); + ok(button); + + const click = new window.MouseEvent('click', { bubbles: true }); + + button.dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + + component.count.set(42); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + + ` + ); + } +}); diff --git a/test/runtime/samples/store-auto-subscribe/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe/main.svelte similarity index 100% rename from test/runtime/samples/store-auto-subscribe/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-auto-subscribe/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-dev-mode-error/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-dev-mode-error/_config.js new file mode 100644 index 000000000000..d74e70a74d8f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-dev-mode-error/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { + dev: true + }, + + get props() { + return { count: 0 }; + }, + + error: 'store_invalid_shape\n`count` is not a store with a `subscribe` method' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-dev-mode-error/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-dev-mode-error/main.svelte new file mode 100644 index 000000000000..13c0f4cf2926 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-dev-mode-error/main.svelte @@ -0,0 +1,5 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/store-each-binding-deep/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-each-binding-deep/_config.js new file mode 100644 index 000000000000..1134b20d0c5b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-each-binding-deep/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + const event = new window.Event('input'); + input.value = 'changed'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      changed

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-each-binding-deep/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-each-binding-deep/main.svelte new file mode 100644 index 000000000000..8f1cabf5b809 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-each-binding-deep/main.svelte @@ -0,0 +1,11 @@ + + +{#each $itemStore.prop.things as thing } + +{/each} + +

      {$itemStore.prop.things[0].name}

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/store-each-binding-destructuring/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-each-binding-destructuring/_config.js new file mode 100644 index 000000000000..1134b20d0c5b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-each-binding-destructuring/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + const event = new window.Event('input'); + input.value = 'changed'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      changed

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-each-binding-destructuring/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-each-binding-destructuring/main.svelte new file mode 100644 index 000000000000..0b68038e739a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-each-binding-destructuring/main.svelte @@ -0,0 +1,13 @@ + + +{#each $items as { text }} + +{/each} + +

      {$items[0].text}

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/store-each-binding/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-each-binding/_config.js new file mode 100644 index 000000000000..1134b20d0c5b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-each-binding/_config.js @@ -0,0 +1,22 @@ +import { flushSync } from 'svelte'; +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target, window }) { + const input = target.querySelector('input'); + ok(input); + + const event = new window.Event('input'); + input.value = 'changed'; + input.dispatchEvent(event); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` + +

      changed

      + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-each-binding/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-each-binding/main.svelte new file mode 100644 index 000000000000..917d5c2001c6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-each-binding/main.svelte @@ -0,0 +1,13 @@ + + +{#each $items as item} + +{/each} + +

      {$items[0].text}

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/store-imported-module/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-imported-module/_config.js new file mode 100644 index 000000000000..2b030088c9d3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-imported-module/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + html: ` +

      42

      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-imported-module/foo.js b/packages/svelte/tests/runtime-legacy/samples/store-imported-module/foo.js new file mode 100644 index 000000000000..b88c1cc5777c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-imported-module/foo.js @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export default writable(42); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-imported-module/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-imported-module/main.svelte new file mode 100644 index 000000000000..35986d43d53f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-imported-module/main.svelte @@ -0,0 +1,9 @@ + + + + +

      {answer}

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/store-imported/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-imported/_config.js new file mode 100644 index 000000000000..a87de0772935 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-imported/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { dev: true }, // tests `@validate_store` code generation + + html: ` +

      42

      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-imported/foo.js b/packages/svelte/tests/runtime-legacy/samples/store-imported/foo.js new file mode 100644 index 000000000000..b88c1cc5777c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-imported/foo.js @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export default writable(42); diff --git a/test/runtime/samples/store-imported/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-imported/main.svelte similarity index 100% rename from test/runtime/samples/store-imported/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-imported/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-imports-hoisted/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-imports-hoisted/_config.js new file mode 100644 index 000000000000..a87de0772935 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-imports-hoisted/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { dev: true }, // tests `@validate_store` code generation + + html: ` +

      42

      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-imports-hoisted/foo.js b/packages/svelte/tests/runtime-legacy/samples/store-imports-hoisted/foo.js new file mode 100644 index 000000000000..b88c1cc5777c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-imports-hoisted/foo.js @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export default writable(42); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-imports-hoisted/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-imports-hoisted/main.svelte new file mode 100644 index 000000000000..223572962e8c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-imports-hoisted/main.svelte @@ -0,0 +1,7 @@ + + +

      {answer}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/store-increment-updates-reactive/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-increment-updates-reactive/_config.js new file mode 100644 index 000000000000..89ff695d9dfb --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-increment-updates-reactive/_config.js @@ -0,0 +1,13 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: '0', + + test({ assert, component, target }) { + component.increment(); + flushSync(); + + assert.htmlEqual(target.innerHTML, '1'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-increment-updates-reactive/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-increment-updates-reactive/main.svelte new file mode 100644 index 000000000000..4085f69fb458 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-increment-updates-reactive/main.svelte @@ -0,0 +1,11 @@ + + +{$foo} diff --git a/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-1/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-1/_config.js new file mode 100644 index 000000000000..b66f9da8be4f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-1/_config.js @@ -0,0 +1,64 @@ +import { ok, test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + html: ` + +
      +
      simple
      + + `, + ssrHtml: ` + +
      +
      simple
      + + `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + const button = target.querySelector('button'); + ok(input); + ok(button); + + const inputEvent = new window.InputEvent('input'); + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + + input.value = 'foo'; + flushSync(() => input.dispatchEvent(inputEvent)); + + assert.htmlEqual( + target.innerHTML, + ` + +
      foo
      +
      foo
      + + ` + ); + + flushSync(() => button.dispatchEvent(clickEvent)); + assert.htmlEqual( + target.innerHTML, + ` + +
      foo
      +
      clicked
      + + ` + ); + + input.value = 'bar'; + flushSync(() => input.dispatchEvent(inputEvent)); + + assert.htmlEqual( + target.innerHTML, + ` + +
      bar
      +
      bar
      + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-1/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-1/main.svelte new file mode 100644 index 000000000000..f74808ee2ec0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-1/main.svelte @@ -0,0 +1,20 @@ + + + +
      {v}
      +
      {$s}
      + diff --git a/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-2/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-2/_config.js new file mode 100644 index 000000000000..4fd569df2cb2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-2/_config.js @@ -0,0 +1,64 @@ +import { ok, test } from '../../test'; +import { flushSync } from 'svelte'; + +export default test({ + html: ` +
      +
      simple
      + + + `, + ssrHtml: ` +
      +
      simple
      + + + `, + + test({ assert, target, window }) { + const input = target.querySelector('input'); + const button = target.querySelector('button'); + ok(input); + ok(button); + + const inputEvent = new window.InputEvent('input'); + const clickEvent = new window.MouseEvent('click', { bubbles: true }); + + input.value = 'foo'; + flushSync(() => input.dispatchEvent(inputEvent)); + + assert.htmlEqual( + target.innerHTML, + ` +
      foo
      +
      foo
      + + + ` + ); + + flushSync(() => button.dispatchEvent(clickEvent)); + assert.htmlEqual( + target.innerHTML, + ` +
      foo
      +
      clicked
      + + + ` + ); + + input.value = 'bar'; + flushSync(() => input.dispatchEvent(inputEvent)); + + assert.htmlEqual( + target.innerHTML, + ` +
      bar
      +
      bar
      + + + ` + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-2/main.svelte new file mode 100644 index 000000000000..83e13742ceb6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-invalidation-while-update-2/main.svelte @@ -0,0 +1,20 @@ + + +
      {v}
      +
      {$s}
      + + diff --git a/packages/svelte/tests/runtime-legacy/samples/store-reference/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-reference/_config.js new file mode 100644 index 000000000000..eceba7a93f8e --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-reference/_config.js @@ -0,0 +1,7 @@ +import { test } from '../../test'; + +export default test({ + compileOptions: { dev: true }, // tests `@validate_store` code generation + + html: `` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-reference/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-reference/main.svelte new file mode 100644 index 000000000000..2afc46d257b1 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-reference/main.svelte @@ -0,0 +1,12 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-b/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-b/_config.js new file mode 100644 index 000000000000..69bd65817199 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-b/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '42' +}); diff --git a/test/runtime/samples/store-resubscribe-b/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-b/main.svelte similarity index 100% rename from test/runtime/samples/store-resubscribe-b/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-resubscribe-b/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-c/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-c/_config.js new file mode 100644 index 000000000000..ac123bc5c86c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-c/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '31 42' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-c/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-c/main.svelte new file mode 100644 index 000000000000..c52a5402bd28 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-c/main.svelte @@ -0,0 +1,16 @@ + + +{$store1} +{$store2} diff --git a/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-export/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-export/_config.js new file mode 100644 index 000000000000..f1ba09f44796 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-export/_config.js @@ -0,0 +1,33 @@ +import { test } from '../../test'; + +let unsubscribeCalled = false; + +/** @param {any} val */ +const fakeStore = (val) => ({ + /** @param {(val: any) => void} cb */ + subscribe: (cb) => { + cb(val); + return { + unsubscribe: () => { + unsubscribeCalled = true; + } + }; + } +}); + +export default test({ + get props() { + return { foo: fakeStore(1) }; + }, + html: ` +

      1

      + `, + + async test({ assert, component, target }) { + component.foo = fakeStore(5); + + assert.htmlEqual(target.innerHTML, '

      5

      '); + + assert.ok(unsubscribeCalled); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-export/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-export/main.svelte new file mode 100644 index 000000000000..44b00544b7d9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-export/main.svelte @@ -0,0 +1,6 @@ + + +

      {$foo}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-observable/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-observable/_config.js new file mode 100644 index 000000000000..69bd65817199 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-observable/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: '42' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-observable/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-observable/main.svelte new file mode 100644 index 000000000000..4ea2112b112d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe-observable/main.svelte @@ -0,0 +1,11 @@ + + +{$foo} diff --git a/packages/svelte/tests/runtime-legacy/samples/store-resubscribe/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe/_config.js new file mode 100644 index 000000000000..5c9229e7cff2 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe/_config.js @@ -0,0 +1,51 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; + +export default test({ + html: ` +

      0

      + + + `, + + test({ assert, target, window }) { + const buttons = target.querySelectorAll('button'); + const click = new window.MouseEvent('click', { bubbles: true }); + + buttons[0].dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      1

      + + + ` + ); + + buttons[1].dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      0

      + + + ` + ); + + buttons[0].dispatchEvent(click); + flushSync(); + + assert.htmlEqual( + target.innerHTML, + ` +

      1

      + + + ` + ); + } +}); diff --git a/test/runtime/samples/store-resubscribe/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-resubscribe/main.svelte similarity index 100% rename from test/runtime/samples/store-resubscribe/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/store-resubscribe/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/store-shadow-scope-declaration/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-shadow-scope-declaration/_config.js new file mode 100644 index 000000000000..f47bee71df87 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-shadow-scope-declaration/_config.js @@ -0,0 +1,3 @@ +import { test } from '../../test'; + +export default test({}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-shadow-scope-declaration/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-shadow-scope-declaration/main.svelte new file mode 100644 index 000000000000..26d7dbbcaad3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-shadow-scope-declaration/main.svelte @@ -0,0 +1,25 @@ + + +
      { + derived(store, $store => {}); + }} + on:test2={(store) => { + let $store; + }} +/> diff --git a/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/Nested.svelte b/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/Nested.svelte new file mode 100644 index 000000000000..4af189078150 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/Nested.svelte @@ -0,0 +1,5 @@ + + +

      count: {$count}

      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/_config.js new file mode 100644 index 000000000000..7096f5d1fefe --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/_config.js @@ -0,0 +1,18 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { count } from './store.js'; + +export default test({ + html: '

      count: 0

      ', + + before_test() { + count.set(0); + }, + + test({ assert, component, target }) { + component.increment(); + flushSync(); + + assert.htmlEqual(target.innerHTML, '

      count: 1

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/main.svelte new file mode 100644 index 000000000000..f55a5bdbdf80 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/main.svelte @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/store.js b/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/store.js new file mode 100644 index 000000000000..d432d339ec46 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-unreferenced/store.js @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export const count = writable(0); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/Child.svelte b/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/Child.svelte new file mode 100644 index 000000000000..58ec0f651639 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/Child.svelte @@ -0,0 +1,15 @@ + + +

      {$copy}

      diff --git a/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/_config.js b/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/_config.js new file mode 100644 index 000000000000..7db95248aaa6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/_config.js @@ -0,0 +1,18 @@ +import { flushSync } from 'svelte'; +import { test } from '../../test'; +import { store } from './state.js'; + +export default test({ + html: '

      0

      ', + + before_test() { + store.set({ value: 0 }); + }, + + async test({ assert, target }) { + const button = target.querySelector('button'); + flushSync(() => button?.click()); + + assert.htmlEqual(target.innerHTML, '

      1

      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/main.svelte b/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/main.svelte new file mode 100644 index 000000000000..1d7a9d6e8f60 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/main.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/state.js b/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/state.js new file mode 100644 index 000000000000..030378b5e7d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/store-updated-in-reactive-statement/state.js @@ -0,0 +1,3 @@ +import { writable } from 'svelte/store'; + +export const store = writable({ value: 0 }); diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-attributes/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-attributes/_config.js new file mode 100644 index 000000000000..e3d62e5f13ad --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-attributes/_config.js @@ -0,0 +1,17 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + + + + + `, + + test({ assert, target }) { + const circle = target.querySelector('circle'); + ok(circle); + assert.equal(circle.getAttribute('class'), 'red'); + } +}); diff --git a/test/runtime/samples/svg-attributes/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-attributes/main.svelte similarity index 100% rename from test/runtime/samples/svg-attributes/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-attributes/main.svelte diff --git a/test/runtime/samples/svg-child-component-declared-namespace-shorthand/Rect.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace-shorthand/Rect.svelte similarity index 100% rename from test/runtime/samples/svg-child-component-declared-namespace-shorthand/Rect.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace-shorthand/Rect.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace-shorthand/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace-shorthand/_config.js new file mode 100644 index 000000000000..1f280a183c1d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace-shorthand/_config.js @@ -0,0 +1,26 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { x: 0, y: 0, width: 100, height: 100 }; + }, + + html: '', + + test({ assert, component, target }) { + const svg = target.querySelector('svg'); + const rect = target.querySelector('rect'); + ok(svg); + ok(rect); + + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(rect.namespaceURI, 'http://www.w3.org/2000/svg'); + + component.width = 150; + component.height = 50; + assert.htmlEqual( + target.innerHTML, + '' + ); + } +}); diff --git a/test/runtime/samples/svg-child-component-declared-namespace-shorthand/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace-shorthand/main.svelte similarity index 100% rename from test/runtime/samples/svg-child-component-declared-namespace-shorthand/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace-shorthand/main.svelte diff --git a/test/runtime/samples/svg-child-component-declared-namespace/Rect.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace/Rect.svelte similarity index 100% rename from test/runtime/samples/svg-child-component-declared-namespace/Rect.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace/Rect.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace/_config.js new file mode 100644 index 000000000000..1f280a183c1d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace/_config.js @@ -0,0 +1,26 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { x: 0, y: 0, width: 100, height: 100 }; + }, + + html: '', + + test({ assert, component, target }) { + const svg = target.querySelector('svg'); + const rect = target.querySelector('rect'); + ok(svg); + ok(rect); + + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(rect.namespaceURI, 'http://www.w3.org/2000/svg'); + + component.width = 150; + component.height = 50; + assert.htmlEqual( + target.innerHTML, + '' + ); + } +}); diff --git a/test/runtime/samples/svg-child-component-declared-namespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace/main.svelte similarity index 100% rename from test/runtime/samples/svg-child-component-declared-namespace/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-child-component-declared-namespace/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-class/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-class/_config.js new file mode 100644 index 000000000000..c5f1e8b44c3a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-class/_config.js @@ -0,0 +1,15 @@ +import { ok, test } from '../../test'; + +// this looks like another JSDOM quirk — svg.className = 'foo' behaves +// differently from browsers. So this test succeeds even when it should fail +export default test({ + html: "", + + test({ assert, target }) { + const svg = target.querySelector('svg'); + ok(svg); + + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(svg.getAttribute('class'), 'foo'); + } +}); diff --git a/test/runtime/samples/svg-class/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-class/main.svelte similarity index 100% rename from test/runtime/samples/svg-class/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-class/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-each-block-anchor/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-each-block-anchor/_config.js new file mode 100644 index 000000000000..3053155da5d3 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-each-block-anchor/_config.js @@ -0,0 +1,29 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { foo: ['a'], bar: ['c'] }; + }, + + html: ` + + a + c + + `, + + test({ assert, component, target }) { + component.foo = ['a', 'b']; + + assert.htmlEqual( + target.innerHTML, + ` + + a + b + c + + ` + ); + } +}); diff --git a/test/runtime/samples/svg-each-block-anchor/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-each-block-anchor/main.svelte similarity index 100% rename from test/runtime/samples/svg-each-block-anchor/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-each-block-anchor/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-each-block-namespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-each-block-namespace/_config.js new file mode 100644 index 000000000000..bbbad24ba212 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-each-block-namespace/_config.js @@ -0,0 +1,16 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + + `, + + test({ assert, target }) { + const circles = target.querySelectorAll('circle'); + assert.equal(circles[0].namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(circles[1].namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(circles[2].namespaceURI, 'http://www.w3.org/2000/svg'); + } +}); diff --git a/test/runtime/samples/svg-each-block-namespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-each-block-namespace/main.svelte similarity index 100% rename from test/runtime/samples/svg-each-block-namespace/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-each-block-namespace/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-foreignobject-namespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-foreignobject-namespace/_config.js new file mode 100644 index 000000000000..e8dad1379542 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-foreignobject-namespace/_config.js @@ -0,0 +1,21 @@ +import { test, ok } from '../../test'; + +export default test({ + html: ` + + +

      some text

      +
      +
      + `, + + test({ assert, target }) { + const foreignObject = target.querySelector('foreignObject'); + ok(foreignObject); + assert.equal(foreignObject.namespaceURI, 'http://www.w3.org/2000/svg'); + + const p = target.querySelector('p'); + ok(p); + assert.equal(p.namespaceURI, 'http://www.w3.org/1999/xhtml'); + } +}); diff --git a/test/runtime/samples/svg-foreignobject-namespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-foreignobject-namespace/main.svelte similarity index 100% rename from test/runtime/samples/svg-foreignobject-namespace/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-foreignobject-namespace/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-html-tag/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag/_config.js new file mode 100644 index 000000000000..b9321162efcc --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag/_config.js @@ -0,0 +1,38 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + + + + `, + test({ assert, target, component }) { + let svg = target.querySelector('svg'); + ok(svg); + let circles = target.querySelectorAll('circle'); + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(2, circles.length); + assert.equal(circles[0].namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(circles[1].namespaceURI, 'http://www.w3.org/2000/svg'); + + component.width = 200; + component.height = 120; + assert.htmlEqual( + target.innerHTML, + ` + + + + + ` + ); + svg = target.querySelector('svg'); + ok(svg); + circles = target.querySelectorAll('circle'); + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(2, circles.length); + assert.equal(circles[0].namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(circles[1].namespaceURI, 'http://www.w3.org/2000/svg'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-html-tag/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag/main.svelte new file mode 100644 index 000000000000..dfeb6b04d324 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag/main.svelte @@ -0,0 +1,10 @@ + + + + {@html circle} + + diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-html-tag2/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag2/_config.js new file mode 100644 index 000000000000..3e10bcc9c31f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag2/_config.js @@ -0,0 +1,43 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + + + + + + `, + test({ assert, target, component }) { + let svg = target.querySelector('svg'); + ok(svg); + let circles = target.querySelectorAll('circle'); + + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(2, circles.length); + assert.equal(circles[0].namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(circles[1].namespaceURI, 'http://www.w3.org/2000/svg'); + + component.width = 200; + component.height = 120; + assert.htmlEqual( + target.innerHTML, + ` + + + + + + + ` + ); + svg = target.querySelector('svg'); + ok(svg); + circles = target.querySelectorAll('circle'); + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(2, circles.length); + assert.equal(circles[0].namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(circles[1].namespaceURI, 'http://www.w3.org/2000/svg'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-html-tag2/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag2/main.svelte new file mode 100644 index 000000000000..d8192955d971 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag2/main.svelte @@ -0,0 +1,12 @@ + + + + + {@html circle} + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-html-tag3/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag3/_config.js new file mode 100644 index 000000000000..6c240bb205d6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag3/_config.js @@ -0,0 +1,38 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + + + `, + test({ assert, target, component }) { + let svg = target.querySelector('svg'); + let circle = target.querySelector('circle'); + ok(svg); + ok(circle); + + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(circle.namespaceURI, 'http://www.w3.org/1999/xhtml'); + + component.width = 200; + component.height = 120; + assert.htmlEqual( + target.innerHTML, + ` + + + + + + ` + ); + + svg = target.querySelector('svg'); + circle = target.querySelector('circle'); + ok(svg); + ok(circle); + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(circle.namespaceURI, 'http://www.w3.org/1999/xhtml'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-html-tag3/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag3/main.svelte new file mode 100644 index 000000000000..0d8836e96357 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag3/main.svelte @@ -0,0 +1,11 @@ + + + + + {@html circle} + + diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-html-tag4/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag4/_config.js new file mode 100644 index 000000000000..1e59eab130e5 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag4/_config.js @@ -0,0 +1,14 @@ +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target, component }) { + let svg = target.querySelector('svg'); + ok(svg); + + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.htmlEqual( + svg.outerHTML, + '' + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-html-tag4/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag4/main.svelte new file mode 100644 index 000000000000..c8d313689996 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-html-tag4/main.svelte @@ -0,0 +1,7 @@ + + + + {@html content} + diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-multiple/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-multiple/_config.js new file mode 100644 index 000000000000..db4c05272e3c --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-multiple/_config.js @@ -0,0 +1,32 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 0, y: 0, width: 100, height: 100 }; + }, + + html: ` + + + `, + + test({ assert, component, target }) { + const svgs = target.querySelectorAll('svg'); + const rects = target.querySelectorAll('rect'); + + assert.equal(svgs[0].namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(svgs[0].namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(rects[1].namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(rects[1].namespaceURI, 'http://www.w3.org/2000/svg'); + + component.width = 150; + component.height = 50; + assert.htmlEqual( + target.innerHTML, + ` + + + ` + ); + } +}); diff --git a/test/runtime/samples/svg-multiple/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-multiple/main.svelte similarity index 100% rename from test/runtime/samples/svg-multiple/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-multiple/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-no-whitespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-no-whitespace/_config.js new file mode 100644 index 000000000000..011856e03ad6 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-no-whitespace/_config.js @@ -0,0 +1,12 @@ +import { ok, test } from '../../test'; + +export default test({ + test({ assert, target }) { + const svg = target.querySelector('svg'); + ok(svg); + + assert.equal(svg.childNodes.length, 2); + assert.equal(svg.childNodes[0].nodeName, 'rect'); + assert.equal(svg.childNodes[1].nodeName, 'rect'); + } +}); diff --git a/test/runtime/samples/svg-no-whitespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-no-whitespace/main.svelte similarity index 100% rename from test/runtime/samples/svg-no-whitespace/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-no-whitespace/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-slot-namespace/Widget.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-slot-namespace/Widget.svelte new file mode 100644 index 000000000000..ebfe572dc77a --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-slot-namespace/Widget.svelte @@ -0,0 +1,3 @@ + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-slot-namespace/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-slot-namespace/_config.js new file mode 100644 index 000000000000..63060f6f7082 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-slot-namespace/_config.js @@ -0,0 +1,21 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` +
      + + + +
      + `, + + test({ assert, target }) { + const div = target.querySelector('div'); + ok(div); + assert.equal(div.namespaceURI, 'http://www.w3.org/1999/xhtml'); + + const line = target.querySelector('line'); + ok(line); + assert.equal(line.namespaceURI, 'http://www.w3.org/2000/svg'); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-slot-namespace/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-slot-namespace/main.svelte new file mode 100644 index 000000000000..d6bac9f06516 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-slot-namespace/main.svelte @@ -0,0 +1,9 @@ + + +
      + + + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-spread/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-spread/_config.js new file mode 100644 index 000000000000..b371757d366f --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-spread/_config.js @@ -0,0 +1,9 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-spread/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-spread/main.svelte new file mode 100644 index 000000000000..a7a143814b00 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-spread/main.svelte @@ -0,0 +1,7 @@ + + + + + diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-tspan-preserve-space/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-tspan-preserve-space/_config.js new file mode 100644 index 000000000000..018902984152 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-tspan-preserve-space/_config.js @@ -0,0 +1,5 @@ +import { test } from '../../test'; + +export default test({ + html: 'foo barfoo bar' +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-tspan-preserve-space/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-tspan-preserve-space/main.svelte new file mode 100644 index 000000000000..df43d575a906 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-tspan-preserve-space/main.svelte @@ -0,0 +1 @@ +foo {"bar"}foo bar \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-with-style/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-with-style/_config.js new file mode 100644 index 000000000000..85a8a86ac6f9 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-with-style/_config.js @@ -0,0 +1,15 @@ +import { test } from '../../test'; + +export default test({ + get props() { + return { x: 'bar' }; + }, + + html: ` + + + + + + ` +}); diff --git a/test/runtime/samples/svg-with-style/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-with-style/main.svelte similarity index 100% rename from test/runtime/samples/svg-with-style/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-with-style/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-xlink/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-xlink/_config.js new file mode 100644 index 000000000000..22e38966f833 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-xlink/_config.js @@ -0,0 +1,22 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + + + + + + + `, + test({ assert, target }) { + const use = target.querySelector('use'); + ok(use); + + // @ts-ignore + const href = use.attributes['xlink:href']; + + assert.equal(href.namespaceURI, 'http://www.w3.org/1999/xlink'); + } +}); diff --git a/test/runtime/samples/svg-xlink/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-xlink/main.svelte similarity index 100% rename from test/runtime/samples/svg-xlink/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-xlink/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg-xmlns/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg-xmlns/_config.js new file mode 100644 index 000000000000..cfa949d26fac --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg-xmlns/_config.js @@ -0,0 +1,26 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { x: 0, y: 0, width: 100, height: 100 }; + }, + + html: '', + + test({ assert, component, target }) { + const svg = target.querySelector('svg'); + const rect = target.querySelector('rect'); + ok(svg); + ok(rect); + + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(rect.namespaceURI, 'http://www.w3.org/2000/svg'); + + component.width = 150; + component.height = 50; + assert.htmlEqual( + target.innerHTML, + '' + ); + } +}); diff --git a/test/runtime/samples/svg-xmlns/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg-xmlns/main.svelte similarity index 100% rename from test/runtime/samples/svg-xmlns/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg-xmlns/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/svg/_config.js b/packages/svelte/tests/runtime-legacy/samples/svg/_config.js new file mode 100644 index 000000000000..1f280a183c1d --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/svg/_config.js @@ -0,0 +1,26 @@ +import { ok, test } from '../../test'; + +export default test({ + get props() { + return { x: 0, y: 0, width: 100, height: 100 }; + }, + + html: '', + + test({ assert, component, target }) { + const svg = target.querySelector('svg'); + const rect = target.querySelector('rect'); + ok(svg); + ok(rect); + + assert.equal(svg.namespaceURI, 'http://www.w3.org/2000/svg'); + assert.equal(rect.namespaceURI, 'http://www.w3.org/2000/svg'); + + component.width = 150; + component.height = 50; + assert.htmlEqual( + target.innerHTML, + '' + ); + } +}); diff --git a/test/runtime/samples/svg/main.svelte b/packages/svelte/tests/runtime-legacy/samples/svg/main.svelte similarity index 100% rename from test/runtime/samples/svg/main.svelte rename to packages/svelte/tests/runtime-legacy/samples/svg/main.svelte diff --git a/packages/svelte/tests/runtime-legacy/samples/table-nesting/_config.js b/packages/svelte/tests/runtime-legacy/samples/table-nesting/_config.js new file mode 100644 index 000000000000..e29e37441edd --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/table-nesting/_config.js @@ -0,0 +1,13 @@ +import { test } from '../../test'; + +export default test({ + html: ` + + + + + + +
      Hello world
      + ` +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/table-nesting/main.svelte b/packages/svelte/tests/runtime-legacy/samples/table-nesting/main.svelte new file mode 100644 index 000000000000..00e4a17c2d3b --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/table-nesting/main.svelte @@ -0,0 +1,9 @@ + + + + + + + + +
      Hello world
      \ No newline at end of file diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/App.svelte b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/App.svelte new file mode 100644 index 000000000000..4ec51de6d5d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/App.svelte @@ -0,0 +1,11 @@ + + +
      Hello {name}
      + + diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/_config.js b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/_config.js new file mode 100644 index 000000000000..42b7254c6b41 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + compileOptions: { + cssHash: () => 'svelte-xyz' + }, + + async test({ assert, component, window }) { + assert.htmlEqual( + window.document.head.innerHTML, + '' + ); + assert.htmlEqual(component.div.innerHTML, '
      Hello World
      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/main.svelte b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/main.svelte new file mode 100644 index 000000000000..eb2d6c0ee6da --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom-detached/main.svelte @@ -0,0 +1,18 @@ + diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom/App.svelte b/packages/svelte/tests/runtime-legacy/samples/target-dom/App.svelte new file mode 100644 index 000000000000..4ec51de6d5d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom/App.svelte @@ -0,0 +1,11 @@ + + +
      Hello {name}
      + + diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom/_config.js b/packages/svelte/tests/runtime-legacy/samples/target-dom/_config.js new file mode 100644 index 000000000000..42b7254c6b41 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom/_config.js @@ -0,0 +1,17 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + compileOptions: { + cssHash: () => 'svelte-xyz' + }, + + async test({ assert, component, window }) { + assert.htmlEqual( + window.document.head.innerHTML, + '' + ); + assert.htmlEqual(component.div.innerHTML, '
      Hello World
      '); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/target-dom/main.svelte b/packages/svelte/tests/runtime-legacy/samples/target-dom/main.svelte new file mode 100644 index 000000000000..f0a63a95aaa7 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-dom/main.svelte @@ -0,0 +1,18 @@ + + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/App.svelte b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/App.svelte new file mode 100644 index 000000000000..4ec51de6d5d0 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/App.svelte @@ -0,0 +1,11 @@ + + +
      Hello {name}
      + + diff --git a/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/_config.js b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/_config.js new file mode 100644 index 000000000000..cf720ec48bac --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/_config.js @@ -0,0 +1,20 @@ +import { test } from '../../test'; + +export default test({ + skip_mode: ['server'], + + compileOptions: { + cssHash: () => 'svelte-xyz' + }, + + async test({ assert, component, window }) { + assert.htmlEqual( + window.document.head.innerHTML, + '' + ); + assert.htmlEqual( + component.div.shadowRoot.innerHTML, + '
      Hello World
      ' + ); + } +}); diff --git a/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/main.svelte b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/main.svelte new file mode 100644 index 000000000000..37e4b7e48773 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/target-shadow-dom/main.svelte @@ -0,0 +1,19 @@ + + +
      diff --git a/packages/svelte/tests/runtime-legacy/samples/template/_config.js b/packages/svelte/tests/runtime-legacy/samples/template/_config.js new file mode 100644 index 000000000000..f82716854293 --- /dev/null +++ b/packages/svelte/tests/runtime-legacy/samples/template/_config.js @@ -0,0 +1,54 @@ +import { ok, test } from '../../test'; + +export default test({ + html: ` + + + + `, + + test({ assert, target }) { + const template = /** @type {HTMLTemplateElement} */ (target.querySelector('#t1')); + assert.htmlEqual( + template.innerHTML, + ` +
      foo
      + ` + ); + const content = /** @type {DocumentFragment} */ (template.content.cloneNode(true)); + const div = content.children[0]; + assert.htmlEqual( + div.outerHTML, + ` +
      foo
      + ` + ); + + const template2 = /** @type {HTMLTemplateElement} */ (target.querySelector('#t2')); + assert.equal(template2.childNodes.length, 0); + assert.equal(template2.content.childNodes.length, 1); + assert.equal(template2.content.firstChild?.textContent, '123'); + assert.htmlEqual(template2.innerHTML, '123'); + + const template3 = /** @type {HTMLTemplateElement} */ (target.querySelector('#t3')); + // test: (with hydration from ssr rendered html) + // out of order render. + // may render as for ssr+hydration case. + // we bypass it by using symmetric siblings. hence