chore: drop support for solid component testing (#33523)

This commit is contained in:
Yury Semikhatsky 2024-11-11 10:26:50 -08:00 committed by GitHub
parent 649e0e0235
commit e3ed9fa7c3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
43 changed files with 13 additions and 1227 deletions

View File

@ -40,7 +40,7 @@ test('event should work', async ({ mount }) => {
## How to get started
Adding Playwright Test to an existing project is easy. Below are the steps to enable Playwright Test for a React, Vue, Svelte or Solid project.
Adding Playwright Test to an existing project is easy. Below are the steps to enable Playwright Test for a React, Vue or Svelte project.
### Step 1: Install Playwright Test for components for your respective framework
@ -106,7 +106,6 @@ component is mounted using this script. It can be either a `.js`, `.ts`, `.jsx`
defaultValue="react"
values={[
{label: 'React', value: 'react'},
{label: 'Solid', value: 'solid'},
{label: 'Svelte', value: 'svelte'},
{label: 'Vue', value: 'vue'},
]
@ -168,20 +167,6 @@ test('should work', async ({ mount }) => {
</TabItem>
<TabItem value="solid">
```js title="app.spec.tsx"
import { test, expect } from '@playwright/experimental-ct-solid';
import App from './App';
test('should work', async ({ mount }) => {
const component = await mount(<App />);
await expect(component).toContainText('Learn Solid');
});
```
</TabItem>
</Tabs>
### Step 3. Run the tests
@ -309,7 +294,6 @@ Provide props to a component when mounted.
defaultValue="react"
values={[
{label: 'React', value: 'react'},
{label: 'Solid', value: 'solid'},
{label: 'Svelte', value: 'svelte'},
{label: 'Vue', value: 'vue'},
]
@ -325,17 +309,6 @@ test('props', async ({ mount }) => {
});
```
</TabItem>
<TabItem value="solid">
```js title="component.spec.tsx"
import { test } from '@playwright/experimental-ct-solid';
test('props', async ({ mount }) => {
const component = await mount(<Component msg="greetings" />);
});
```
</TabItem>
<TabItem value="svelte">
@ -379,7 +352,6 @@ Provide callbacks/events to a component when mounted.
defaultValue="react"
values={[
{label: 'React', value: 'react'},
{label: 'Solid', value: 'solid'},
{label: 'Svelte', value: 'svelte'},
{label: 'Vue', value: 'vue'},
]
@ -395,17 +367,6 @@ test('callback', async ({ mount }) => {
});
```
</TabItem>
<TabItem value="solid">
```js title="component.spec.tsx"
import { test } from '@playwright/experimental-ct-solid';
test('callback', async ({ mount }) => {
const component = await mount(<Component onClick={() => {}} />);
});
```
</TabItem>
<TabItem value="svelte">
@ -449,7 +410,6 @@ Provide children/slots to a component when mounted.
defaultValue="react"
values={[
{label: 'React', value: 'react'},
{label: 'Solid', value: 'solid'},
{label: 'Svelte', value: 'svelte'},
{label: 'Vue', value: 'vue'},
]
@ -465,17 +425,6 @@ test('children', async ({ mount }) => {
});
```
</TabItem>
<TabItem value="solid">
```js title="component.spec.tsx"
import { test } from '@playwright/experimental-ct-solid';
test('children', async ({ mount }) => {
const component = await mount(<Component>Child</Component>);
});
```
</TabItem>
<TabItem value="svelte">
@ -519,7 +468,6 @@ You can use `beforeMount` and `afterMount` hooks to configure your app. This let
defaultValue="react"
values={[
{label: 'React', value: 'react'},
{label: 'Solid', value: 'solid'},
{label: 'Vue3', value: 'vue3'},
]
}>
@ -554,37 +502,6 @@ You can use `beforeMount` and `afterMount` hooks to configure your app. This let
</TabItem>
<TabItem value="solid">
```js title="playwright/index.tsx"
import { beforeMount, afterMount } from '@playwright/experimental-ct-solid/hooks';
import { Router } from '@solidjs/router';
export type HooksConfig = {
enableRouting?: boolean;
}
beforeMount<HooksConfig>(async ({ App, hooksConfig }) => {
if (hooksConfig?.enableRouting)
return <Router><App /></Router>;
});
```
```js title="src/pages/ProductsPage.spec.tsx"
import { test, expect } from '@playwright/experimental-ct-solid';
import type { HooksConfig } from '../playwright';
import { ProductsPage } from './pages/ProductsPage';
test('configure routing through hooks config', async ({ page, mount }) => {
const component = await mount<HooksConfig>(<ProductsPage />, {
hooksConfig: { enableRouting: true },
});
await expect(component.getByRole('link')).toHaveAttribute('href', '/products/42');
});
```
</TabItem>
<TabItem value="vue3">
```js title="playwright/index.ts"
@ -626,7 +543,6 @@ Unmount the mounted component from the DOM. This is useful for testing the compo
defaultValue="react"
values={[
{label: 'React', value: 'react'},
{label: 'Solid', value: 'solid'},
{label: 'Svelte', value: 'svelte'},
{label: 'Vue', value: 'vue'},
]
@ -643,18 +559,6 @@ test('unmount', async ({ mount }) => {
});
```
</TabItem>
<TabItem value="solid">
```js title="component.spec.tsx"
import { test } from '@playwright/experimental-ct-solid';
test('unmount', async ({ mount }) => {
const component = await mount(<Component/>);
await component.unmount();
});
```
</TabItem>
<TabItem value="svelte">
@ -700,7 +604,6 @@ Update props, slots/children, and/or events/callbacks of a mounted component. Th
defaultValue="react"
values={[
{label: 'React', value: 'react'},
{label: 'Solid', value: 'solid'},
{label: 'Svelte', value: 'svelte'},
{label: 'Vue', value: 'vue'},
]
@ -719,20 +622,6 @@ test('update', async ({ mount }) => {
});
```
</TabItem>
<TabItem value="solid">
```js title="component.spec.tsx"
import { test } from '@playwright/experimental-ct-solid';
test('update', async ({ mount }) => {
const component = await mount(<Component/>);
await component.update(
<Component msg="greetings" onClick={() => {}}>Child</Component>
);
});
```
</TabItem>
<TabItem value="svelte">
@ -820,7 +709,7 @@ test('example test', async ({ mount, router }) => {
## Frequently asked questions
### What's the difference between `@playwright/test` and `@playwright/experimental-ct-{react,svelte,vue,solid}`?
### What's the difference between `@playwright/test` and `@playwright/experimental-ct-{react,svelte,vue}`?
```js
test('…', async ({ mount, page, context }) => {
@ -828,13 +717,12 @@ test('…', async ({ mount, page, context }) => {
});
```
`@playwright/experimental-ct-{react,svelte,vue,solid}` wrap `@playwright/test` to provide an additional built-in component-testing specific fixture called `mount`:
`@playwright/experimental-ct-{react,svelte,vue}` wrap `@playwright/test` to provide an additional built-in component-testing specific fixture called `mount`:
<Tabs
defaultValue="react"
values={[
{label: 'React', value: 'react'},
{label: 'Solid', value: 'solid'},
{label: 'Svelte', value: 'svelte'},
{label: 'Vue', value: 'vue'},
]
@ -895,22 +783,6 @@ test('should work', async ({ mount }) => {
</TabItem>
<TabItem value="solid">
```js
import { test, expect } from '@playwright/experimental-ct-solid';
import HelloWorld from './HelloWorld';
test.use({ viewport: { width: 500, height: 500 } });
test('should work', async ({ mount }) => {
const component = await mount(<HelloWorld msg="greetings" />);
await expect(component).toContainText('Greetings');
});
```
</TabItem>
</Tabs>
Additionally, it adds some config options you can use in your `playwright-ct.config.{ts,js}`.

182
package-lock.json generated
View File

@ -207,6 +207,7 @@
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
"integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==",
"dev": true,
"dependencies": {
"@babel/types": "^7.22.5"
},
@ -233,6 +234,7 @@
"version": "7.23.7",
"resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.7.tgz",
"integrity": "sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-environment-visitor": "^7.22.20",
@ -286,6 +288,7 @@
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz",
"integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==",
"dev": true,
"dependencies": {
"@babel/types": "^7.23.0"
},
@ -326,6 +329,7 @@
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz",
"integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==",
"dev": true,
"dependencies": {
"@babel/types": "^7.22.5"
},
@ -345,6 +349,7 @@
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz",
"integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==",
"dev": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-member-expression-to-functions": "^7.22.15",
@ -372,6 +377,7 @@
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz",
"integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==",
"dev": true,
"dependencies": {
"@babel/types": "^7.22.5"
},
@ -467,6 +473,7 @@
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz",
"integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@ -517,6 +524,7 @@
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz",
"integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5"
},
@ -579,6 +587,7 @@
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz",
"integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==",
"dev": true,
"dependencies": {
"@babel/helper-module-transforms": "^7.23.3",
"@babel/helper-plugin-utils": "^7.22.5",
@ -721,6 +730,7 @@
"version": "7.23.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz",
"integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.22.5",
"@babel/helper-create-class-features-plugin": "^7.23.6",
@ -754,24 +764,6 @@
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/preset-typescript": {
"version": "7.23.3",
"resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz",
"integrity": "sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==",
"dependencies": {
"@babel/helper-plugin-utils": "^7.22.5",
"@babel/helper-validator-option": "^7.22.15",
"@babel/plugin-syntax-jsx": "^7.23.3",
"@babel/plugin-transform-modules-commonjs": "^7.23.3",
"@babel/plugin-transform-typescript": "^7.23.3"
},
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/runtime": {
"version": "7.23.8",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.8.tgz",
@ -1496,10 +1488,6 @@
"resolved": "packages/playwright-ct-react17",
"link": true
},
"node_modules/@playwright/experimental-ct-solid": {
"resolved": "packages/playwright-ct-solid",
"link": true
},
"node_modules/@playwright/experimental-ct-svelte": {
"resolved": "packages/playwright-ct-svelte",
"link": true
@ -2616,43 +2604,6 @@
"dequal": "^2.0.3"
}
},
"node_modules/babel-plugin-jsx-dom-expressions": {
"version": "0.37.13",
"resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.37.13.tgz",
"integrity": "sha512-oAEMMIgU0h1DmHn4ZDaBBFc08nsVJciLq9pF7g0ZdpeIDKfY4zXjXr8+/oBjKhXG8nyomhnTodPjeG+/ZXcWXQ==",
"dependencies": {
"@babel/helper-module-imports": "7.18.6",
"@babel/plugin-syntax-jsx": "^7.18.6",
"@babel/types": "^7.20.7",
"html-entities": "2.3.3",
"validate-html-nesting": "^1.2.1"
},
"peerDependencies": {
"@babel/core": "^7.20.12"
}
},
"node_modules/babel-plugin-jsx-dom-expressions/node_modules/@babel/helper-module-imports": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
"integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
"dependencies": {
"@babel/types": "^7.18.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/babel-preset-solid": {
"version": "1.8.9",
"resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.8.9.tgz",
"integrity": "sha512-1awR1QCoryXtAdnjsrx/eVBTYz+tpHUDOdBXqG9oVV7S0ojf2MV/woR0+8BG+LMXVzIr60oKYzCZ9UZGafxmpg==",
"dependencies": {
"babel-plugin-jsx-dom-expressions": "^0.37.13"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -4565,11 +4516,6 @@
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
"node_modules/html-entities": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz",
"integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="
},
"node_modules/html-reporter": {
"resolved": "packages/html-reporter",
"link": true
@ -5038,17 +4984,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-what": {
"version": "4.1.16",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
"integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/isarray": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
@ -5362,20 +5297,6 @@
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
},
"node_modules/merge-anything": {
"version": "5.1.7",
"resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-5.1.7.tgz",
"integrity": "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==",
"dependencies": {
"is-what": "^4.1.8"
},
"engines": {
"node": ">=12.13"
},
"funding": {
"url": "https://github.com/sponsors/mesqueeb"
}
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@ -6422,25 +6343,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/seroval": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/seroval/-/seroval-1.0.4.tgz",
"integrity": "sha512-qQs/N+KfJu83rmszFQaTxcoJoPn6KNUruX4KmnmyD0oZkUoiNvJ1rpdYKDf4YHM05k+HOgCxa3yvf15QbVijGg==",
"engines": {
"node": ">=10"
}
},
"node_modules/seroval-plugins": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/seroval-plugins/-/seroval-plugins-1.0.4.tgz",
"integrity": "sha512-DQ2IK6oQVvy8k+c2V5x5YCtUa/GGGsUwUBNN9UqohrZ0rWdUapBFpNMYP1bCyRHoxOJjdKGl+dieacFIpU/i1A==",
"engines": {
"node": ">=10"
},
"peerDependencies": {
"seroval": "^1.0"
}
},
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@ -6530,29 +6432,6 @@
"node": "*"
}
},
"node_modules/solid-js": {
"version": "1.8.11",
"resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.8.11.tgz",
"integrity": "sha512-WdwmER+TwBJiN4rVQTVBxocg+9pKlOs41KzPYntrC86xO5sek8TzBYozPEZPL1IRWDouf2lMrvSbIs3CanlPvQ==",
"dependencies": {
"csstype": "^3.1.0",
"seroval": "^1.0.3",
"seroval-plugins": "^1.0.3"
}
},
"node_modules/solid-refresh": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/solid-refresh/-/solid-refresh-0.6.3.tgz",
"integrity": "sha512-F3aPsX6hVw9ttm5LYlth8Q15x6MlI/J3Dn+o3EQyRTtTxidepSTwAYdozt01/YA+7ObcciagGEyXIopGZzQtbA==",
"dependencies": {
"@babel/generator": "^7.23.6",
"@babel/helper-module-imports": "^7.22.15",
"@babel/types": "^7.23.6"
},
"peerDependencies": {
"solid-js": "^1.3"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@ -7120,11 +6999,6 @@
"uuid": "dist/bin/uuid"
}
},
"node_modules/validate-html-nesting": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/validate-html-nesting/-/validate-html-nesting-1.2.2.tgz",
"integrity": "sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg=="
},
"node_modules/validate-npm-package-license": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@ -7193,24 +7067,6 @@
}
}
},
"node_modules/vite-plugin-solid": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.8.2.tgz",
"integrity": "sha512-HcvMs6DTxBaO4kE3psnirPQBCUUdYeQkCNKuB2TpEkJsxb6BGP6/7qkbbCSMxn25PyNdjvzVi1WXi0ou8KPgHw==",
"dependencies": {
"@babel/core": "^7.23.3",
"@babel/preset-typescript": "^7.23.3",
"@types/babel__core": "^7.20.4",
"babel-preset-solid": "^1.8.4",
"merge-anything": "^5.1.7",
"solid-refresh": "^0.6.3",
"vitefu": "^0.2.5"
},
"peerDependencies": {
"solid-js": "^1.7.2",
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
}
},
"node_modules/vite/node_modules/@esbuild/android-arm": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
@ -7995,24 +7851,6 @@
"node": ">=18"
}
},
"packages/playwright-ct-solid": {
"name": "@playwright/experimental-ct-solid",
"version": "1.49.0-next",
"license": "Apache-2.0",
"dependencies": {
"@playwright/experimental-ct-core": "1.49.0-next",
"vite-plugin-solid": "^2.7.0"
},
"bin": {
"playwright": "cli.js"
},
"devDependencies": {
"solid-js": "^1.7.0"
},
"engines": {
"node": ">=18"
}
},
"packages/playwright-ct-svelte": {
"name": "@playwright/experimental-ct-svelte",
"version": "1.49.0-next",

View File

@ -1,12 +0,0 @@
**/*
!README.md
!LICENSE
!cli.js
!register.d.ts
!register.mjs
!registerSource.mjs
!index.d.ts
!index.js
!hooks.d.ts
!hooks.mjs

View File

@ -1,3 +0,0 @@
> **BEWARE** This package is EXPERIMENTAL and does not respect semver.
Read more at https://playwright.dev/docs/test-components

View File

@ -1,20 +0,0 @@
#!/usr/bin/env node
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { program } = require('@playwright/experimental-ct-core/lib/program');
program.parse(process.argv);

View File

@ -1,24 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { JSXElement } from 'solid-js';
export declare function beforeMount<HooksConfig>(
callback: (params: { hooksConfig?: HooksConfig, App: () => JSXElement }) => Promise<void | JSXElement>
): void;
export declare function afterMount<HooksConfig>(
callback: (params: { hooksConfig?: HooksConfig }) => Promise<void>
): void;

View File

@ -1,29 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const __pw_hooks_before_mount = [];
const __pw_hooks_after_mount = [];
window.__pw_hooks_before_mount = __pw_hooks_before_mount;
window.__pw_hooks_after_mount = __pw_hooks_after_mount;
export const beforeMount = callback => {
__pw_hooks_before_mount.push(callback);
};
export const afterMount = callback => {
__pw_hooks_after_mount.push(callback);
};

View File

@ -1,35 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { TestType, Locator } from '@playwright/experimental-ct-core';
export interface MountOptions<HooksConfig> {
hooksConfig?: HooksConfig;
}
export interface MountResult extends Locator {
unmount(): Promise<void>;
update(component: JSX.Element): Promise<void>;
}
export const test: TestType<{
mount<HooksConfig>(
component: JSX.Element,
options?: MountOptions<HooksConfig>
): Promise<MountResult>;
}>;
export { defineConfig, PlaywrightTestConfig, expect, devices } from '@playwright/experimental-ct-core';

View File

@ -1,33 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { test, expect, devices, defineConfig: originalDefineConfig } = require('@playwright/experimental-ct-core');
const path = require('path');
const defineConfig = (config, ...configs) => {
return originalDefineConfig({
...config,
'@playwright/test': {
packageJSON: require.resolve('./package.json'),
},
'@playwright/experimental-ct-core': {
registerSourceFile: path.join(__dirname, 'registerSource.mjs'),
frameworkPluginFactory: () => import('vite-plugin-solid').then(plugin => plugin.default()),
},
}, ...configs);
};
module.exports = { test, expect, devices, defineConfig };

View File

@ -1,42 +0,0 @@
{
"name": "@playwright/experimental-ct-solid",
"version": "1.49.0-next",
"description": "Playwright Component Testing for Solid",
"repository": {
"type": "git",
"url": "git+https://github.com/microsoft/playwright.git"
},
"homepage": "https://playwright.dev",
"engines": {
"node": ">=18"
},
"author": {
"name": "Microsoft Corporation"
},
"license": "Apache-2.0",
"exports": {
".": {
"types": "./index.d.ts",
"default": "./index.js"
},
"./register": {
"types": "./register.d.ts",
"default": "./register.mjs"
},
"./hooks": {
"types": "./hooks.d.ts",
"default": "./hooks.mjs"
},
"./package.json": "./package.json"
},
"dependencies": {
"@playwright/experimental-ct-core": "1.49.0-next",
"vite-plugin-solid": "^2.7.0"
},
"devDependencies": {
"solid-js": "^1.7.0"
},
"bin": {
"playwright": "cli.js"
}
}

View File

@ -1,17 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export default function pwRegister(components: Record<string, any>): void;

View File

@ -1,21 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { pwRegister } from './registerSource.mjs';
export default components => {
pwRegister(components);
};

View File

@ -1,84 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// @ts-check
// This file is injected into the registry as text, no dependencies are allowed.
import { render as __pwSolidRender, createComponent as __pwSolidCreateComponent } from 'solid-js/web';
import __pwH from 'solid-js/h';
/** @typedef {import('../playwright-ct-core/types/component').JsxComponent} JsxComponent */
/**
* @param {any} component
* @returns {component is JsxComponent}
*/
function isJsxComponent(component) {
return typeof component === 'object' && component && component.__pw_type === 'jsx';
}
/**
* @param {any} value
*/
function __pwCreateComponent(value) {
return window.__pwTransformObject(value, v => {
if (isJsxComponent(v)) {
const component = v;
const props = component.props ? __pwCreateComponent(component.props) : {};
if (typeof component.type === 'string') {
const { children, ...propsWithoutChildren } = props;
return { result: __pwH(component.type, propsWithoutChildren, children) };
}
return { result: __pwSolidCreateComponent(component.type, props) };
}
});
}
const __pwUnmountKey = Symbol('unmountKey');
window.playwrightMount = async (component, rootElement, hooksConfig) => {
if (!isJsxComponent(component))
throw new Error('Object mount notation is not supported');
let App = () => __pwCreateComponent(component);
for (const hook of window.__pw_hooks_before_mount || []) {
const wrapper = await hook({ App, hooksConfig });
if (wrapper)
App = () => wrapper;
}
const unmount = __pwSolidRender(App, rootElement);
rootElement[__pwUnmountKey] = unmount;
for (const hook of window.__pw_hooks_after_mount || [])
await hook({ hooksConfig });
};
window.playwrightUnmount = async rootElement => {
const unmount = rootElement[__pwUnmountKey];
if (!unmount)
throw new Error('Component was not mounted');
unmount();
delete rootElement[__pwUnmountKey];
};
window.playwrightUpdate = async (rootElement, component) => {
if (!isJsxComponent(component))
throw new Error('Object mount notation is not supported');
window.playwrightUnmount(rootElement);
window.playwrightMount(component, rootElement, {});
};

View File

@ -1,2 +0,0 @@
node_modules
dist

View File

@ -1,34 +0,0 @@
## Usage
Those templates dependencies are maintained via [pnpm](https://pnpm.io) via `pnpm up -Lri`.
This is the reason you see a `pnpm-lock.yaml`. That being said, any package manager will work. This file can be safely be removed once you clone a template.
```bash
$ npm install # or pnpm install or yarn install
```
### Learn more on the [Solid Website](https://solidjs.com) and come chat with us on our [Discord](https://discord.com/invite/solidjs)
## Available Scripts
In the project directory, you can run:
### `npm dev` or `npm start`
Runs the app in the development mode.<br>
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
The page will reload if you make edits.<br>
### `npm run build`
Builds the app for production to the `dist` folder.<br>
It correctly bundles Solid in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.<br>
Your app is ready to be deployed!
## Deployment
You can deploy the `dist` folder to any static host provider (netlify, surge, now, etc.)

View File

@ -1,16 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="shortcut icon" type="image/ico" href="/src/assets/favicon.ico" />
<title>Solid App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/index.tsx" type="module"></script>
</body>
</html>

View File

@ -1,22 +0,0 @@
{
"name": "ct-solid",
"version": "0.0.0",
"description": "",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"typecheck": "tsc --noEmit"
},
"license": "MIT",
"dependencies": {
"@solidjs/router": "^0.8.2",
"solid-js": "^1.7.3"
},
"devDependencies": {
"typescript": "^5.2.2",
"vite": "^5.2.8",
"vite-plugin-solid": "^2.6.1"
}
}

View File

@ -1,49 +0,0 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { defineConfig, devices } from '@playwright/experimental-ct-solid';
import { resolve } from 'path';
export default defineConfig({
testDir: 'tests',
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 0,
reporter: process.env.CI ? 'html' : 'line',
use: {
trace: 'on-first-retry',
ctViteConfig: {
resolve: {
alias: {
'@': resolve(__dirname, './src'),
}
}
}
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
use: { ...devices['Desktop Safari'] },
},
],
});

View File

@ -1,13 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Solid App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./index.tsx"></script>
</body>
</html>

View File

@ -1,19 +0,0 @@
import { beforeMount, afterMount } from '@playwright/experimental-ct-solid/hooks';
import { Router } from "@solidjs/router";
import '../src/assets/index.css';
export type HooksConfig = {
route?: string;
routing?: boolean;
}
beforeMount<HooksConfig>(async ({ hooksConfig, App }) => {
console.log(`Before mount: ${JSON.stringify(hooksConfig)}`);
if (hooksConfig?.routing)
return <Router><App /></Router>;
});
afterMount<HooksConfig>(async () => {
console.log(`After mount`);
});

View File

@ -1,20 +0,0 @@
import { Routes, Route, A } from "@solidjs/router"
import logo from './assets/logo.svg';
import LoginPage from './pages/LoginPage';
import DashboardPage from './pages/DashboardPage';
export default function App() {
return <>
<header>
<img src={logo} alt="logo" width={125} height={125} />
<A href="/">Login</A>
<A href="/dashboard">Dashboard</A>
</header>
<Routes>
<Route path="/">
<Route path="/" component={LoginPage} />
<Route path="dashboard" component={DashboardPage} />
</Route>
</Routes>
</>
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,20 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
@media (prefers-color-scheme: light) {
:root {
color: #e3e3e3;
background-color: #1b1b1d;
}
}

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 166 155.3"><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" fill="#76b3e1"/><linearGradient id="a" gradientUnits="userSpaceOnUse" x1="27.5" y1="3" x2="152" y2="63.5"><stop offset=".1" stop-color="#76b3e1"/><stop offset=".3" stop-color="#dcf2fd"/><stop offset="1" stop-color="#76b3e1"/></linearGradient><path d="M163 35S110-4 69 5l-3 1c-6 2-11 5-14 9l-2 3-15 26 26 5c11 7 25 10 38 7l46 9 18-30z" opacity=".3" fill="url(#a)"/><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" fill="#518ac8"/><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="95.8" y1="32.6" x2="74" y2="105.2"><stop offset="0" stop-color="#76b3e1"/><stop offset=".5" stop-color="#4377bb"/><stop offset="1" stop-color="#1f3b77"/></linearGradient><path d="M52 35l-4 1c-17 5-22 21-13 35 10 13 31 20 48 15l62-21S92 26 52 35z" opacity=".3" fill="url(#b)"/><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="18.4" y1="64.2" x2="144.3" y2="149.8"><stop offset="0" stop-color="#315aa9"/><stop offset=".5" stop-color="#518ac8"/><stop offset="1" stop-color="#315aa9"/></linearGradient><path d="M134 80a45 45 0 00-48-15L24 85 4 120l112 19 20-36c4-7 3-15-2-23z" fill="url(#c)"/><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="75.2" y1="74.5" x2="24.4" y2="260.8"><stop offset="0" stop-color="#4377bb"/><stop offset=".5" stop-color="#1a336b"/><stop offset="1" stop-color="#1a336b"/></linearGradient><path d="M114 115a45 45 0 00-48-15L4 120s53 40 94 30l3-1c17-5 23-21 13-34z" fill="url(#d)"/></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -1,13 +0,0 @@
import type { JSX } from "solid-js";
type ButtonProps = {
title: string;
onClick?(props: string): void;
className?: string;
} & Omit<JSX.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'>;
export default function Button({ onClick, title, ...attributes }: ButtonProps) {
return <button {...attributes} onClick={() => onClick?.('hello')}>
{title}
</button>
}

View File

@ -1,7 +0,0 @@
import { type ParentProps } from 'solid-js';
type DefaultChildrenProps = ParentProps<{}>;
export default function CheckChildrenProp(props: DefaultChildrenProps) {
return <>{'children' in props ? props.children : 'No Children'}</>
}

View File

@ -1,19 +0,0 @@
import { createSignal } from "solid-js";
type CounterProps = {
count?: number;
onClick?(props: string): void;
children?: any;
}
let _remountCount = 1;
export default function Counter(props: CounterProps) {
const [remountCount, setRemountCount] = createSignal(_remountCount++);
return <button onClick={() => props.onClick?.('hello')}>
<span data-testid="props">{props.count}</span>
<span data-testid="remount-count">{remountCount()}</span>
{ props.children }
</button>
}

View File

@ -1,15 +0,0 @@
type DefaultChildrenProps = {
children?: any;
}
export default function DefaultChildren(props: DefaultChildrenProps) {
return <div>
<h1>Welcome!</h1>
<main>
{props.children}
</main>
<footer>
Thanks for visiting.
</footer>
</div>
}

View File

@ -1,4 +0,0 @@
export default function EmptyFragment(props: unknown) {
Object.assign(window, { props });
return <>{[]}</>;
}

View File

@ -1,6 +0,0 @@
export default function MultiRoot() {
return <>
<div>root 1</div>
<div>root 2</div>
</>
}

View File

@ -1,17 +0,0 @@
type MultipleChildrenProps = {
children?: [any, any, any];
}
export default function MultipleChildren(props: MultipleChildrenProps) {
return <div>
<header>
{props.children?.at(0)}
</header>
<main>
{props.children?.at(1)}
</main>
<footer>
{props.children?.at(2)}
</footer>
</div>
}

View File

@ -1,7 +0,0 @@
/* @refresh reload */
import { render } from 'solid-js/web';
import { Router } from "@solidjs/router";
import App from './App';
import './assets/index.css';
render(() => <Router><App /></Router>, document.getElementById('root')!);

View File

@ -1,3 +0,0 @@
export default function DashboardPage() {
return <main>Dashboard</main>
}

View File

@ -1,3 +0,0 @@
export default function LoginPage() {
return <main>Login</main>
}

View File

@ -1,28 +0,0 @@
import { test, expect } from '@playwright/experimental-ct-solid';
import Button from '@/components/Button';
import DefaultChildren from '@/components/DefaultChildren';
test('execute callback when the button is clicked', async ({ mount }) => {
const messages: string[] = [];
const component = await mount(
<Button
title="Submit"
onClick={(data) => {
messages.push(data);
}}
/>
);
await component.click();
expect(messages).toEqual(['hello']);
});
test('execute callback when a child node is clicked', async ({ mount }) => {
let clickFired = false;
const component = await mount(
<DefaultChildren>
<span onClick={() => (clickFired = true)}>Main Content</span>
</DefaultChildren>
);
await component.getByText('Main Content').click();
expect(clickFired).toBeTruthy();
});

View File

@ -1,66 +0,0 @@
import { test, expect } from '@playwright/experimental-ct-solid';
import Button from '@/components/Button';
import DefaultChildren from '@/components/DefaultChildren';
import MultipleChildren from '@/components/MultipleChildren';
import CheckChildrenProp from '@/components/CheckChildrenProp'
test('render a default child', async ({ mount }) => {
const component = await mount(
<DefaultChildren>Main Content</DefaultChildren>
);
await expect(component).toContainText('Main Content');
});
test('render multiple children', async ({ mount }) => {
const component = await mount(
<DefaultChildren>
<div data-testid="one">One</div>
<div data-testid="two">Two</div>
</DefaultChildren>
);
await expect(component.getByTestId('one')).toContainText('One');
await expect(component.getByTestId('two')).toContainText('Two');
});
test('render a component as child', async ({ mount }) => {
const component = await mount(
<DefaultChildren>
<Button title="Submit" />
</DefaultChildren>
);
await expect(component).toContainText('Submit');
});
test('render named children', async ({ mount }) => {
const component = await mount(
<MultipleChildren>
<div>Header</div>
<div>Main Content</div>
<div>Footer</div>
</MultipleChildren>
);
await expect(component).toContainText('Header');
await expect(component).toContainText('Main Content');
await expect(component).toContainText('Footer');
});
test('render string as child', async ({ mount }) => {
const component = await mount(<DefaultChildren>{'string'}</DefaultChildren>);
await expect(component).toContainText('string');
});
test('render array as child', async ({ mount }) => {
const component = await mount(<DefaultChildren>{[<h4>{[4]}</h4>,[[<p>[2,3]</p>]]]}</DefaultChildren>);
await expect(component.getByRole('heading', { level: 4 })).toHaveText('4');
await expect(component.getByRole('paragraph')).toHaveText('[2,3]');
});
test('render number as child', async ({ mount }) => {
const component = await mount(<DefaultChildren>{1337}</DefaultChildren>);
await expect(component).toContainText('1337');
});
test('absence of children when children prop is not provided', async ({ mount }) => {
const component = await mount(<CheckChildrenProp />);
await expect(component).toContainText('No Children');
});

View File

@ -1,21 +0,0 @@
import { test, expect } from '@playwright/experimental-ct-solid';
import Button from '@/components/Button';
import EmptyFragment from '@/components/EmptyFragment';
test('render props', async ({ mount }) => {
const component = await mount(<Button title="Submit" />);
await expect(component).toContainText('Submit');
});
test('render attributes', async ({ mount }) => {
const component = await mount(<Button className="primary" title="Submit" />);
await expect(component).toHaveClass('primary');
});
test('render an empty component', async ({ mount, page }) => {
const component = await mount(<EmptyFragment />);
expect(await page.evaluate(() => 'props' in window && window.props)).toEqual({});
expect(await component.allTextContents()).toEqual(['']);
expect(await component.textContent()).toBe('');
await expect(component).toHaveText('');
});

View File

@ -1,14 +0,0 @@
import { test, expect } from '@playwright/experimental-ct-solid';
import App from '@/App';
import type { HooksConfig } from '../playwright';
test('navigate to a page by clicking a link', async ({ page, mount }) => {
const component = await mount<HooksConfig>(<App />, {
hooksConfig: { routing: true },
});
await expect(component.getByRole('main')).toHaveText('Login');
await expect(page).toHaveURL('/');
await component.getByRole('link', { name: 'Dashboard' }).click();
await expect(component.getByRole('main')).toHaveText('Dashboard');
await expect(page).toHaveURL('/dashboard');
});

View File

@ -1,32 +0,0 @@
import { test, expect } from '@playwright/experimental-ct-solid';
import Button from '@/components/Button';
import MultiRoot from '@/components/MultiRoot';
test('unmount', async ({ page, mount }) => {
const component = await mount(<Button title="Submit" />);
await expect(page.locator('#root')).toContainText('Submit');
await component.unmount();
await expect(page.locator('#root')).not.toContainText('Submit');
});
test('unmount a multi root component', async ({ mount, page }) => {
const component = await mount(<MultiRoot />);
await expect(page.locator('#root')).toContainText('root 1');
await expect(page.locator('#root')).toContainText('root 2');
await component.unmount();
await expect(page.locator('#root')).not.toContainText('root 1');
await expect(page.locator('#root')).not.toContainText('root 2');
});
test('unmount twice throws an error', async ({ mount }) => {
const component = await mount(<Button title="Submit" />);
await component.unmount();
await expect(component.unmount()).rejects.toThrowError('Component was not mounted');
});
test('mount then unmount then mount', async ({ mount }) => {
let component = await mount(<Button title="Submit" />);
await component.unmount();
component = await mount(<Button title="Save" />);
await expect(component).toContainText('Save');
});

View File

@ -1,115 +0,0 @@
import { test, expect } from '@playwright/experimental-ct-solid';
import Counter from '@/components/Counter';
import DefaultChildren from '@/components/DefaultChildren';
test('update props without remounting', async ({ mount }) => {
const component = await mount(<Counter count={9001} />);
await expect(component.getByTestId('props')).toContainText('9001');
await component.update(<Counter count={1337} />);
await expect(component).not.toContainText('9001');
await expect(component.getByTestId('props')).toContainText('1337');
/**
* Ideally toContainText('2') should be toContainText('1')
* However it seems impossible to update the props, slots or events of a rendered component
*/
await expect(component.getByTestId('remount-count')).toContainText('2');
});
test('update child props without remounting', async ({ mount }) => {
const component = await mount(<DefaultChildren><Counter count={9001} /></DefaultChildren>);
await expect(component.getByTestId('props')).toContainText('9001');
await component.update(<DefaultChildren><Counter count={1337} /></DefaultChildren>);
await expect(component).not.toContainText('9001');
await expect(component.getByTestId('props')).toContainText('1337');
/**
* Ideally toContainText('2') should be toContainText('1')
* However it seems impossible to update the props, slots or events of a rendered component
*/
await expect(component.getByTestId('remount-count')).toContainText('2');
});
test('update callbacks without remounting', async ({ mount }) => {
const component = await mount(<Counter />);
const messages: string[] = [];
await component.update(
<Counter
onClick={(message) => {
messages.push(message);
}}
/>
);
await component.click();
expect(messages).toEqual(['hello']);
/**
* Ideally toContainText('2') should be toContainText('1')
* However it seems impossible to update the props, slots or events of a rendered component
*/
await expect(component.getByTestId('remount-count')).toContainText('2');
});
test('update child callbacks without remounting', async ({ mount }) => {
const component = await mount(<DefaultChildren><Counter /></DefaultChildren>);
const messages: string[] = [];
await component.update(
<DefaultChildren>
<Counter
onClick={(message) => {
messages.push(message);
}}
/>
</DefaultChildren>
);
await component.getByRole('button').click();
expect(messages).toEqual(['hello']);
/**
* Ideally toContainText('2') should be toContainText('1')
* However it seems impossible to update the props, slots or events of a rendered component
*/
await expect(component.getByTestId('remount-count')).toContainText('2');
});
test('update children without remounting', async ({ mount }) => {
const component = await mount(<Counter>Default Slot</Counter>);
await expect(component).toContainText('Default Slot');
await component.update(<Counter>Test Slot</Counter>);
await expect(component).not.toContainText('Default Slot');
await expect(component).toContainText('Test Slot');
/**
* Ideally toContainText('2') should be toContainText('1')
* However it seems impossible to update the props, slots or events of a rendered component
*/
await expect(component.getByTestId('remount-count')).toContainText('2');
});
test('update grandchild without remounting', async ({ mount }) => {
const component = await mount(
<DefaultChildren>
<Counter>Default Slot</Counter>
</DefaultChildren>
);
await expect(component.getByRole('button')).toContainText('Default Slot');
await component.update(
<DefaultChildren>
<Counter>Test Slot</Counter>
</DefaultChildren>
);
await expect(component.getByRole('button')).not.toContainText('Default Slot');
await expect(component.getByRole('button')).toContainText('Test Slot');
/**
* Ideally toContainText('2') should be toContainText('1')
* However it seems impossible to update the props, slots or events of a rendered component
*/
await expect(component.getByTestId('remount-count')).toContainText('2');
});

View File

@ -1,21 +0,0 @@
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": ["vite/client"],
"noEmit": true,
"isolatedModules": true,
"skipLibCheck": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"*": ["_"],
}
}
}

View File

@ -1,12 +0,0 @@
import { defineConfig } from 'vite';
import solidPlugin from 'vite-plugin-solid';
export default defineConfig({
plugins: [solidPlugin()],
server: {
port: 3000,
},
build: {
target: 'esnext',
},
});

View File

@ -197,11 +197,6 @@ const workspace = new Workspace(ROOT_PATH, [
path: path.join(ROOT_PATH, 'packages', 'playwright-ct-react17'),
files: ['LICENSE'],
}),
new PWPackage({
name: '@playwright/experimental-ct-solid',
path: path.join(ROOT_PATH, 'packages', 'playwright-ct-solid'),
files: ['LICENSE'],
}),
new PWPackage({
name: '@playwright/experimental-ct-svelte',
path: path.join(ROOT_PATH, 'packages', 'playwright-ct-svelte'),