feat(tests): add e2e tests for widgets (#8735)
* test(e2e): add baseline for widget tests * chore(repo): enable test running in branch * fix(e2e): set viewport for widget tests * fix(client): add widget identifier classes to widgets * test(e2e): add memo widget test * fix(tests): force select value * fix(tests): force button press for widget addition * fix(tests): invoke select value differently * fix(tests): adjust widget submit * fix(tests): don't explicitly navigate for widget test * fix(tests): click label to hide select popup * fix(tests): just click modal background * fix(tests): adjust modal background selector * fix(tests): click all modal backgrounds * feat(e2e): add test for adding timeline widget * fix(client): add more widget identifier classes * feat(tests): add method abstraction for test cases * fix(tests): force-click overlays * fix(tests): force widget button press * fix(tests): remove timeout from final widget check * feat(tests): add widget removal test case * fix(client): use mk instead of msky as class prefix * fix(tests): check widgets for existence rather than visibility * chore(meta): don't run tests for specific feature branch
This commit is contained in:
		
							parent
							
								
									1c057818c6
								
							
						
					
					
						commit
						708fba989a
					
				
					 16 changed files with 100 additions and 16 deletions
				
			
		
							
								
								
									
										84
									
								
								cypress/integration/widgets.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								cypress/integration/widgets.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
describe('After user signed in', () => {
 | 
			
		||||
	beforeEach(() => {
 | 
			
		||||
		cy.window(win => {
 | 
			
		||||
			win.indexedDB.deleteDatabase('keyval-store');
 | 
			
		||||
		});
 | 
			
		||||
		cy.viewport('macbook-16');
 | 
			
		||||
		cy.request('POST', '/api/reset-db').as('reset');
 | 
			
		||||
		cy.get('@reset').its('status').should('equal', 204);
 | 
			
		||||
		cy.reload(true);
 | 
			
		||||
 | 
			
		||||
		// インスタンス初期セットアップ
 | 
			
		||||
		cy.request('POST', '/api/admin/accounts/create', {
 | 
			
		||||
			username: 'admin',
 | 
			
		||||
			password: 'pass',
 | 
			
		||||
		}).its('body').as('admin');
 | 
			
		||||
 | 
			
		||||
		// ユーザー作成
 | 
			
		||||
		cy.request('POST', '/api/signup', {
 | 
			
		||||
			username: 'alice',
 | 
			
		||||
			password: 'alice1234',
 | 
			
		||||
		}).its('body').as('alice');
 | 
			
		||||
 | 
			
		||||
		cy.visit('/');
 | 
			
		||||
 | 
			
		||||
		cy.intercept('POST', '/api/signin').as('signin');
 | 
			
		||||
 | 
			
		||||
		cy.get('[data-cy-signin]').click();
 | 
			
		||||
		cy.get('[data-cy-signin-username] input').type('alice');
 | 
			
		||||
		cy.get('[data-cy-signin-password] input').type('alice1234{enter}');
 | 
			
		||||
 | 
			
		||||
		cy.wait('@signin').as('signedIn');
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	afterEach(() => {
 | 
			
		||||
		// テスト終了直前にページ遷移するようなテストケース(例えばアカウント作成)だと、たぶんCypressのバグでブラウザの内容が次のテストケースに引き継がれてしまう(例えばアカウントが作成し終わった段階からテストが始まる)。
 | 
			
		||||
		// waitを入れることでそれを防止できる
 | 
			
		||||
		cy.wait(1000);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
  it('widget edit toggle is visible', () => {
 | 
			
		||||
		cy.get('.mk-widget-edit').should('be.visible');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
	it('widget select should be visible in edit mode', () => {
 | 
			
		||||
		cy.get('.mk-widget-edit').click();
 | 
			
		||||
		cy.get('.mk-widget-select').should('be.visible');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
	it('first widget should be removed', () => {
 | 
			
		||||
		cy.get('.mk-widget-edit').click();
 | 
			
		||||
		cy.get('.customize-container:first-child .remove._button').click();
 | 
			
		||||
		cy.get('.customize-container').should('have.length', 2);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	function buildWidgetTest(widgetName) {
 | 
			
		||||
		it(`${widgetName} widget should get added`, () => {
 | 
			
		||||
			cy.get('.mk-widget-edit').click();
 | 
			
		||||
			cy.get('.mk-widget-select select').select(widgetName, { force: true });
 | 
			
		||||
			cy.get('.bg._modalBg.transparent').click({ multiple: true, force: true });
 | 
			
		||||
			cy.get('.mk-widget-add').click({ force: true });
 | 
			
		||||
			cy.get(`.mkw-${widgetName}`).should('exist');
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	buildWidgetTest('memo');
 | 
			
		||||
	buildWidgetTest('notifications');
 | 
			
		||||
	buildWidgetTest('timeline');
 | 
			
		||||
	buildWidgetTest('calendar');
 | 
			
		||||
	buildWidgetTest('rss');
 | 
			
		||||
	buildWidgetTest('trends');
 | 
			
		||||
	buildWidgetTest('clock');
 | 
			
		||||
	buildWidgetTest('activity');
 | 
			
		||||
	buildWidgetTest('photos');
 | 
			
		||||
	buildWidgetTest('digitalClock');
 | 
			
		||||
	buildWidgetTest('federation');
 | 
			
		||||
	buildWidgetTest('postForm');
 | 
			
		||||
	buildWidgetTest('slideshow');
 | 
			
		||||
	buildWidgetTest('serverMetric');
 | 
			
		||||
	buildWidgetTest('onlineUsers');
 | 
			
		||||
	buildWidgetTest('jobQueue');
 | 
			
		||||
	buildWidgetTest('button');
 | 
			
		||||
	buildWidgetTest('aiscript');
 | 
			
		||||
	buildWidgetTest('aichan');
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -2,11 +2,11 @@
 | 
			
		|||
<div class="vjoppmmu">
 | 
			
		||||
	<template v-if="edit">
 | 
			
		||||
		<header>
 | 
			
		||||
			<MkSelect v-model="widgetAdderSelected" style="margin-bottom: var(--margin)">
 | 
			
		||||
			<MkSelect v-model="widgetAdderSelected" style="margin-bottom: var(--margin)" class="mk-widget-select">
 | 
			
		||||
				<template #label>{{ $ts.selectWidget }}</template>
 | 
			
		||||
				<option v-for="widget in widgetDefs" :key="widget" :value="widget">{{ $t(`_widgets.${widget}`) }}</option>
 | 
			
		||||
			</MkSelect>
 | 
			
		||||
			<MkButton inline primary @click="addWidget"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton>
 | 
			
		||||
			<MkButton inline primary class="mk-widget-add" @click="addWidget"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton>
 | 
			
		||||
			<MkButton inline @click="$emit('exit')">{{ $ts.close }}</MkButton>
 | 
			
		||||
		</header>
 | 
			
		||||
		<XDraggable
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
	<XWidgets :edit="editMode" :widgets="defaultStore.reactiveState.widgets.value" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="editMode = false"/>
 | 
			
		||||
 | 
			
		||||
	<button v-if="editMode" class="_textButton" style="font-size: 0.9em;" @click="editMode = false"><i class="fas fa-check"></i> {{ i18n.ts.editWidgetsExit }}</button>
 | 
			
		||||
	<button v-else class="_textButton" style="font-size: 0.9em;" @click="editMode = true"><i class="fas fa-pencil-alt"></i> {{ i18n.ts.editWidgets }}</button>
 | 
			
		||||
	<button v-else class="_textButton mk-widget-edit" style="font-size: 0.9em;" @click="editMode = true"><i class="fas fa-pencil-alt"></i> {{ i18n.ts.editWidgets }}</button>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" :naked="widgetProps.transparent">
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" :naked="widgetProps.transparent" class="mkw-activity">
 | 
			
		||||
	<template #header><i class="fas fa-chart-bar"></i>{{ $ts._widgets.activity }}</template>
 | 
			
		||||
	<template #func><button class="_button" @click="toggleView()"><i class="fas fa-sort"></i></button></template>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :naked="widgetProps.transparent" :show-header="false">
 | 
			
		||||
<MkContainer :naked="widgetProps.transparent" :show-header="false" class="mkw-aichan">
 | 
			
		||||
	<iframe ref="live2d" class="dedjhjmo" src="https://misskey-dev.github.io/mascot-web/?scale=1.5&y=1.1&eyeY=100" @click="touched"></iframe>
 | 
			
		||||
</MkContainer>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader">
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" class="mkw-aiscript">
 | 
			
		||||
	<template #header><i class="fas fa-terminal"></i>{{ $ts._widgets.aiscript }}</template>
 | 
			
		||||
 | 
			
		||||
	<div class="uylguesu _monospace">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :naked="widgetProps.transparent" :show-header="false">
 | 
			
		||||
<MkContainer :naked="widgetProps.transparent" :show-header="false" class="mkw-clock">
 | 
			
		||||
	<div class="vubelbmv">
 | 
			
		||||
		<MkAnalogClock class="clock" :thickness="widgetProps.thickness"/>
 | 
			
		||||
	</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" :foldable="foldable" :scrollable="scrollable">
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" :foldable="foldable" :scrollable="scrollable" class="mkw-federation">
 | 
			
		||||
	<template #header><i class="fas fa-globe"></i>{{ $ts._widgets.federation }}</template>
 | 
			
		||||
 | 
			
		||||
	<div class="wbrkwalb">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader">
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" class="mkw-memo">
 | 
			
		||||
	<template #header><i class="fas fa-sticky-note"></i>{{ $ts._widgets.memo }}</template>
 | 
			
		||||
 | 
			
		||||
	<div class="otgbylcu">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :style="`height: ${widgetProps.height}px;`" :show-header="widgetProps.showHeader" :scrollable="true">
 | 
			
		||||
<MkContainer :style="`height: ${widgetProps.height}px;`" :show-header="widgetProps.showHeader" :scrollable="true" class="mkw-notifications">
 | 
			
		||||
	<template #header><i class="fas fa-bell"></i>{{ $ts.notifications }}</template>
 | 
			
		||||
	<template #func><button class="_button" @click="configureNotification()"><i class="fas fa-cog"></i></button></template>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" :naked="widgetProps.transparent" :class="$style.root" :data-transparent="widgetProps.transparent ? true : null">
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" :naked="widgetProps.transparent" :class="$style.root" :data-transparent="widgetProps.transparent ? true : null" class="mkw-photos">
 | 
			
		||||
	<template #header><i class="fas fa-camera"></i>{{ $ts._widgets.photos }}</template>
 | 
			
		||||
 | 
			
		||||
	<div class="">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<XPostForm class="_panel" :fixed="true" :autofocus="false"/>
 | 
			
		||||
<XPostForm class="_panel mkw-postForm" :fixed="true" :autofocus="false"/>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader">
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" class="mkw-rss">
 | 
			
		||||
	<template #header><i class="fas fa-rss-square"></i>RSS</template>
 | 
			
		||||
	<template #func><button class="_button" @click="configure"><i class="fas fa-cog"></i></button></template>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<div class="kvausudm _panel" :style="{ height: widgetProps.height + 'px' }">
 | 
			
		||||
<div class="kvausudm _panel mkw-slideshow" :style="{ height: widgetProps.height + 'px' }">
 | 
			
		||||
	<div @click="choose">
 | 
			
		||||
		<p v-if="widgetProps.folderId == null">
 | 
			
		||||
			{{ $ts.folder }}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" :style="`height: ${widgetProps.height}px;`" :scrollable="true">
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" :style="`height: ${widgetProps.height}px;`" :scrollable="true" class="mkw-timeline">
 | 
			
		||||
	<template #header>
 | 
			
		||||
		<button class="_button" @click="choose">
 | 
			
		||||
			<i v-if="widgetProps.src === 'home'" class="fas fa-home"></i>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
<template>
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader">
 | 
			
		||||
<MkContainer :show-header="widgetProps.showHeader" class="mkw-trends">
 | 
			
		||||
	<template #header><i class="fas fa-hashtag"></i>{{ $ts._widgets.trends }}</template>
 | 
			
		||||
 | 
			
		||||
	<div class="wbrkwala">
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue