Skip to content

Commit

Permalink
フロントエンドの自動テストスイートを改善して[email protected]にアップデート
Browse files Browse the repository at this point in the history
(AlesInfiny/maris#2169 を反映)
  • Loading branch information
KentaHizume committed Dec 26, 2024
1 parent 1e745f5 commit ce747a5
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 338 deletions.
2 changes: 1 addition & 1 deletion samples/web-csr/dressca-frontend/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"dependencies": {
"@heroicons/vue": "^2.1.5",
"axios": "^1.7.7",
"msw": "~2.3.5",
"msw": "2.7.0",
"@vee-validate/yup": "^4.13.2",
"pinia": "^2.2.5",
"vee-validate": "^4.14.4",
Expand Down
39 changes: 31 additions & 8 deletions samples/web-csr/dressca-frontend/admin/public/mockServiceWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
* - Please do NOT serve this file on production.
*/

const PACKAGE_VERSION = '2.3.5'
const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423'
const PACKAGE_VERSION = '2.7.0'
const INTEGRITY_CHECKSUM = '00729d72e3b82faf54ca8b9621dbb96f'
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
const activeClientIds = new Set()

Expand Down Expand Up @@ -62,7 +62,12 @@ self.addEventListener('message', async function (event) {

sendToClient(client, {
type: 'MOCKING_ENABLED',
payload: true,
payload: {
client: {
id: client.id,
frameType: client.frameType,
},
},
})
break
}
Expand Down Expand Up @@ -155,6 +160,10 @@ async function handleRequest(event, requestId) {
async function resolveMainClient(event) {
const client = await self.clients.get(event.clientId)

if (activeClientIds.has(event.clientId)) {
return client
}

if (client?.frameType === 'top-level') {
return client
}
Expand Down Expand Up @@ -183,12 +192,26 @@ async function getResponse(event, client, requestId) {
const requestClone = request.clone()

function passthrough() {
const headers = Object.fromEntries(requestClone.headers.entries())
// Cast the request headers to a new Headers instance
// so the headers can be manipulated with.
const headers = new Headers(requestClone.headers)

// Remove the "accept" header value that marked this request as passthrough.
// This prevents request alteration and also keeps it compliant with the
// user-defined CORS policies.
const acceptHeader = headers.get('accept')
if (acceptHeader) {
const values = acceptHeader.split(',').map((value) => value.trim())
const filteredValues = values.filter(
(value) => value !== 'msw/passthrough',
)

// Remove internal MSW request header so the passthrough request
// complies with any potential CORS preflight checks on the server.
// Some servers forbid unknown request headers.
delete headers['x-msw-intention']
if (filteredValues.length > 0) {
headers.set('accept', filteredValues.join(', '))
} else {
headers.delete('accept')
}
}

return fetch(requestClone, { headers })
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,43 @@
import { describe, it, expect } from 'vitest';
import { flushPromises, mount } from '@vue/test-utils';
import { describe, it, expect, vi, beforeAll } from 'vitest';
import { flushPromises, mount, VueWrapper } from '@vue/test-utils';
import { router } from '@/router';
import { createPinia, setActivePinia } from 'pinia';
import { createCustomErrorHandler } from '@/shared/error-handler/custom-error-handler';
import ItemsAddView from '@/views/catalog/ItemsAddView.vue';

describe('アイテム追加画面のテスト', () => {
it('アイテムを追加できる', async () => {
const pinia = createPinia();
setActivePinia(pinia);
const customErrorHandler = createCustomErrorHandler();
const wrapper = mount(ItemsAddView, {
global: { plugins: [pinia, router, customErrorHandler] },
});
async function getWrapper() {
const pinia = createPinia();
setActivePinia(pinia);
const customErrorHandler = createCustomErrorHandler();
return mount(ItemsAddView, {
global: { plugins: [pinia, router, customErrorHandler] },
});
}

describe('アイテムを追加できる', () => {
let wrapper: VueWrapper;

beforeAll(async () => {
wrapper = await getWrapper();
});

it('追加画面に遷移できる', async () => {
// Arrange
// Act
await flushPromises();
// Assert
expect(wrapper.html()).toContain('カタログアイテム追加');
});

it('追加ボタンを押下_追加成功_通知モーダルが開く', async () => {
// Arrange
// Act
wrapper.find('button').trigger('click');
await flushPromises();
await vi.waitUntil(() =>
wrapper.findAllComponents({ name: 'NotificationModal' })[0].isVisible(),
);
// Assert
expect(wrapper.html()).toContain('カタログアイテムを追加しました。');
});
});
Original file line number Diff line number Diff line change
@@ -1,71 +1,130 @@
import { describe, it, expect } from 'vitest';
import { flushPromises, mount } from '@vue/test-utils';
import { describe, it, expect, vi, beforeAll } from 'vitest';
import { flushPromises, mount, VueWrapper } from '@vue/test-utils';
import { createPinia, setActivePinia } from 'pinia';
import { createCustomErrorHandler } from '@/shared/error-handler/custom-error-handler';
import ItemsEditView from '@/views/catalog/ItemsEditView.vue';
import { router } from '@/router';

describe('アイテム編集画面_アイテム削除機能のテスト', () => {
it('アイテムを削除できる', async () => {
const pinia = createPinia();
setActivePinia(pinia);
const customErrorHandler = createCustomErrorHandler();
router.push({ name: 'catalog/items/edit', params: { itemId: 1 } });
await router.isReady();
const wrapper = mount(ItemsEditView, {
global: { plugins: [pinia, router, customErrorHandler] },
});
async function getWrapper() {
const pinia = createPinia();
setActivePinia(pinia);
const customErrorHandler = createCustomErrorHandler();
router.push({ name: 'catalog/items/edit', params: { itemId: 1 } });
await router.isReady();
return mount(ItemsEditView, {
global: { plugins: [pinia, router, customErrorHandler] },
});
}

describe('アイテムが削除できる', () => {
let wrapper: VueWrapper;

beforeAll(async () => {
wrapper = await getWrapper();
});

it('編集画面に遷移できる', async () => {
// Arrange
// Act
await flushPromises();
// Assert
expect(wrapper.html()).toContain('カタログアイテム編集');
});

it('削除ボタンを押下_確認モーダルが開く', async () => {
// Arrange
// Act
await wrapper.findAll('button')[0].trigger('click');
// Assert
expect(wrapper.html()).toContain('カタログアイテムを削除します。');
});

it('OKボタンを押下_確認モーダルが閉じる', async () => {
// Arrange
// Act
await wrapper
.findAllComponents({ name: 'ConfirmationModal' })[0]
.findAll('button')[0]
.trigger('click');
await flushPromises();
// Assert
expect(
wrapper.findAllComponents({ name: 'ConfirmationModal' })[0].isVisible(),
).toBeFalsy();
});

it('削除成功_通知モーダルが開く', async () => {
// Arrange
// Act
await vi.waitUntil(() =>
wrapper.findAllComponents({ name: 'NotificationModal' })[0].isVisible(),
);
// Assert
expect(wrapper.html()).toContain('カタログアイテムを削除しました。');
});

it('OKボタンを押下__通知モーダルが閉じる', async () => {
// Act
await wrapper
.findAllComponents({ name: 'NotificationModal' })[0]
.findAll('button')[0]
.trigger('click');
// Assert
expect(
wrapper.findAllComponents({ name: 'NotificationModal' })[0].isVisible(),
).toBeFalsy();
});
});

describe('アイテム編集画面_アイテム更新機能のテスト', () => {
it('アイテムを更新できる', async () => {
const pinia = createPinia();
setActivePinia(pinia);
const customErrorHandler = createCustomErrorHandler();
router.push({ name: 'catalog/items/edit', params: { itemId: 1 } });
await router.isReady();
const wrapper = mount(ItemsEditView, {
global: { plugins: [pinia, router, customErrorHandler] },
});
describe('アイテムが更新できる', () => {
let wrapper: VueWrapper;

beforeAll(async () => {
wrapper = await getWrapper();
});

it('編集画面に遷移できる', async () => {
// Arrange
// Act
await flushPromises();
// Assert
expect(wrapper.html()).toContain('カタログアイテム編集');
});

it('更新ボタンを押下__確認モーダルが開く', async () => {
// Arrange
const editButton = wrapper.findAll('button')[1];
// Act
await editButton.trigger('click');
// Assert
expect(wrapper.html()).toContain('カタログアイテムを更新します。');
});

it('更新成功__通知モーダルが開く', async () => {
// Arrange
// Act
await wrapper
.findAllComponents({ name: 'ConfirmationModal' })[1]
.findAll('button')[0]
.trigger('click');
await flushPromises();
await vi.waitUntil(() =>
wrapper.findAllComponents({ name: 'NotificationModal' })[1].isVisible(),
);
// Assert
expect(
wrapper.findAllComponents({ name: 'ConfirmationModal' })[1].isVisible(),
).toBeFalsy();
expect(wrapper.html()).toContain('カタログアイテムを更新しました。');
});

it('OKボタンを押下__通知モーダルが閉じる', async () => {
// Act
await wrapper
.findAllComponents({ name: 'NotificationModal' })[1]
.findAll('button')[0]
.trigger('click');
// Assert
expect(
wrapper.findAllComponents({ name: 'NotificationModal' })[1].isVisible(),
).toBeFalsy();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
import { describe, it, expect } from 'vitest';
import { flushPromises, mount } from '@vue/test-utils';
import { describe, it, expect, beforeAll } from 'vitest';
import { flushPromises, mount, VueWrapper } from '@vue/test-utils';
import { router } from '@/router';
import { createPinia, setActivePinia } from 'pinia';
import { createCustomErrorHandler } from '@/shared/error-handler/custom-error-handler';
import ItemsView from '@/views/catalog/ItemsView.vue';

describe('アイテム一覧画面のテスト', () => {
it('アイテム一覧が表示できる', async () => {
const pinia = createPinia();
setActivePinia(pinia);
const customErrorHandler = createCustomErrorHandler();
const wrapper = mount(ItemsView, {
global: { plugins: [pinia, router, customErrorHandler] },
});
async function getWrapper() {
const pinia = createPinia();
setActivePinia(pinia);
const customErrorHandler = createCustomErrorHandler();
return mount(ItemsView, {
global: { plugins: [pinia, router, customErrorHandler] },
});
}
describe('アイテム一覧が表示できる', () => {
let wrapper: VueWrapper;

beforeAll(async () => {
wrapper = await getWrapper();
});

it('アイテム一覧画面に遷移できる', async () => {
// Arrange
// Act
await flushPromises();
// Assert
expect(wrapper.html()).toContain('カタログアイテム一覧');
});

it('アイテムが取得した個数分表示される', async () => {
// Arrange
const expectedItemCount = 11;
// Act
const tableRows = wrapper.find('tbody').findAll('tr');
// Assert
expect(tableRows.length).toBe(expectedItemCount);
});
});
Loading

0 comments on commit ce747a5

Please sign in to comment.