Skip to content
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

type: close の E2E テストを追加する #576

Merged
merged 8 commits into from
Dec 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
VITE_SORA_SIGNALING_URL=ws://127.0.0.1:5000/signaling
# テストに利用する Sora の ChannelID のプレフィックスを指定してください
VITE_SORA_CHANNEL_ID_PREFIX=sora-js-sdk-e2e-test_
# テストに利用するアクセストークンを指定してください、不要であれば何の値でも問題ありません
# テストに利用する Sora の API URL を指定ください、不要であれば空欄で大丈夫です
VITE_SORA_API_URL=http://127.0.0.1:5000/
# テストに利用するアクセストークンを指定してください、不要であれば空欄で大丈夫です
VITE_ACCESS_TOKEN=access_token
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:

jobs:
test:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
strategy:
matrix:
node: ["18", "20", "22"]
Expand Down
12 changes: 9 additions & 3 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ on:
jobs:
e2e-test:
timeout-minutes: 20
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
strategy:
matrix:
node: ["18", "20", "22"]
Expand All @@ -25,9 +25,15 @@ jobs:
env:
VITE_SORA_SIGNALING_URL: ${{ secrets.TEST_SIGNALING_URL }}
VITE_SORA_CHANNEL_ID_PREFIX: ${{ secrets.TEST_CHANNEL_ID_PREFIX }}
VITE_SORA_API_URL: ${{ secrets.TEST_API_URL }}
VITE_ACCESS_TOKEN: ${{ secrets.TEST_SECRET_KEY }}
steps:
- uses: actions/checkout@v4
- uses: tailscale/github-action@v2
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:ci
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
Expand All @@ -48,7 +54,7 @@ jobs:

slack_notify_succeeded:
needs: [e2e-test]
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
if: success()
steps:
- name: Slack Notification
Expand All @@ -62,7 +68,7 @@ jobs:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
slack_notify_failed:
needs: [e2e-test]
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
if: failure()
steps:
- name: Slack Notification
Expand Down
12 changes: 9 additions & 3 deletions .github/workflows/npm-pkg-e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ on:
jobs:
npm-pkg-e2e-test:
timeout-minutes: 20
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
strategy:
matrix:
# メンテナンスはおてて
Expand All @@ -38,10 +38,16 @@ jobs:
env:
VITE_SORA_SIGNALING_URL: ${{ secrets.TEST_SIGNALING_URL }}
VITE_SORA_CHANNEL_ID_PREFIX: ${{ secrets.TEST_CHANNEL_ID_PREFIX }}
VITE_SORA_API_URL: ${{ secrets.TEST_API_URL }}
VITE_ACCESS_TOKEN: ${{ secrets.TEST_SECRET_KEY }}
NPM_PKG_E2E_TEST: true
steps:
- uses: actions/checkout@v4
- uses: tailscale/github-action@v2
with:
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
tags: tag:ci
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
Expand All @@ -66,7 +72,7 @@ jobs:

slack_notify_succeeded:
needs: [npm-pkg-e2e-test]
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
if: success()
steps:
- name: Slack Notification
Expand All @@ -79,7 +85,7 @@ jobs:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
slack_notify_failed:
needs: [npm-pkg-e2e-test]
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
if: failure()
steps:
- name: Slack Notification
Expand Down
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

### misc

- [ADD] E2E テストに `"type": "close"` のテストを追加する
- @voluntas
- [ADD] E2E テストに `"type": "switched"` のテストを追加する
- @voluntas
- [CHANGE] canary リリース方法を `canary.py` に変更する
Expand Down
26 changes: 26 additions & 0 deletions examples/data_channel_signaling_only/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<html lang="ja">

<head>
<meta charset="utf-8">
<title>Sendonly test</title>
</head>

<body>
<div class="container">
<h1>Sendonly test</h1>
<h3 id="sdk-version"></h3>
<button id="connect">connect</button>
<button id="disconnect">disconnect</button>
<button id="disconnect-api">disconnect-api</button>
<button id="get-stats">getStats</button><br />
<div id="connection-id"></div>
<video id="local-video" autoplay="" playsinline="" controls="" muted=""
style="width: 320px; height: 240px; border: 1px solid black;"></video>
<div id="stats-report" style="white-space: pre-wrap; font-family: monospace;"></div>
<div id="stats-report-json"></div>
</div>

<script type="module" src="./main.mts"></script>
</body>

</html>
167 changes: 167 additions & 0 deletions examples/data_channel_signaling_only/main.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import Sora, {
type SignalingNotifyMessage,
type SignalingEvent,
type ConnectionPublisher,
type SoraConnection,
type ConnectionOptions,
} from 'sora-js-sdk'

