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:
 | 
			
		||||
      postgres:
 | 
			
		||||
        image: postgres:12.2-alpine
 | 
			
		||||
        image: postgres:13
 | 
			
		||||
        ports:
 | 
			
		||||
          - 54312:5432
 | 
			
		||||
        env:
 | 
			
		||||
          POSTGRES_DB: test-misskey
 | 
			
		||||
          POSTGRES_HOST_AUTH_METHOD: trust
 | 
			
		||||
      redis:
 | 
			
		||||
        image: redis:4.0-alpine
 | 
			
		||||
        image: redis:6
 | 
			
		||||
        ports:
 | 
			
		||||
          - 56312:6379
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -51,19 +51,21 @@ jobs:
 | 
			
		|||
    runs-on: ubuntu-latest
 | 
			
		||||
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        node-version: [16.x]
 | 
			
		||||
        browser: [chrome]
 | 
			
		||||
 | 
			
		||||
    services:
 | 
			
		||||
      postgres:
 | 
			
		||||
        image: postgres:12.2-alpine
 | 
			
		||||
        image: postgres:13
 | 
			
		||||
        ports:
 | 
			
		||||
          - 54312:5432
 | 
			
		||||
        env:
 | 
			
		||||
          POSTGRES_DB: test-misskey
 | 
			
		||||
          POSTGRES_HOST_AUTH_METHOD: trust
 | 
			
		||||
      redis:
 | 
			
		||||
        image: redis:4.0-alpine
 | 
			
		||||
        image: redis:6
 | 
			
		||||
        ports:
 | 
			
		||||
          - 56312:6379
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -71,6 +73,12 @@ jobs:
 | 
			
		|||
    - uses: actions/checkout@v2
 | 
			
		||||
      with:
 | 
			
		||||
        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 }}
 | 
			
		||||
      uses: actions/setup-node@v1
 | 
			
		||||
      with:
 | 
			
		||||
