Skip to content

Commit

Permalink
test: VVPPデフォルトエンジンを使うテストを書く (VOICEVOX#2444)
Browse files Browse the repository at this point in the history
  • Loading branch information
Hiroshiba authored Dec 29, 2024
1 parent 13cb1d5 commit 7cc32cc
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 34 deletions.
17 changes: 17 additions & 0 deletions .env.test-electron-default-vvpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# VVPPデフォルトエンジンでのテスト用の.envファイル。

VITE_APP_NAME=voicevox
VITE_DEFAULT_ENGINE_INFOS=`[
{
"type": "downloadVvpp",
"name": "VOICEVOX Nemo Engine",
"uuid": "208cf94d-43d2-4cf5-abc0-9783cac36d29",
"executionEnabled": true,
"executionArgs": [],
"host": "http://127.0.0.1:50121",
"latestUrl": "https://voicevox.hiroshiba.jp/nemoLatestDefaultEngineInfos.json"
}
]`
VITE_OFFICIAL_WEBSITE_URL=https://voicevox.hiroshiba.jp/
VITE_LATEST_UPDATE_INFOS_URL=https://voicevox.hiroshiba.jp/updateInfos.json
VITE_GTM_CONTAINER_ID=GTM-DUMMY
2 changes: 1 addition & 1 deletion src/backend/electron/engineAndVvppController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ export class EngineAndVvppController {
await this.vvppManager.install(vvppPath);
return true;
} catch (e) {
log.error(`Failed to install ${vvppPath},`, e);
dialog.showErrorBox(
"インストールエラー",
`${vvppPath} をインストールできませんでした。`,
);
log.error(`Failed to install ${vvppPath},`, e);
return false;
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/domain/defaultEngine/envEngineInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import { z } from "zod";

import { engineIdSchema } from "@/type/preload";
import { isElectron } from "@/helpers/platform";

/** .envに書くデフォルトエンジン情報のスキーマ */
const envEngineInfoSchema = z
Expand Down Expand Up @@ -34,8 +35,12 @@ type EnvEngineInfoType = z.infer<typeof envEngineInfoSchema>;

/** .envからデフォルトエンジン情報を読み込む */
export function loadEnvEngineInfos(): EnvEngineInfoType[] {
// electronのときはプロセスの環境変数を参照する。
// NOTE: electronテスト環境を切り替えるため。テスト環境が1本化されればimport.meta.envを使う。
const defaultEngineInfosEnv =
import.meta.env.VITE_DEFAULT_ENGINE_INFOS ?? "[]";
(isElectron
? process.env.VITE_DEFAULT_ENGINE_INFOS
: import.meta.env.VITE_DEFAULT_ENGINE_INFOS) ?? "[]";

// FIXME: 「.envを書き換えてください」というログを出したい
// NOTE: domainディレクトリなのでログを出す方法がなく、Errorオプションのcauseを用いてもelectron-logがcauseのログを出してくれない
Expand Down
93 changes: 66 additions & 27 deletions tests/e2e/electron/example.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import os from "os";
import path from "path";
import { _electron as electron, test } from "@playwright/test";
import dotenv from "dotenv";
import { BrowserWindow, MessageBoxSyncOptions } from "electron";

test.beforeAll(async () => {
dotenv.config(); // FIXME: エンジンの設定直読み

console.log("Waiting for main.js to be built...");
while (true) {
try {
Expand All @@ -19,40 +18,80 @@ test.beforeAll(async () => {
console.log("main.js is built.");
});

// キャッシュなどでテスト結果が変化しないように、appDataをテスト起動時に毎回消去する。
// cf: https://www.electronjs.org/ja/docs/latest/api/app#appgetpathname
const appDataMap: Partial<Record<NodeJS.Platform, string>> = {
win32: process.env.APPDATA,
darwin: os.homedir() + "/Library/Application Support",
linux: process.env.XDG_CONFIG_HOME || os.homedir() + "/.config",
} as const;
test.beforeEach(async () => {
// キャッシュなどでテスト結果が変化しないように、appDataをテスト起動時に毎回消去する。
// cf: https://www.electronjs.org/ja/docs/latest/api/app#appgetpathname
const appDataMap: Partial<Record<NodeJS.Platform, string>> = {
win32: process.env.APPDATA,
darwin: os.homedir() + "/Library/Application Support",
linux: process.env.XDG_CONFIG_HOME || os.homedir() + "/.config",
} as const;

const appData = appDataMap[process.platform];
if (!appData) {
throw new Error("Unsupported platform");
}
const userDir = path.resolve(appData, `${process.env.VITE_APP_NAME}-test`);
const appData = appDataMap[process.platform];
if (!appData) {
throw new Error("Unsupported platform");
}
const userDir = path.resolve(appData, `${process.env.VITE_APP_NAME}-test`);

test.beforeEach(async () => {
await fs.rm(userDir, {
recursive: true,
force: true,
});
});

test("起動したら「利用規約に関するお知らせ」が表示される", async () => {
const app = await electron.launch({
args: ["--no-sandbox", "."], // NOTE: --no-sandbox はUbuntu 24.04で動かすのに必要
timeout: process.env.CI ? 0 : 60000,
});
[
{
envName: ".env環境",
envPath: ".env",
},
{
envName: "VVPPデフォルトエンジン",
envPath: ".env.test-electron-default-vvpp",
},
].forEach(({ envName, envPath }) => {
test.describe(`${envName}`, () => {
test.beforeEach(() => {
dotenv.config({ path: envPath, override: true });
});

const sut = await app.firstWindow({
timeout: process.env.CI ? 60000 : 30000,
});
test("起動したら「利用規約に関するお知らせ」が表示される", async () => {
const app = await electron.launch({
args: ["--no-sandbox", "."], // NOTE: --no-sandbox はUbuntu 24.04で動かすのに必要
timeout: process.env.CI ? 0 : 60000,
});

// ダイアログのモック
await app.evaluate((electron) => {
// @ts-expect-error 2種のオーバーロードを無視する
electron.dialog.showMessageBoxSync = (
win: BrowserWindow,
options: MessageBoxSyncOptions,
) => {
// デフォルトエンジンのインストールの確認ダイアログ
if (
options.title == "デフォルトエンジンのインストール" &&
options.buttons?.[0] == "インストール"
) {
return 0;
}

throw new Error(`Unexpected dialog: ${JSON.stringify(options)}`);
};
});

// ログを表示
app.on("console", (msg) => {
console.log(msg.text());
});

// エンジンが起動し「利用規約に関するお知らせ」が表示されるのを待つ
await sut.waitForSelector("text=利用規約に関するお知らせ", {
timeout: 60000,
const sut = await app.firstWindow({
timeout: process.env.CI ? 60000 : 30000,
});
// エンジンが起動し「利用規約に関するお知らせ」が表示されるのを待つ
await sut.waitForSelector("text=利用規約に関するお知らせ", {
timeout: 60000,
});
await app.close();
});
});
await app.close();
});
15 changes: 10 additions & 5 deletions vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ import vue from "@vitejs/plugin-vue";
import checker from "vite-plugin-checker";
import { BuildOptions, defineConfig, loadEnv, Plugin } from "vite";
import { quasar } from "@quasar/vite-plugin";
import { z } from "zod";

const isElectron = process.env.VITE_TARGET === "electron";
const isBrowser = process.env.VITE_TARGET === "browser";

export default defineConfig((options) => {
const mode = z
.enum(["development", "test", "production"])
.parse(options.mode);

const packageName = process.env.npm_package_name;
const env = loadEnv(options.mode, import.meta.dirname);
const env = loadEnv(mode, import.meta.dirname);
if (!packageName?.startsWith(env.VITE_APP_NAME)) {
throw new Error(
`"package.json"の"name":"${packageName}"は"VITE_APP_NAME":"${env.VITE_APP_NAME}"から始まっている必要があります`,
Expand All @@ -32,19 +37,19 @@ export default defineConfig((options) => {
throw new Error(`Unsupported platform: ${process.platform}`);
}
process.env.VITE_7Z_BIN_NAME =
(options.mode === "development"
(mode !== "production"
? path.join(import.meta.dirname, "vendored", "7z") + path.sep
: "") + sevenZipBinName;
process.env.VITE_APP_VERSION = process.env.npm_package_version;

const shouldEmitSourcemap = ["development", "test"].includes(options.mode);
const shouldEmitSourcemap = ["development", "test"].includes(mode);
const sourcemap: BuildOptions["sourcemap"] = shouldEmitSourcemap
? "inline"
: false;

// ref: electronの起動をスキップしてデバッグ起動を軽くする
const skipLahnchElectron =
options.mode === "test" || process.env.SKIP_LAUNCH_ELECTRON === "1";
mode === "test" || process.env.SKIP_LAUNCH_ELECTRON === "1";

return {
root: path.resolve(import.meta.dirname, "src"),
Expand All @@ -71,7 +76,7 @@ export default defineConfig((options) => {
plugins: [
vue(),
quasar({ autoImportComponentCase: "pascal" }),
options.mode !== "test" &&
mode !== "test" &&
checker({
overlay: false,
eslint: {
Expand Down

0 comments on commit 7cc32cc

Please sign in to comment.