document.addEventListener('DOMContentLoaded', async () => {
const SORA_SIGNALING_URL = import.meta.env.VITE_SORA_SIGNALING_URL
const SORA_CHANNEL_ID_PREFIX = import.meta.env.VITE_SORA_CHANNEL_ID_PREFIX || ''
const SORA_CHANNEL_ID_SUFFIX = import.meta.env.VITE_SORA_CHANNEL_ID_SUFFIX || ''
const ACCESS_TOKEN = import.meta.env.VITE_ACCESS_TOKEN || ''

const client = new SoraClient(
SORA_SIGNALING_URL,
SORA_CHANNEL_ID_PREFIX,
SORA_CHANNEL_ID_SUFFIX,
ACCESS_TOKEN,
)

// SDK バージョンの表示
const sdkVersionElement = document.querySelector('#sdk-version')
if (sdkVersionElement) {
sdkVersionElement.textContent = `${Sora.version()}`
}

document.querySelector('#connect')?.addEventListener('click', async () => {
const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true })
await client.connect(stream)
})

document.querySelector('#disconnect')?.addEventListener('click', async () => {
await client.disconnect()
})

document.querySelector('#disconnect-api')?.addEventListener('click', async () => {
await client.apiDisconnect()
})

document.querySelector('#get-stats')?.addEventListener('click', async () => {
const statsReport = await client.getStats()
const statsDiv = document.querySelector('#stats-report') as HTMLElement
const statsReportJsonDiv = document.querySelector('#stats-report-json')
if (statsDiv && statsReportJsonDiv) {
let statsHtml = ''
const statsReportJson: Record<string, unknown>[] = []
for (const report of statsReport.values()) {
statsHtml += `<h3>Type: ${report.type}</h3><ul>`
const reportJson: Record<string, unknown> = { id: report.id, type: report.type }
for (const [key, value] of Object.entries(report)) {
if (key !== 'type' && key !== 'id') {
statsHtml += `<li><strong>${key}:</strong> ${value}</li>`
reportJson[key] = value
}
}
statsHtml += '</ul>'
statsReportJson.push(reportJson)
}
statsDiv.innerHTML = statsHtml
// データ属性としても保存(オプション)
statsDiv.dataset.statsReportJson = JSON.stringify(statsReportJson)
}
})
})

class SoraClient {
private debug = false
private channelId: string
private metadata: { access_token: string }
private options: ConnectionOptions = {
dataChannelSignaling: true,
ignoreDisconnectWebSocket: true,
}

private sora: SoraConnection
private connection: ConnectionPublisher

constructor(
signaling_url: string,
channel_id_prefix: string,
channel_id_suffix: string,
access_token: string,
) {
this.sora = Sora.connection(signaling_url, this.debug)

// channel_id の生成
this.channelId = `${channel_id_prefix}sendonly_recvonly${channel_id_suffix}`
// access_token を指定する metadata の生成
this.metadata = { access_token: access_token }

this.connection = this.sora.sendonly(this.channelId, this.metadata, this.options)
this.connection.on('notify', this.onNotify.bind(this))

// E2E テスト用のコード
this.connection.on('signaling', this.onSignaling.bind(this))
}

async connect(stream: MediaStream): Promise<void> {
await this.connection.connect(stream)

const videoElement = document.querySelector<HTMLVideoElement>('#local-video')
if (videoElement !== null) {
videoElement.srcObject = stream
}
}

async disconnect(): Promise<void> {
await this.connection.disconnect()

const videoElement = document.querySelector<HTMLVideoElement>('#local-video')
if (videoElement !== null) {
videoElement.srcObject = null
}
}

getStats(): Promise<RTCStatsReport> {
if (this.connection.pc === null) {
return Promise.reject(new Error('PeerConnection is not ready'))
}
return this.connection.pc.getStats()
}

private onNotify(event: SignalingNotifyMessage): void {
if (
event.event_type === 'connection.created' &&
this.connection.connectionId === event.connection_id
) {
const connectionIdElement = document.querySelector('#connection-id')
if (connectionIdElement) {
connectionIdElement.textContent = event.connection_id
}
}
}

// E2E テスト用のコード
private onSignaling(event: SignalingEvent): void {
if (event.type === 'onmessage-switched') {
console.log('[signaling]', event.type, event.transportType)
}
if (event.type === 'onmessage-close') {
console.log('[signaling]', event.type, event.transportType)
}
}

// E2E テスト側で実行した方が良い気がする
async apiDisconnect(): Promise<void> {
const apiUrl = import.meta.env.VITE_SORA_API_URL
if (apiUrl === '') {
console.error('VITE_SORA_API_URL is not set')
}
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Sora-Target': 'Sora_20151104.DisconnectConnection',
},
body: JSON.stringify({
channel_id: this.channelId,
connection_id: this.connection.connectionId,
}),
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
}
}
4 changes: 4 additions & 0 deletions playwright.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ export default defineConfig({
use: {
launchOptions: {
args: [
// CORS 無効
'--disable-web-security',
'--disable-features=IsolateOrigins,site-per-process',

'--use-fake-ui-for-media-stream',
'--use-fake-device-for-media-stream',
// "--use-file-for-fake-video-capture=/app/sample.mjpeg",
Expand Down
Loading
Loading