Skip to content

Commit

Permalink
feat: playwright 설정 및 custom reporter 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
llqqssttyy committed Sep 25, 2024
1 parent 221fef5 commit bcee992
Show file tree
Hide file tree
Showing 7 changed files with 475 additions and 1 deletion.
4 changes: 4 additions & 0 deletions frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ storybook-static

# Sentry Config File
.env.sentry-build-plugin
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
18 changes: 18 additions & 0 deletions frontend/e2e/example.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { test, expect } from '@playwright/test';

test('has title', async ({ page }) => {
await page.goto('https://playwright.dev/');

// Expect a title "to contain" a substring.
await expect(page).toHaveTitle(/Playwright/);
});

test('get started link', async ({ page }) => {
await page.goto('https://playwright.dev/');

// Click the get started link.
await page.getByRole('link', { name: 'Get started' }).click();

// Expects page to have a heading with the name of Installation.
await expect(page.getByRole('heading', { name: 'Installation' })).toBeVisible();
});
319 changes: 319 additions & 0 deletions frontend/e2e/slack-reporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@
/* eslint-disable class-methods-use-this */
import type { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';

const getSlackMessage = ({
all,
passed,
failed,
skipped,
duration,
result,
}: {
all: string;
passed: string;
failed: string;
skipped: string;
duration: string;
result: string;
}) => ({
blocks: [
{
type: 'header',
text: {
type: 'plain_text',
text: '🏃 테스트 실행이 시작되었습니다: ',
emoji: true,
},
},
{
type: 'rich_text',
elements: [
{
type: 'rich_text_section',
elements: [],
},
{
type: 'rich_text_list',
style: 'bullet',
elements: [
{
type: 'rich_text_section',
elements: [
{
type: 'text',
text: '실행 시각: ',
},
{
type: 'text',
text: `${new Date().toLocaleDateString('ko-KR', {
year: 'numeric',
month: 'long',
day: 'numeric',
hour: 'numeric',
minute: 'numeric',
second: 'numeric',
hour12: true,
})}`,
},
],
},
{
type: 'rich_text_section',
elements: [
{
type: 'text',
text: '테스트 케이스 수: ',
},
{
type: 'text',
text: all,
},
],
},
],
},
],
},
{
type: 'divider',
},
{
type: 'rich_text',
elements: [
{
type: 'rich_text_section',
elements: [
{
type: 'text',
text: 'SUMMARY',
style: {
bold: true,
},
},
],
},
],
},
{
type: 'rich_text',
elements: [
{
type: 'rich_text_list',
style: 'bullet',
indent: 0,
border: 0,
elements: [
{
type: 'rich_text_section',
elements: [
{
type: 'emoji',
name: 'hourglass',
unicode: '231b',
style: {
bold: true,
},
},
{
type: 'text',
text: ' 테스트 실행 시간: ',
style: {
bold: true,
},
},
{
type: 'text',
text: duration,
},
],
},
{
type: 'rich_text_section',
elements: [
{
type: 'emoji',
name: 'package',
unicode: '1f4e6',
style: {
bold: true,
},
},
{
type: 'text',
text: ' 테스트 결과: ',
style: {
bold: true,
},
},
],
},
],
},
{
type: 'rich_text_list',
style: 'bullet',
indent: 1,
border: 0,
elements: [
{
type: 'rich_text_section',
elements: [
{
type: 'emoji',
name: 'white_check_mark',
unicode: '2705',
},
{
type: 'text',
text: ' 성공: ',
},
{
type: 'text',
text: passed,
},
],
},
{
type: 'rich_text_section',
elements: [
{
type: 'emoji',
name: 'x',
unicode: '274c',
},
{
type: 'text',
text: ' 실패: ',
},
{
type: 'text',
text: failed,
},
],
},
{
type: 'rich_text_section',
elements: [
{
type: 'emoji',
name: 'fast_forward',
unicode: '23e9',
},
{
type: 'text',
text: ' 건너뜀: ',
},
{
type: 'text',
text: skipped,
},
],
},
],
},
],
},
{
type: 'divider',
},
{
type: 'rich_text',
elements: [
{
type: 'rich_text_section',
elements: [
{
type: 'text',
text: result,
},
],
},
],
},
],
});

class MyReporter implements Reporter {
all = 0;

passed = 0;

failed = 0;

skipped = 0;

failsMessage = '';

onBegin(_: FullConfig, suite: Suite) {
this.all = suite.allTests().length;
}

onTestEnd(test: TestCase, result: TestResult) {
switch (result.status) {
case 'failed':
case 'timedOut':
this.addFailMessage(`❌ 테스트 실패: ${test.title}\n>${result.error?.message}`);
this.failed += 1;
break;
case 'skipped':
this.addFailMessage(`⚠️ 테스트 건너뜀: ${test.title}`);
this.skipped += 1;
break;
case 'passed':
this.passed += 1;
break;
default:
break;
}
}

async onEnd(result: FullResult) {
const blockKit = await this.getBlockKit(result);
const webhookUrl = await process.env.SLACK_WEBHOOK_URL;

if (!webhookUrl) {
console.error('SLACK_WEBHOOK_URL 환경 변수가 설정되지 않았습니다.');
return;
}

try {
const response = await fetch(webhookUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(blockKit),
});

if (!response.ok) {
console.error('Slack 메시지 전송 실패:', response.statusText);
} else {
console.log('Slack 메시지 전송 성공');
}
} catch (error) {
console.error('Slack 메시지 전송 중 에러 발생:', error);
}
}

private addFailMessage(message: string) {
this.failsMessage += `\n${message}`;
}

private async getBlockKit(result: FullResult) {
const { duration } = result;
const minutes = Math.floor(duration / 6000);
const seconds = ((duration % 60000) / 1000).toFixed(0);

const resultBlockKit = getSlackMessage({
all: `${this.all}`,
passed: `${this.passed}개`,
failed: `${this.failed}개`,
skipped: `${this.skipped}개`,
duration: `${minutes}${seconds}초`,
result: `${this.failsMessage ? `테스트 실패 ❌\n${this.failsMessage}` : '👍 모든 테스트가 성공적으로 통과했습니다!'}`,
});

return resultBlockKit;
}
}
export default MyReporter;
Loading

0 comments on commit bcee992

Please sign in to comment.