enhance: e2eテストをできるだけ改良してみた (#8159)
* update docker image?
* 続
* serial run delete from "${table}" cascade
* use cypress official github action
* refuse install by cypress action
* clean up
* use wait?
* use more wait?
* Revert "use more wait?"
This reverts commit 18d0fcae9c7d8f98a4cafb4a846a031ece57350c.
* Revert "use wait?"
This reverts commit 5aa8feec9cdc3e2f79e566249f0a0eff6c0df6a0.
* fix
* test
* test
* log?
* 握りつぶしてみる
* clean up
* env?
* clean up?
* disable video
* add comment
* remove test
* 成功?
* test browser
* nodeインストール無効化
* node16.13.0-chrome95-ff94
* node.js復活
* ?
* ちょっと戻してみる
* chrome?
* cross browser test2
* --shm-size=2g
* artifact?
* misskey.local?
* firefoxはあきらめる
* not headless?
* oops
* fix
* ??
* test1
* if?
* fail-fast: false
* headless: false
* easy error ignoreing describe
* エラーの解消
とちょっとリファクター
* add browser name to artifact
* Install mplayer for FireFox
* no wait?
* タイムアウトを甘くしてみる
* firefoxをあきらめる(n回目)
* remove timeout setting
* wait復活
* Update basic.js
* Update index.js
Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
			
			
This commit is contained in:
		
							parent
							
								
									cbb7e95d82
								
							
						
					
					
						commit
						e1d69e236f
					
				
					 10 changed files with 99 additions and 71 deletions
				
			
		
							
								
								
									
										39
									
								
								.github/workflows/test.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								.github/workflows/test.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -17,14 +17,14 @@ jobs: | ||||||
| 
 | 
 | ||||||
|     services: |     services: | ||||||
|       postgres: |       postgres: | ||||||
|         image: postgres:12.2-alpine |         image: postgres:13 | ||||||
|         ports: |         ports: | ||||||
|           - 54312:5432 |           - 54312:5432 | ||||||
|         env: |         env: | ||||||
|           POSTGRES_DB: test-misskey |           POSTGRES_DB: test-misskey | ||||||
|           POSTGRES_HOST_AUTH_METHOD: trust |           POSTGRES_HOST_AUTH_METHOD: trust | ||||||
|       redis: |       redis: | ||||||
|         image: redis:4.0-alpine |         image: redis:6 | ||||||
|         ports: |         ports: | ||||||
|           - 56312:6379 |           - 56312:6379 | ||||||
| 
 | 
 | ||||||
|  | @ -51,19 +51,21 @@ jobs: | ||||||
|     runs-on: ubuntu-latest |     runs-on: ubuntu-latest | ||||||
| 
 | 
 | ||||||
|     strategy: |     strategy: | ||||||
|  |       fail-fast: false | ||||||
|       matrix: |       matrix: | ||||||
|         node-version: [16.x] |         node-version: [16.x] | ||||||
|  |         browser: [chrome] | ||||||
| 
 | 
 | ||||||
|     services: |     services: | ||||||
|       postgres: |       postgres: | ||||||
|         image: postgres:12.2-alpine |         image: postgres:13 | ||||||
|         ports: |         ports: | ||||||
|           - 54312:5432 |           - 54312:5432 | ||||||
|         env: |         env: | ||||||
|           POSTGRES_DB: test-misskey |           POSTGRES_DB: test-misskey | ||||||
|           POSTGRES_HOST_AUTH_METHOD: trust |           POSTGRES_HOST_AUTH_METHOD: trust | ||||||
|       redis: |       redis: | ||||||
|         image: redis:4.0-alpine |         image: redis:6 | ||||||
|         ports: |         ports: | ||||||
|           - 56312:6379 |           - 56312:6379 | ||||||
| 
 | 
 | ||||||
|  | @ -71,6 +73,12 @@ jobs: | ||||||
|     - uses: actions/checkout@v2 |     - uses: actions/checkout@v2 | ||||||
|       with: |       with: | ||||||
|         submodules: true |         submodules: true | ||||||
|  |     # https://github.com/cypress-io/cypress-docker-images/issues/150 | ||||||
|  |     #- name: Install mplayer for FireFox | ||||||
|  |     #  run: sudo apt install mplayer -y | ||||||
|  |     #  if: ${{ matrix.browser == 'firefox' }} | ||||||
|  |     #- uses: browser-actions/setup-firefox@latest | ||||||
|  |     #  if: ${{ matrix.browser == 'firefox' }} | ||||||
|     - name: Use Node.js ${{ matrix.node-version }} |     - name: Use Node.js ${{ matrix.node-version }} | ||||||
|       uses: actions/setup-node@v1 |       uses: actions/setup-node@v1 | ||||||
|       with: |       with: | ||||||
|  | @ -87,5 +95,24 @@ jobs: | ||||||
|       run: cp .github/misskey/test.yml .config |       run: cp .github/misskey/test.yml .config | ||||||
|     - name: Build |     - name: Build | ||||||
|       run: yarn build |       run: yarn build | ||||||
|     - name: Test |     # https://github.com/cypress-io/cypress/issues/4351#issuecomment-559489091 | ||||||
|       run: yarn e2e |     - name: ALSA Env | ||||||
|  |       run: echo -e 'pcm.!default {\n type hw\n card 0\n}\n\nctl.!default {\n type hw\n card 0\n}' > ~/.asoundrc | ||||||
|  |     - name: Cypress run | ||||||
|  |       uses: cypress-io/github-action@v2 | ||||||
|  |       with: | ||||||
|  |         install: false | ||||||
|  |         start: npm run start:test | ||||||
|  |         wait-on: 'http://localhost:61812' | ||||||
|  |         headless: false | ||||||
|  |         browser: ${{ matrix.browser }} | ||||||
|  |     - uses: actions/upload-artifact@v2 | ||||||
|  |       if: failure() | ||||||
|  |       with: | ||||||
|  |         name: ${{ matrix.browser }}-cypress-screenshots | ||||||
|  |         path: cypress/screenshots | ||||||
|  |     - uses: actions/upload-artifact@v2 | ||||||
|  |       if: always() | ||||||
|  |       with: | ||||||
|  |         name: ${{ matrix.browser }}-cypress-videos | ||||||
|  |         path: cypress/videos | ||||||
|  |  | ||||||
|  | @ -41,8 +41,6 @@ describe('After setup instance', () => { | ||||||
| 			username: 'admin', | 			username: 'admin', | ||||||
| 			password: 'pass', | 			password: 'pass', | ||||||
| 		}).its('body').as('admin'); | 		}).its('body').as('admin'); | ||||||
| 
 |  | ||||||
