今回は、 Outlook 用アドインの開発において、随時アップデートされる Outlook on the web(OWA)上でアドインが継続して正常に動作するかを確認する必要があるため、 Azure Pipelines から OWA にアクセスし、Playwright を使ってメール送信の自動テストを実行できるかを検証しました。
Azure App Testing とは
Azure App Testing では、Playwright Workspaces を使って Playwright によるテストをクラウド上で実行できます。Playwright Workspaces は、Playwright をベースにした E2E テスト向けのマネージドサービスで、クラウド上のブラウザーで並列実行できます。
今回の検証では、Azure Pipelines から Azure App Testing の Playwright Workspaces を経由して Outlook on the web にアクセスしました。
環境
利用した主なサービス・ツールは以下です。
| 種類 | 内容 |
|---|---|
| CI/CD | Azure DevOps - Azure Pipelines |
| 実行基盤 | Azure App Testing - Playwright Workspaces |
| テスト対象 | Outlook on the web |
| 実行ブラウザー | Chromium |
| ランタイム | Node.js |
検証目的
今回の検証目的は、Azure Pipelines 上から Outlook on the web にアクセスし、Playwright を使ってメール送信操作を自動化できるか確認することです。
具体的には、以下を確認しました。
- Azure Pipelines から Playwright テストを実行できること
- Outlook on the web に M365 テストアカウントでログインできること
- 新規メール作成画面を開けること
- 宛先、件名、本文を入力できること
- メール送信ボタンをクリックして送信操作を実行できること
- 失敗時にスクリーンショットや Trace を確認できること
全体構成
今回の構成は以下のイメージです。
Azure Pipelines では、Service Connection を使って Azure へ認証し、Playwright Workspaces へ接続しました。
具体的な検証手順
1. M365 テストアカウントを準備する
まず、Outlook on the web にログインするための M365 テストアカウントを準備します。
メール送信テストでは実際にメールが送信される可能性があるため、通常利用者のアカウントではなく、テスト専用アカウントを利用するのが望ましいです。
また、CI 実行時に MFA を要求されるとテストが停止する可能性があります。そのため、検証用アカウントについては MFA を要求されないようにしておく必要があります。
2. Azure App Testing の Playwright Workspace を作成する
Azure portal から Azure App Testing の Playwright Workspace を作成しました。作成後、Workspace のブラウザエンドポイントを確認し、Azure Pipelines の変数として登録します。
PLAYWRIGHT_SERVICE_URL = wss://eastasia.api.playwright.microsoft.com/playwrightworkspaces/...
3. Azure DevOps の Service Connection を作成する
Azure Pipelines から Azure リソースへアクセスするため、Azure DevOps で Service Connection を作成しました。
作成した Service Connection は、YAML の AzureCLI@2 タスクで指定します。
azureSubscription: 'sc-playwright-workspace-dev'
認証方式は、 Workload identity federation を利用するのが望ましいです。シークレットを持たずに Azure へ認証できます。
4. Playwright プロジェクトを準備する
テストコードは以下のような構成にしました。
e2e/
specs/
send-mail.spec.ts
helpers/
owa-helper.ts
fixtures/
recipients.ts
playwright.config.ts
specs にはテストシナリオを書き、OWA の起動、ログイン、新規メール作成、メール送信などの共通処理は owa-helper.ts に寄せました。
5. playwright.config.ts を作成する
Playwright の設定です。
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './e2e',
timeout: 180_000,
retries: 1,
workers: 1,
reporter: [
['html', { open: 'never' }],
['list']
],
use: {
baseURL: 'https://outlook.office.com',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure'
},
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome']
}
}
]
});
OWA の読み込みやサインインには時間がかかる場合があるため、通常の Web アプリよりも timeout はやや長めに設定しました。
timeout: 180_000
また、CI 上での失敗原因を確認しやすくするため、Trace、Screenshot、Video を保存する設定にしています。
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure'
6. OWA 操作用 helper を作成する
Outlook on the web の起動、ログイン、新規メール作成、メール送信処理は、各 spec に直接書かず helper にまとめました。
例:
import { expect, Page } from '@playwright/test';
export type SendMailOptions = {
to: string;
subject: string;
body: string;
};
export async function openOwa(page: Page): Promise<void> {
// OWA のメール画面へ遷移する
await page.goto('https://outlook.office.com/mail/');
// ログイン処理を実装する
// - メールアドレス入力
// - パスワード入力
// - サインイン状態の確認
// - OWA の受信トレイ表示待ち
// OWA 配下へ戻っていることを確認
await expect(page).toHaveURL(/outlook\.office\.com/);
}
export async function composeAndSendMail(
page: Page,
options: SendMailOptions
): Promise<void> {
// 新規メール画面を開く
await page.getByRole('button', { name: '新規メール' }).click();
// 宛先候補が表示されるため、入力後に Enter で確定する
await page.getByLabel('宛先').fill(options.to);
// 件名と本文を順に入力する
await page.getByPlaceholder('件名').fill(options.subject);
await page.getByLabel('メッセージ本文').fill(options.body);
// 送信ボタンを押し、OWA 側の送信処理を開始する
await page.getByLabel('送信', { exact: true }).click();
}
export async function expectComposeClosed(page: Page): Promise<void> {
// 作成画面が閉じたことを、送信ボタンの非表示で確認する
await expect(
page.getByRole('button', { name: /送信|Send/ })
).toBeHidden({ timeout: 30_000 });
}
7. テストデータを共通化する
宛先情報などは recipients.ts に分離しました。
export const testRecipient = {
displayName: 'Test Recipient',
emailAddress: process.env.OWA_RECIPIENT_EMAIL?.trim()
};
8. spec を実装する
実送信を伴うテストは危険があるため、OWA_ALLOW_SEND=true のときだけ動くようにしました。これにより、通常の CI 実行で誤ってメール送信されるリスクを抑えられます。
import { expect, test } from '@playwright/test';
import {
composeAndSendMail,
expectComposeClosed,
openOwa
} from '../helpers/owa-helper';
import { testRecipient } from '../fixtures/recipients';
test.describe('Outlook on the web - メール送信', () => {
test('[MAIL-SEND-001] OWA からメールを送信できる', async ({ page }) => {
test.skip(
process.env.OWA_ALLOW_SEND !== 'true',
'実メール送信は OWA_ALLOW_SEND=true の場合のみ実行します。'
);
await openOwa(page);
await composeAndSendMail(page, {
to: testRecipient.emailAddress,
subject: 'Test Subject',
body: 'Test Body'
});
await expectComposeClosed(page);
await expect(page.getByText('送信しました')).toBeVisible({
timeout: 30_000
}).catch(() => {
// OWA の通知文言は環境や言語設定で変わる可能性があるため、
// 作成画面が閉じたことを主な確認ポイントにする。
});
});
});
9. Azure Pipelines の YAML を作成する
Azure Pipelines では、以下のような YAML を使いました。
PLAYWRIGHT_SERVICE_URL、M365_TEST_USER、M365_TEST_PASSWORD は Pipeline の環境変数として管理しました。また、メール送信を実行する場合のみ、OWA_ALLOW_SEND は true を設定します。
trigger: none
pr: none
schedules:
- cron: '30 1 * * *'
displayName: 'Daily 10:30 JST'
branches:
include:
- main
always: true
pool:
vmImage: 'ubuntu-latest'
variables:
E2E_WORKDIR: '.'
stages:
- stage: E2E
displayName: 'Run Outlook Add-in E2E tests'
jobs:
- job: PlaywrightWorkspace
displayName: 'Run tests with Azure App Testing Playwright Workspaces'
steps:
- task: UseNode@1
displayName: 'Use Node.js'
inputs:
version: '24.x'
- script: npm ci
displayName: 'Install dependencies'
workingDirectory: '$(E2E_WORKDIR)'
- task: AzureCLI@2
displayName: 'Run Playwright tests'
inputs:
azureSubscription: 'sc-playwright-workspace-dev'
scriptType: 'pscore'
scriptLocation: 'inlineScript'
inlineScript: |
npx playwright test --workers=1
addSpnToEnvironment: true
workingDirectory: '$(E2E_WORKDIR)'
env:
PLAYWRIGHT_SERVICE_URL: $(PLAYWRIGHT_SERVICE_URL)
M365_TEST_USER: $(M365_TEST_USER)
M365_TEST_PASSWORD: $(M365_TEST_PASSWORD)
OWA_ALLOW_SEND: $(OWA_ALLOW_SEND)
- task: PublishPipelineArtifact@1
displayName: 'Upload Playwright report'
condition: always()
inputs:
targetPath: '$(E2E_WORKDIR)/playwright-report'
artifact: 'playwright-report'
publishLocation: 'pipeline'
- task: PublishPipelineArtifact@1
displayName: 'Upload test results'
condition: always()
inputs:
targetPath: '$(E2E_WORKDIR)/test-results'
artifact: 'test-results'
publishLocation: 'pipeline'
結果
今回の検証により、Azure Pipelines から Azure App Testing の Playwright Workspaces を使って、Outlook on the web 上でメール送信できることを確認できました。

今回の検証で得た気づき
1. spec は薄く、 helper を厚くするのがよい
OWA の起動、ログイン、新規メール作成、送信ボタンの操作は複雑になりがちです。そのため、spec に OWA 操作を直接書くと、テストの意図が読みにくくなります。
await composeAndSendMail(page, {
to: testRecipient.emailAddress,
subject: 'Test Subject',
body: 'Test Body'
});
のように helper に隠蔽すると、spec は「何を検証しているのか」に集中できます。
2. UI 変更に備える必要がある
Outlook on the web は Microsoft 側の UI 変更が入る可能性があります。
そのため、できるだけ以下を意識しました。
- 表示文言を使う場合は変更可能性を理解しておく
- role ベースの locator を使う
3. Trace と Screenshot は必須
OWA のような外部サービス UI を含む E2E テストでは、失敗原因が locator なのか、認証なのか、読み込み遅延なのかを判断しづらいです。
そのため、以下は必須に近いと感じました。
use: {
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure'
}
失敗時に Trace を確認できると、再現が難しい CI 上の失敗も追いやすくなります。

