mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	test(ct): solid slice by feature (#20048)
This commit is contained in:
		
							parent
							
								
									a7495c3326
								
							
						
					
					
						commit
						ff23b49457
					
				| @ -15,14 +15,22 @@ | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| import { type PlaywrightTestConfig, devices } from '@playwright/experimental-ct-solid'; | import { type PlaywrightTestConfig, devices } from '@playwright/experimental-ct-solid'; | ||||||
|  | import { resolve } from 'path'; | ||||||
| 
 | 
 | ||||||
| const config: PlaywrightTestConfig = { | const config: PlaywrightTestConfig = { | ||||||
|   testDir: 'src', |   testDir: 'tests', | ||||||
|   forbidOnly: !!process.env.CI, |   forbidOnly: !!process.env.CI, | ||||||
|   retries: process.env.CI ? 2 : 0, |   retries: process.env.CI ? 2 : 0, | ||||||
|   reporter: 'html', |   reporter: 'html', | ||||||
|   use: { |   use: { | ||||||
|     trace: 'on-first-retry', |     trace: 'on-first-retry', | ||||||
|  |     ctViteConfig: { | ||||||
|  |       resolve: { | ||||||
|  |         alias: { | ||||||
|  |           '@': resolve(__dirname, './src'), | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|   }, |   }, | ||||||
|   projects: [ |   projects: [ | ||||||
|     { |     { | ||||||
|  | |||||||
| @ -1,169 +0,0 @@ | |||||||
| import { test, expect } from '@playwright/experimental-ct-solid'; |  | ||||||
| import App from './App'; |  | ||||||
| import Button from './components/Button'; |  | ||||||
| import Counter from './components/Counter'; |  | ||||||
| import DefaultChildren from './components/DefaultChildren'; |  | ||||||
| import MultipleChildren from './components/MultipleChildren'; |  | ||||||
| import MultiRoot from './components/MultiRoot'; |  | ||||||
| import EmptyFragment from './components/EmptyFragment'; |  | ||||||
| import type { HooksConfig } from '../playwright'; |  | ||||||
| 
 |  | ||||||
| test.use({ viewport: { width: 500, height: 500 } }); |  | ||||||
| 
 |  | ||||||
| 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('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 slots 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 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('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('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 id="one">One</div> |  | ||||||
|     <div id="two">Two</div> |  | ||||||
|   </DefaultChildren>); |  | ||||||
|   await expect(component.locator('#one')).toContainText('One'); |  | ||||||
|   await expect(component.locator('#two')).toContainText('Two'); |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| test('render a component as slot', 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('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.locator('text=Main Content').click(); |  | ||||||
|   expect(clickFired).toBeTruthy(); |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| test('run hooks', async ({ page, mount }) => { |  | ||||||
|   const messages: string[] = []; |  | ||||||
|   page.on('console', (m) => messages.push(m.text())); |  | ||||||
|   await mount<HooksConfig>(<Button title="Submit" />, { |  | ||||||
|     hooksConfig: { |  | ||||||
|       route: 'A', |  | ||||||
|     }, |  | ||||||
|   }); |  | ||||||
|   expect(messages).toEqual(['Before mount: {"route":"A"}', 'After mount']); |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| 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('get textContent of the empty fragment', async ({ mount }) => { |  | ||||||
|   const component = await mount(<EmptyFragment />); |  | ||||||
|   expect(await component.allTextContents()).toEqual(['']); |  | ||||||
|   expect(await component.textContent()).toBe(''); |  | ||||||
|   await expect(component).toHaveText(''); |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| 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'); |  | ||||||
| }); |  | ||||||
							
								
								
									
										28
									
								
								tests/components/ct-solid/tests/callbacks.spec.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								tests/components/ct-solid/tests/callbacks.spec.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | 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.locator('text=Main Content').click(); | ||||||
|  |   expect(clickFired).toBeTruthy(); | ||||||
|  | }); | ||||||
							
								
								
									
										44
									
								
								tests/components/ct-solid/tests/children.spec.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								tests/components/ct-solid/tests/children.spec.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,44 @@ | |||||||
|  | import { test, expect } from '@playwright/experimental-ct-solid'; | ||||||
|  | import Button from '@/components/Button'; | ||||||
|  | import DefaultChildren from '@/components/DefaultChildren'; | ||||||
|  | import MultipleChildren from '@/components/MultipleChildren'; | ||||||
|  | 
 | ||||||
|  | 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 id="one">One</div> | ||||||
|  |       <div id="two">Two</div> | ||||||
|  |     </DefaultChildren> | ||||||
|  |   ); | ||||||
|  |   await expect(component.locator('#one')).toContainText('One'); | ||||||
|  |   await expect(component.locator('#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'); | ||||||
|  | }); | ||||||
							
								
								
									
										20
									
								
								tests/components/ct-solid/tests/render.spec.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								tests/components/ct-solid/tests/render.spec.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | 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('get textContent of the empty fragment', async ({ mount }) => { | ||||||
|  |   const component = await mount(<EmptyFragment />); | ||||||
|  |   expect(await component.allTextContents()).toEqual(['']); | ||||||
|  |   expect(await component.textContent()).toBe(''); | ||||||
|  |   await expect(component).toHaveText(''); | ||||||
|  | }); | ||||||
							
								
								
									
										14
									
								
								tests/components/ct-solid/tests/solid-router.spec.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tests/components/ct-solid/tests/solid-router.spec.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | 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'); | ||||||
|  | }); | ||||||
							
								
								
									
										19
									
								
								tests/components/ct-solid/tests/unmount.spec.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								tests/components/ct-solid/tests/unmount.spec.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | 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'); | ||||||
|  | }); | ||||||
							
								
								
									
										53
									
								
								tests/components/ct-solid/tests/update.spec.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								tests/components/ct-solid/tests/update.spec.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | |||||||
|  | import { test, expect } from '@playwright/experimental-ct-solid'; | ||||||
|  | import Counter from '@/components/Counter'; | ||||||
|  | 
 | ||||||
|  | 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 slots 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 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'); | ||||||
|  | }); | ||||||
| @ -11,6 +11,10 @@ | |||||||
|     "types": ["vite/client"], |     "types": ["vite/client"], | ||||||
|     "noEmit": true, |     "noEmit": true, | ||||||
|     "isolatedModules": true, |     "isolatedModules": true, | ||||||
|     "skipLibCheck": true |     "skipLibCheck": true, | ||||||
|  |     "baseUrl": ".", | ||||||
|  |     "paths": { | ||||||
|  |       "@/*": ["./src/*"] | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Sander
						Sander