| 		cy.get('@admin'); |  | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
| 	afterEach(() => { | 	afterEach(() => { | ||||||
|  | @ -82,7 +80,6 @@ describe('After user signup', () => { | ||||||
| 			password: 'pass', | 			password: 'pass', | ||||||
| 		}).its('body').as('admin'); | 		}).its('body').as('admin'); | ||||||
| 
 | 
 | ||||||
| 		cy.get('@admin').then(() => { |  | ||||||
| 		// ユーザー作成
 | 		// ユーザー作成
 | ||||||
| 		cy.request('POST', '/api/signup', { | 		cy.request('POST', '/api/signup', { | ||||||
| 			username: 'alice', | 			username: 'alice', | ||||||
|  | @ -90,9 +87,6 @@ describe('After user signup', () => { | ||||||
| 		}).its('body').as('alice'); | 		}).its('body').as('alice'); | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
| 		cy.get('@alice'); |  | ||||||
| 	}); |  | ||||||
| 
 |  | ||||||
| 	afterEach(() => { | 	afterEach(() => { | ||||||
| 		// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
 | 		// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
 | ||||||
| 		// waitを入れることでそれを防止できる
 | 		// waitを入れることでそれを防止できる
 | ||||||
|  | @ -145,15 +139,12 @@ describe('After user singed in', () => { | ||||||
| 			password: 'pass', | 			password: 'pass', | ||||||
| 		}).its('body').as('admin'); | 		}).its('body').as('admin'); | ||||||
| 
 | 
 | ||||||
| 		cy.get('@admin').then(() => { |  | ||||||
| 		// ユーザー作成
 | 		// ユーザー作成
 | ||||||
| 		cy.request('POST', '/api/signup', { | 		cy.request('POST', '/api/signup', { | ||||||
| 			username: 'alice', | 			username: 'alice', | ||||||
| 			password: 'alice1234', | 			password: 'alice1234', | ||||||
| 		}).its('body').as('alice'); | 		}).its('body').as('alice'); | ||||||
| 		}); |  | ||||||
| 
 | 
 | ||||||
| 		cy.get('@alice').then(() => { |  | ||||||
| 		cy.visit('/'); | 		cy.visit('/'); | ||||||
| 
 | 
 | ||||||
| 		cy.intercept('POST', '/api/signin').as('signin'); | 		cy.intercept('POST', '/api/signin').as('signin'); | ||||||
|  | @ -165,9 +156,6 @@ describe('After user singed in', () => { | ||||||
| 		cy.wait('@signin').as('signedIn'); | 		cy.wait('@signin').as('signedIn'); | ||||||
| 	}); | 	}); | ||||||
| 
 | 
 | ||||||
| 		cy.get('@signedIn'); |  | ||||||
| 	}); |  | ||||||
| 
 |  | ||||||
| 	afterEach(() => { | 	afterEach(() => { | ||||||
| 		// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
 | 		// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
 | ||||||
| 		// waitを入れることでそれを防止できる
 | 		// waitを入れることでそれを防止できる
 | ||||||
|  |  | ||||||
|  | @ -20,7 +20,13 @@ import './commands' | ||||||
| // require('./commands')
 | // require('./commands')
 | ||||||
| 
 | 
 | ||||||
| Cypress.on('uncaught:exception', (err, runnable) => { | Cypress.on('uncaught:exception', (err, runnable) => { | ||||||
|   if (err.message.includes('ResizeObserver loop limit exceeded')) { | 	if ([ | ||||||
|     return false | 		// Chrome
 | ||||||
|  | 		'ResizeObserver loop limit exceeded', | ||||||
|  | 
 | ||||||
|  | 		// Firefox
 | ||||||
|  | 		'ResizeObserver loop completed with undelivered notifications', | ||||||
|  | 	].some(msg => err.message.includes(msg))) { | ||||||
|  | 		return false; | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -220,7 +220,9 @@ export async function resetDb() { | ||||||
| 		WHERE nspname NOT IN ('pg_catalog', 'information_schema') | 		WHERE nspname NOT IN ('pg_catalog', 'information_schema') | ||||||
| 			AND C.relkind = 'r' | 			AND C.relkind = 'r' | ||||||
| 			AND nspname !~ '^pg_toast';`);
 | 			AND nspname !~ '^pg_toast';`);
 | ||||||
| 		await Promise.all(tables.map(t => t.table).map(x => conn.query(`DELETE FROM "${x}" CASCADE`))); | 		for (const table of tables) { | ||||||
|  | 			await conn.query(`DELETE FROM "${table.table}" CASCADE`); | ||||||
|  | 		} | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	for (let i = 1; i <= 3; i++) { | 	for (let i = 1; i <= 3; i++) { | ||||||
|  |  | ||||||
|  | @ -2,12 +2,12 @@ version: "3" | ||||||
| 
 | 
 | ||||||
| services: | services: | ||||||
|   redistest: |   redistest: | ||||||
|     image: redis:4.0-alpine |     image: redis:6 | ||||||
|     ports: |     ports: | ||||||
|       - "127.0.0.1:56312:6379" |       - "127.0.0.1:56312:6379" | ||||||
| 
 | 
 | ||||||
|   dbtest: |   dbtest: | ||||||
|     image: postgres:12.2-alpine |     image: postgres:13 | ||||||
|     ports: |     ports: | ||||||
|       - "127.0.0.1:54312:5432" |       - "127.0.0.1:54312:5432" | ||||||
|     environment: |     environment: | ||||||
|  |  | ||||||
|  | @ -32,9 +32,7 @@ const props = defineProps<{ | ||||||
| const pagingComponent = ref<InstanceType<typeof MkPagination>>(); | const pagingComponent = ref<InstanceType<typeof MkPagination>>(); | ||||||
| 
 | 
 | ||||||
| defineExpose({ | defineExpose({ | ||||||
| 	prepend: (note) => { | 	pagingComponent, | ||||||
| 		pagingComponent.value?.prepend(note); |  | ||||||
| 	}, |  | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -25,10 +25,10 @@ const emit = defineEmits<{ | ||||||
| 
 | 
 | ||||||
| provide('inChannel', computed(() => props.src === 'channel')); | provide('inChannel', computed(() => props.src === 'channel')); | ||||||
| 
 | 
 | ||||||
| const tlComponent = ref<InstanceType<typeof XNotes>>(); | const tlComponent: InstanceType<typeof XNotes> = $ref(); | ||||||
| 
 | 
 | ||||||
| const prepend = note => { | const prepend = note => { | ||||||
| 	tlComponent.value.prepend(note); | 	tlComponent.pagingComponent?.prepend(note); | ||||||
| 
 | 
 | ||||||
| 	emit('note'); | 	emit('note'); | ||||||
| 
 | 
 | ||||||
|  | @ -38,16 +38,16 @@ const prepend = note => { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const onUserAdded = () => { | const onUserAdded = () => { | ||||||
| 	tlComponent.value.reload(); | 	tlComponent.pagingComponent?.reload(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const onUserRemoved = () => { | const onUserRemoved = () => { | ||||||
| 	tlComponent.value.reload(); | 	tlComponent.pagingComponent?.reload(); | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const onChangeFollowing = () => { | const onChangeFollowing = () => { | ||||||
| 	if (!tlComponent.value.backed) { | 	if (!tlComponent.pagingComponent?.backed) { | ||||||
| 		tlComponent.value.reload(); | 		tlComponent.pagingComponent?.reload(); | ||||||
| 	} | 	} | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -73,12 +73,11 @@ const queue = ref<Item[]>([]); | ||||||
| const offset = ref(0); | const offset = ref(0); | ||||||
| const fetching = ref(true); | const fetching = ref(true); | ||||||
| const moreFetching = ref(false); | const moreFetching = ref(false); | ||||||
| const inited = ref(false); |  | ||||||
| const more = ref(false); | const more = ref(false); | ||||||
| const backed = ref(false); // 遡り中か否か | const backed = ref(false); // 遡り中か否か | ||||||
| const isBackTop = ref(false); | const isBackTop = ref(false); | ||||||
| const empty = computed(() => items.value.length === 0 && !fetching.value && inited.value); | const empty = computed(() => items.value.length === 0); | ||||||
| const error = computed(() => !fetching.value && !inited.value); | const error = ref(false); | ||||||
| 
 | 
 | ||||||
| const init = async (): Promise<void> => { | const init = async (): Promise<void> => { | ||||||
| 	queue.value = []; | 	queue.value = []; | ||||||
|  | @ -105,9 +104,10 @@ const init = async (): Promise<void> => { | ||||||
| 			more.value = false; | 			more.value = false; | ||||||
| 		} | 		} | ||||||
| 		offset.value = res.length; | 		offset.value = res.length; | ||||||
| 		inited.value = true; | 		error.value = false; | ||||||
| 		fetching.value = false; | 		fetching.value = false; | ||||||
| 	}, e => { | 	}, e => { | ||||||
|  | 		error.value = true; | ||||||
| 		fetching.value = false; | 		fetching.value = false; | ||||||
| 	}); | 	}); | ||||||
| }; | }; | ||||||
|  | @ -183,9 +183,8 @@ const fetchMoreAhead = async (): Promise<void> => { | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const prepend = (item: Item): void => { | const prepend = (item: Item): void => { | ||||||
| 	if (rootEl.value == null) return; |  | ||||||
| 
 |  | ||||||
| 	if (props.pagination.reversed) { | 	if (props.pagination.reversed) { | ||||||
|  | 		if (rootEl.value) { | ||||||
| 			const container = getScrollContainer(rootEl.value); | 			const container = getScrollContainer(rootEl.value); | ||||||
| 			if (container == null) return; // TODO? | 			if (container == null) return; // TODO? | ||||||
| 
 | 
 | ||||||
|  | @ -204,9 +203,16 @@ const prepend = (item: Item): void => { | ||||||
| 					more.value = true; | 					more.value = true; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
|  | 		} | ||||||
| 		items.value.push(item); | 		items.value.push(item); | ||||||
| 		// TODO | 		// TODO | ||||||
| 	} else { | 	} else { | ||||||
|  | 		// 初回表示時はunshiftだけでOK | ||||||
|  | 		if (!rootEl.value) { | ||||||
|  | 			items.value.unshift(item); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		const isTop = isBackTop.value || (document.body.contains(rootEl.value) && isTopVisible(rootEl.value)); | 		const isTop = isBackTop.value || (document.body.contains(rootEl.value) && isTopVisible(rootEl.value)); | ||||||
| 
 | 
 | ||||||
| 		if (isTop) { | 		if (isTop) { | ||||||
|  | @ -264,6 +270,7 @@ onDeactivated(() => { | ||||||
| 
 | 
 | ||||||
| defineExpose({ | defineExpose({ | ||||||
| 	items, | 	items, | ||||||
|  | 	backed, | ||||||
| 	reload, | 	reload, | ||||||
| 	fetchMoreAhead, | 	fetchMoreAhead, | ||||||
| 	prepend, | 	prepend, | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| <template> | <template> | ||||||
| <div class="_section"> | <div class="_section"> | ||||||
| 	<XNotes ref="notes" class="_content" :pagination="pagination"/> | 	<XNotes class="_content" :pagination="pagination"/> | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ | ||||||
| 		<option value="replies">{{ $ts.notesAndReplies }}</option> | 		<option value="replies">{{ $ts.notesAndReplies }}</option> | ||||||
| 		<option value="files">{{ $ts.withFiles }}</option> | 		<option value="files">{{ $ts.withFiles }}</option> | ||||||
| 	</MkTab> | 	</MkTab> | ||||||
| 	<XNotes ref="timeline" :no-gap="true" :pagination="pagination"/> | 	<XNotes :no-gap="true" :pagination="pagination"/> | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue