-
-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
結合テストを導入 #697
Open
HosokawaR
wants to merge
9
commits into
main
Choose a base branch
from
feature/integration-tests
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
結合テストを導入 #697
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
c0316c5
Add environment variables to toggle GA and Sentry
HosokawaR 5d327d1
Use <button> for toggle button's clickable parts
HosokawaR 100a6c4
Introduce Playwright
HosokawaR c14f49b
Add tests
HosokawaR 7e01778
Modify tests command
HosokawaR 8f94c8e
Make use full core in CI
HosokawaR ef5391c
Make CI faster
HosokawaR a618941
Modify mock
HosokawaR ead124a
Add Document about Integration tests
HosokawaR File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
name: CI / Playwright | ||
on: [push] | ||
jobs: | ||
test: | ||
timeout-minutes: 60 | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: 16 | ||
cache: 'yarn' | ||
|
||
- name: Install dependencies | ||
run: yarn install --frozen-lockfile | ||
|
||
- name: Install Playwright Browsers | ||
run: yarn playwright install chromium webkit --with-deps | ||
|
||
- name: Run Playwright tests | ||
run: yarn test:integration | ||
|
||
- uses: actions/upload-artifact@v3 | ||
if: always() | ||
with: | ||
name: playwright-report | ||
path: playwright-report/ | ||
retention-days: 30 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,6 @@ dist-ssr | |
*.local | ||
tsconfig.staged.json | ||
storybook-static | ||
/test-results/ | ||
/playwright-report/ | ||
/playwright/.cache/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
# Integration Tests Guide | ||
|
||
Twin:te Front では [Playwright](https://playwright.dev/) を利用した結合テストを実施しています。 | ||
|
||
## 実行 | ||
|
||
ブラウザバイナリなどの依存をインストール | ||
|
||
```console | ||
yarn playwright install --with-deps | ||
``` | ||
|
||
テストを実行 | ||
|
||
```console | ||
yarn test:integration # ヘッドレスモードで実行 | ||
yarn test:integration --headed # ブラウザを表示して実行 | ||
yarn test:integration --ui # 専用の GUI で実行 | ||
``` | ||
|
||
## 方針 | ||
|
||
このテストでは最低限のユーザの行動を実行できることを保証します。 | ||
例えば以下のような内容です。 | ||
|
||
- 授業を検索したら授業結果が表示される | ||
- 検索結果でチェックボックスを押すと授業が選択され、追加ボタンがアクティブになり押せる | ||
|
||
反対に以下のような網羅性の高さは保証しません。 | ||
|
||
- 授業検索でそれぞれの時限指定の入力パターンで正しく表示されるか | ||
- スマホ、タブレット、PC のそれぞれで正しく表示されるか | ||
- Twin:te は 8, 9 割がスマホでの利用なので結合テストでは基本的にスマホのみを対象とします | ||
|
||
## 背景 | ||
|
||
Twin:te Front 過去に重大な不具合が長期間放置されていたことがあります。 | ||
|
||
- アーキテクチャの以降時にバグが混入し、KdB もどきからのインポートが 3 ヶ月間ほどできない状態で放置されていた | ||
- パッケージアップグレード時にライブラリの仕様が変わり、一部のトグルボタンが半年ほど機能しない状態で放置されていた | ||
|
||
これらの不具合は QA をリリース前に行っていれば防げたものである一方、安定した開発リソースが無い Twin:te ではリリース前に毎回 QA を行うことは難しいです。 | ||
そこで QA の一部を代替するために結合テストを導入しました。 | ||
|
||
詳細は [https://github.com/twin-te/twinte-front/issues/689] を参照してください。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { defineConfig, devices } from '@playwright/test'; | ||
|
||
/** | ||
* See https://playwright.dev/docs/test-configuration. | ||
*/ | ||
export default defineConfig({ | ||
testDir: './tests', | ||
fullyParallel: true, | ||
forbidOnly: !!process.env.CI, | ||
retries: process.env.CI ? 2 : 0, | ||
workers: process.env.CI ? "100%" : undefined, | ||
reporter: 'html', | ||
use: { | ||
baseURL: 'http://localhost:8080', | ||
trace: 'on-first-retry', | ||
}, | ||
projects: [ | ||
// Twin:te ユーザの大半はモバイルからの利用なので、モバイルに絞ってテストを書く | ||
// PC のレイアウトも考慮すると要素の表示・非表示など考慮することが多くなるため | ||
{ | ||
name: 'Mobile Chrome', | ||
use: { ...devices['Pixel 5'] }, | ||
}, | ||
{ | ||
name: 'Mobile Safari', | ||
use: { ...devices['iPhone 12'] }, | ||
}, | ||
], | ||
webServer: { | ||
command: 'VITE_API_URL=http://localhost:8080/api/v3 yarn preview', | ||
url: 'http://localhost:8080', | ||
reuseExistingServer: !process.env.CI, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { Page } from "@playwright/test"; | ||
|
||
const API_BASE_URL = `http://localhost:8080/api/v3`; | ||
|
||
type Method = "GET" | "POST" | "PUT" | "DELETE"; | ||
|
||
// route.fulfill function's parameter type | ||
type fullfillOptions = Parameters< | ||
Parameters<Parameters<Page["route"]>[1]>[0]["fulfill"] | ||
>[0]; | ||
|
||
export const mockApi = async ( | ||
page: Page, | ||
path: string | RegExp, | ||
responses: { | ||
[K in Method]?: fullfillOptions; | ||
}, | ||
): Promise<void> => { | ||
const routeTarget = typeof path === "string" | ||
? `${API_BASE_URL}${path}` | ||
: (url: URL) => | ||
url.href.startsWith(API_BASE_URL) && path.test(url.pathname); | ||
page.route(routeTarget, async (route) => { | ||
for (const [method, response] of Object.entries(responses)) { | ||
if (route.request().method() === method) await route.fulfill(response); | ||
} | ||
}); | ||
}; | ||
|
||
export const USER_ID = `00000000-0000-0000-0000-000000000000`; | ||
export const DUMMY_COURSE = { | ||
"recommendedGrades": [2], | ||
"id": "00000000-0000-0000-0000-000000000000", | ||
"year": 2023, | ||
"code": "XX000000", | ||
"name": "ダミー講義名", | ||
"instructor": "ダミー講義の講師", | ||
"credit": 2, | ||
"overview": "ダミー講義の説明文", | ||
"remarks": "対面", | ||
"lastUpdate": "2023-03-28T01:21:32.000Z", | ||
"hasParseError": false, | ||
"isAnnual": false, | ||
"methods": ["Asynchronous"], | ||
"schedules": [ | ||
{ "module": "SpringA", "day": "Mon", "period": 5, "room": "" }, | ||
{ "module": "SpringA", "day": "Mon", "period": 6, "room": "" }, | ||
{ "module": "SpringA", "day": "Mon", "period": 5, "room": "" }, | ||
{ "module": "SpringA", "day": "Mon", "period": 6, "room": "" }, | ||
], | ||
}; | ||
export const DUMMY_REGISTERED_COURSE = { | ||
"tags": [], | ||
"id": "00000000-0000-0000-0000-000000000000", | ||
"userId": "00000000-0000-0000-0000-000000000000", | ||
"year": 2023, | ||
"memo": "", | ||
"attendance": 0, | ||
"absence": 0, | ||
"late": 0, | ||
"course": DUMMY_COURSE, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { expect, test } from "@playwright/test"; | ||
import { | ||
DUMMY_COURSE, | ||
DUMMY_REGISTERED_COURSE, | ||
mockApi, | ||
USER_ID, | ||
} from "./mock"; | ||
|
||
test.beforeEach(async ({ page }) => { | ||
await mockApi(page, "/users/me", { | ||
"GET": { json: { id: USER_ID } }, | ||
}); | ||
await mockApi(page, /events/, { | ||
"GET": { json: [] }, | ||
}); | ||
await mockApi(page, /information/, { | ||
"GET": { json: [] }, | ||
}); | ||
await mockApi(page, /school-calendar\/modules/, { | ||
"GET": { | ||
json: [ | ||
{ | ||
"id": 1, | ||
"year": 2023, | ||
"module": "SpringA", | ||
"start": "2023-04-05T00:00:00.000Z", | ||
"end": "2024-03-31T00:00:00.000Z", | ||
}, | ||
], | ||
}, | ||
}); | ||
await mockApi(page, "/courses/search", { | ||
"POST": { json: [DUMMY_COURSE] }, | ||
}); | ||
await mockApi(page, /registered-courses/, { | ||
"GET": { json: [] }, | ||
}); | ||
await mockApi(page, "/registered-courses", { | ||
"POST": { json: [DUMMY_REGISTERED_COURSE] }, | ||
}); | ||
}); | ||
|
||
test.describe("授業の検索", () => { | ||
test("検索して追加できる", async ({ page }) => { | ||
await page.goto("/add/search"); | ||
|
||
// 検索 | ||
await page.getByPlaceholder("例)情報 倫理").fill("ダミー講義名"); | ||
await page.getByRole("button").filter({ hasText: "search" }).click(); | ||
await expect(page.locator(".search__result")).toContainText("ダミー講義名"); | ||
|
||
// 選択して追加 | ||
await page.getByText("done").click(); | ||
await page.getByRole("button").filter({ hasText: "選択した授業を追加" }).click(); | ||
await expect(page).toHaveTitle("Twin:te | ホーム"); | ||
await expect(page.locator(".table")).toContainText("ダミー講義名"); | ||
}); | ||
|
||
test("検索結果の詳細と簡易を切り替えられる", async ({ page }) => { | ||
await page.goto("/add/search"); | ||
|
||
// 検索 | ||
await page.getByPlaceholder("例)情報 倫理").fill("ダミー講義名"); | ||
await page.getByRole("button").filter({ hasText: "search" }).click(); | ||
await expect(page.locator(".search__result")).toContainText("ダミー講義名"); | ||
|
||
// 簡易モードで検索結果を表示 | ||
await page.getByRole("button").filter({ hasText: "簡易" }).click(); | ||
await expect(page.getByText("ダミー講義名")).toBeVisible(); | ||
await expect(page.getByText("ダミー講義の説明文")).not.toBeVisible(); | ||
|
||
// 詳細モードで検索結果を表示 | ||
await page.getByRole("button").filter({ hasText: "詳細" }).click(); | ||
await expect(page.getByText("ダミー講義名")).toBeVisible(); | ||
await expect(page.getByText("ダミー講義の説明文")).toBeVisible(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2033,6 +2033,16 @@ | |
tiny-glob "^0.2.9" | ||
tslib "^2.4.0" | ||
|
||
"@playwright/test@^1.33.0": | ||
version "1.33.0" | ||
resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.33.0.tgz#669ef859efb81b143dfc624eef99d1dd92a81b67" | ||
integrity sha512-YunBa2mE7Hq4CfPkGzQRK916a4tuZoVx/EpLjeWlTVOnD4S2+fdaQZE0LJkbfhN5FTSKNLdcl7MoT5XB37bTkg== | ||
dependencies: | ||
"@types/node" "*" | ||
playwright-core "1.33.0" | ||
optionalDependencies: | ||
fsevents "2.3.2" | ||
|
||
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": | ||
version "1.1.2" | ||
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" | ||
|
@@ -7121,6 +7131,11 @@ fs.realpath@^1.0.0: | |
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" | ||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== | ||
|
||
[email protected], fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: | ||
version "2.3.2" | ||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" | ||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== | ||
|
||
fsevents@^1.2.7: | ||
version "1.2.13" | ||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" | ||
|
@@ -7129,11 +7144,6 @@ fsevents@^1.2.7: | |
bindings "^1.5.0" | ||
nan "^2.12.1" | ||
|
||
fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: | ||
version "2.3.2" | ||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" | ||
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== | ||
|
||
function-bind@^1.1.1: | ||
version "1.1.1" | ||
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" | ||
|
@@ -10318,6 +10328,11 @@ pkg-dir@^5.0.0: | |
dependencies: | ||
find-up "^5.0.0" | ||
|
||
[email protected]: | ||
version "1.33.0" | ||
resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.33.0.tgz#269efe29a927cd6d144d05f3c2d2f72bd72447a1" | ||
integrity sha512-aizyPE1Cj62vAECdph1iaMILpT0WUDCq3E6rW6I+dleSbBoGbktvJtzS6VHkZ4DKNEOG9qJpiom/ZxO+S15LAw== | ||
|
||
[email protected]: | ||
version "1.6.4" | ||
resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Twin:te ではソースコード中のコメントなどが英語で書かれていますが、テストではなるべく日本語で書きたいと思います。理由は以下です。