| 
						 | 
				
			
			@ -87,5 +95,24 @@ jobs:
 | 
			
		|||
      run: cp .github/misskey/test.yml .config
 | 
			
		||||
    - name: Build
 | 
			
		||||
      run: yarn build
 | 
			
		||||
    - name: Test
 | 
			
		||||
      run: yarn e2e
 | 
			
		||||
    # https://github.com/cypress-io/cypress/issues/4351#issuecomment-559489091
 | 
			
		||||
    - 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',
 | 
			
		||||
			password: 'pass',
 | 
			
		||||
		}).its('body').as('admin');
 | 
			
		||||
 | 
			
		||||
		cy.get('@admin');
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	afterEach(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -82,7 +80,6 @@ describe('After user signup', () => {
 | 
			
		|||
			password: 'pass',
 | 
			
		||||
		}).its('body').as('admin');
 | 
			
		||||
 | 
			
		||||
		cy.get('@admin').then(() => {
 | 
			
		||||
		// ユーザー作成
 | 
			
		||||
		cy.request('POST', '/api/signup', {
 | 
			
		||||
			username: 'alice',
 | 
			
		||||
| 
						 | 
				
			
			@ -90,9 +87,6 @@ describe('After user signup', () => {
 | 
			
		|||
		}).its('body').as('alice');
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
		cy.get('@alice');
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	afterEach(() => {
 | 
			
		||||
		// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
 | 
			
		||||
		// waitを入れることでそれを防止できる
 | 
			
		||||
| 
						 | 
				
			
			@ -145,15 +139,12 @@ describe('After user singed in', () => {
 | 
			
		|||
			password: 'pass',
 | 
			
		||||
		}).its('body').as('admin');
 | 
			
		||||
 | 
			
		||||
		cy.get('@admin').then(() => {
 | 
			
		||||
		// ユーザー作成
 | 
			
		||||
		cy.request('POST', '/api/signup', {
 | 
			
		||||
			username: 'alice',
 | 
			
		||||
			password: 'alice1234',
 | 
			
		||||
		}).its('body').as('alice');
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		cy.get('@alice').then(() => {
 | 
			
		||||
		cy.visit('/');
 | 
			
		||||
 | 
			
		||||
		cy.intercept('POST', '/api/signin').as('signin');
 | 
			
		||||
| 
						 | 
				
			
			@ -165,9 +156,6 @@ describe('After user singed in', () => {
 | 
			
		|||
		cy.wait('@signin').as('signedIn');
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
		cy.get('@signedIn');
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	afterEach(() => {
 | 
			
		||||
		// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
 | 
			
		||||
		// waitを入れることでそれを防止できる
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,13 @@ import './commands'
 | 
			
		|||
// require('./commands')
 | 
			
		||||
 | 
			
		||||
Cypress.on('uncaught:exception', (err, runnable) => {
 | 
			
		||||
  if (err.message.includes('ResizeObserver loop limit exceeded')) {
 | 
			
		||||
    return false
 | 
			
		||||
	if ([
 | 
			
		||||
		// 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')
 | 
			
		||||
			AND C.relkind = 'r'
 | 
			
		||||
			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++) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,12 +2,12 @@ version: "3"
 | 
			
		|||
 | 
			
		||||
services:
 | 
			
		||||
  redistest:
 | 
			
		||||
    image: redis:4.0-alpine
 | 
			
		||||
    image: redis:6
 | 
			
		||||
    ports:
 | 
			
		||||
      - "127.0.0.1:56312:6379"
 | 
			
		||||
 | 
			
		||||
  dbtest:
 | 
			
		||||
    image: postgres:12.2-alpine
 | 
			
		||||
    image: postgres:13
 | 
			
		||||
    ports:
 | 
			
		||||
      - "127.0.0.1:54312:5432"
 | 
			
		||||
    environment:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,9 +32,7 @@ const props = defineProps<{
 | 
			
		|||
const pagingComponent = ref<InstanceType<typeof MkPagination>>();
 | 
			
		||||
 | 
			
		||||
defineExpose({
 | 
			
		||||
	prepend: (note) => {
 | 
			
		||||
		pagingComponent.value?.prepend(note);
 | 
			
		||||
	},
 | 
			
		||||
	pagingComponent,
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,10 +25,10 @@ const emit = defineEmits<{
 | 
			
		|||
 | 
			
		||||
provide('inChannel', computed(() => props.src === 'channel'));
 | 
			
		||||
 | 
			
		||||
const tlComponent = ref<InstanceType<typeof XNotes>>();
 | 
			
		||||
const tlComponent: InstanceType<typeof XNotes> = $ref();
 | 
			
		||||
 | 
			
		||||
const prepend = note => {
 | 
			
		||||
	tlComponent.value.prepend(note);
 | 
			
		||||
	tlComponent.pagingComponent?.prepend(note);
 | 
			
		||||
 | 
			
		||||
	emit('note');
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -38,16 +38,16 @@ const prepend = note => {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
const onUserAdded = () => {
 | 
			
		||||
	tlComponent.value.reload();
 | 
			
		||||
	tlComponent.pagingComponent?.reload();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const onUserRemoved = () => {
 | 
			
		||||
	tlComponent.value.reload();
 | 
			
		||||
	tlComponent.pagingComponent?.reload();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const onChangeFollowing = () => {
 | 
			
		||||
	if (!tlComponent.value.backed) {
 | 
			
		||||
		tlComponent.value.reload();
 | 
			
		||||
	if (!tlComponent.pagingComponent?.backed) {
 | 
			
		||||
		tlComponent.pagingComponent?.reload();
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -73,12 +73,11 @@ const queue = ref<Item[]>([]);
 | 
			
		|||
const offset = ref(0);
 | 
			
		||||
const fetching = ref(true);
 | 
			
		||||
const moreFetching = ref(false);
 | 
			
		||||
const inited = ref(false);
 | 
			
		||||
const more = ref(false);
 | 
			
		||||
const backed = ref(false); // 遡り中か否か
 | 
			
		||||
const isBackTop = ref(false);
 | 
			
		||||
const empty = computed(() => items.value.length === 0 && !fetching.value && inited.value);
 | 
			
		||||
const error = computed(() => !fetching.value && !inited.value);
 | 
			
		||||
const empty = computed(() => items.value.length === 0);
 | 
			
		||||
const error = ref(false);
 | 
			
		||||
 | 
			
		||||
const init = async (): Promise<void> => {
 | 
			
		||||
	queue.value = [];
 | 
			
		||||
| 
						 | 
				
			
			@ -105,9 +104,10 @@ const init = async (): Promise<void> => {
 | 
			
		|||
			more.value = false;
 | 
			
		||||
		}
 | 
			
		||||
		offset.value = res.length;
 | 
			
		||||
		inited.value = true;
 | 
			
		||||
		error.value = false;
 | 
			
		||||
		fetching.value = false;
 | 
			
		||||
	}, e => {
 | 
			
		||||
		error.value = true;
 | 
			
		||||
		fetching.value = false;
 | 
			
		||||
	});
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -183,9 +183,8 @@ const fetchMoreAhead = async (): Promise<void> => {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
const prepend = (item: Item): void => {
 | 
			
		||||
	if (rootEl.value == null) return;
 | 
			
		||||
 | 
			
		||||
	if (props.pagination.reversed) {
 | 
			
		||||
		if (rootEl.value) {
 | 
			
		||||
			const container = getScrollContainer(rootEl.value);
 | 
			
		||||
			if (container == null) return; // TODO?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -204,9 +203,16 @@ const prepend = (item: Item): void => {
 | 
			
		|||
					more.value = true;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		items.value.push(item);
 | 
			
		||||
		// TODO
 | 
			
		||||
	} else {
 | 
			
		||||
		// 初回表示時はunshiftだけでOK
 | 
			
		||||
		if (!rootEl.value) {
 | 
			
		||||
			items.value.unshift(item);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		const isTop = isBackTop.value || (document.body.contains(rootEl.value) && isTopVisible(rootEl.value));
 | 
			
		||||
 | 
			
		||||
		if (isTop) {
 | 
			
		||||
| 
						 | 
				
			
			@ -264,6 +270,7 @@ onDeactivated(() => {
 | 
			
		|||
 | 
			
		||||
defineExpose({
 | 
			
		||||
	items,
 | 
			
		||||
	backed,
 | 
			
		||||
	reload,
 | 
			
		||||
	fetchMoreAhead,
 | 
			
		||||
	prepend,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="_section">
 | 
			
		||||
	<XNotes ref="notes" class="_content" :pagination="pagination"/>
 | 
			
		||||
	<XNotes class="_content" :pagination="pagination"/>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@
 | 
			
		|||
		<option value="replies">{{ $ts.notesAndReplies }}</option>
 | 
			
		||||
		<option value="files">{{ $ts.withFiles }}</option>
 | 
			
		||||
	</MkTab>
 | 
			
		||||
	<XNotes ref="timeline" :no-gap="true" :pagination="pagination"/>
 | 
			
		||||
	<XNotes :no-gap="true" :pagination="pagination"/>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue