Skip to content

Commit

Permalink
useFetchNewUpdateInfosのテストを追加 (#1678)
Browse files Browse the repository at this point in the history
* Refactor imports and add error handling for missing environment variables

* window.electron.getAppInfosのモックは良くない

* Fix issue with undefined latestVersion in HelpDialog.vue

* Update useFetchNewUpdateInfos function description

* Fix

* タイポミス
  • Loading branch information
Hiroshiba authored Jan 12, 2024
1 parent 577cd93 commit 80a3eb0
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 61 deletions.
28 changes: 20 additions & 8 deletions src/components/help/HelpDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@
</template>

<script setup lang="ts">
import { computed, ref, type Component } from "vue";
import { computed, ref } from "vue";
import type { Component } from "vue";
import HelpPolicy from "./HelpPolicy.vue";
import LibraryPolicy from "./LibraryPolicy.vue";
import HowToUse from "./HowToUse.vue";
Expand Down Expand Up @@ -131,11 +132,15 @@ const store = useStore();
const updateInfos = ref<UpdateInfoObject[]>();
store.dispatch("GET_UPDATE_INFOS").then((obj) => (updateInfos.value = obj));
const { isCheckingFinished, latestVersion } = useFetchNewUpdateInfos();
const isUpdateAvailable = computed(() => {
return isCheckingFinished.value && latestVersion.value !== "";
});
if (!import.meta.env.VITE_LATEST_UPDATE_INFOS_URL) {
throw new Error(
"環境変数VITE_LATEST_UPDATE_INFOS_URLが設定されていません。.envに記載してください。"
);
}
const newUpdateResult = useFetchNewUpdateInfos(
() => window.electron.getAppInfos().then((obj) => obj.version), // アプリのバージョン
import.meta.env.VITE_LATEST_UPDATE_INFOS_URL
);
// エディタのOSSライセンス取得
const licenses = ref<Record<string, string>[]>();
Expand Down Expand Up @@ -184,8 +189,15 @@ const pagedata = computed(() => {
props: {
downloadLink: import.meta.env.VITE_OFFICIAL_WEBSITE_URL,
updateInfos: updateInfos.value,
isUpdateAvailable: isUpdateAvailable.value,
latestVersion: latestVersion.value,
...(newUpdateResult.value.status == "updateAvailable"
? {
isUpdateAvailable: true,
latestVersion: newUpdateResult.value.latestVersion,
}
: {
isUpdateAvailable: false,
latestVersion: undefined,
}),
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion src/components/help/UpdateInfo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import { UpdateInfo } from "@/type/preload";
const props =
defineProps<{
latestVersion: string;
latestVersion: string | undefined;
downloadLink: string;
updateInfos: UpdateInfo[];
isUpdateAvailable: boolean;
Expand Down
88 changes: 49 additions & 39 deletions src/composables/useFetchNewUpdateInfos.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,57 @@
import { ref } from "vue";
import semver from "semver";
import { UpdateInfo } from "@/type/preload";
import { z } from "zod";
import { UpdateInfo, updateInfoSchema } from "@/type/preload";

// 最新版があるか調べる
// 現バージョンより新しい最新版があれば`latestVersion`に代入される
export const useFetchNewUpdateInfos = () => {
const isCheckingFinished = ref<boolean>(false);
const currentVersion = ref("");
const latestVersion = ref("");
const newUpdateInfos = ref<UpdateInfo[]>([]);
/**
* 現在のバージョンより新しいバージョンがリリースされているか調べる。
* あれば最新バージョンと、現在より新しいバージョンの情報を返す。
*/
export const useFetchNewUpdateInfos = (
currentVersionGetter: () => Promise<string>,
newUpdateInfosUrl: string
) => {
const result = ref<
| {
status: "updateChecking";
}
| {
status: "updateAvailable";
latestVersion: string;
newUpdateInfos: UpdateInfo[];
}
| {
status: "updateNotAvailable";
}
>({
status: "updateChecking",
});

window.electron
.getAppInfos()
.then((obj) => {
currentVersion.value = obj.version;
})
.then(() => {
const url: string | undefined = import.meta.env
.VITE_LATEST_UPDATE_INFOS_URL;
if (!url) {
throw new Error(
"VITE_LATEST_UPDATE_INFOS_URLが未設定です。.env内に記載してください。"
);
(async () => {
const currentVersion = await currentVersionGetter();

const updateInfos = await fetch(newUpdateInfosUrl).then(
async (response) => {
if (!response.ok) throw new Error("Network response was not ok.");
return z.array(updateInfoSchema).parse(await response.json());
}
fetch(url)
.then((response) => {
if (!response.ok) throw new Error("Network response was not ok.");
return response.json();
})
.then((json) => {
newUpdateInfos.value = json.filter((item: UpdateInfo) => {
return semver.lt(currentVersion.value, item.version);
});
if (newUpdateInfos.value?.length) {
latestVersion.value = newUpdateInfos.value[0].version;
}
isCheckingFinished.value = true;
});
);
const newUpdateInfos = updateInfos.filter((item: UpdateInfo) => {
return semver.lt(currentVersion, item.version);
});

return {
isCheckingFinished,
latestVersion,
newUpdateInfos,
};
if (newUpdateInfos.length > 0) {
result.value = {
status: "updateAvailable",
latestVersion: newUpdateInfos[0].version,
newUpdateInfos,
};
} else {
result.value = {
status: "updateNotAvailable",
};
}
})();

return result;
};
11 changes: 6 additions & 5 deletions src/type/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,11 +270,12 @@ export type CharacterInfo = {
};
};

export type UpdateInfo = {
version: string;
descriptions: string[];
contributors: string[];
};
export const updateInfoSchema = z.object({
version: z.string(),
descriptions: z.array(z.string()),
contributors: z.array(z.string()),
});
export type UpdateInfo = z.infer<typeof updateInfoSchema>;

export type Voice = {
engineId: EngineId;
Expand Down
22 changes: 14 additions & 8 deletions src/views/EditorHome.vue
Original file line number Diff line number Diff line change
Expand Up @@ -178,9 +178,10 @@
/>
<accept-terms-dialog v-model="isAcceptTermsDialogOpenComputed" />
<update-notification-dialog
v-if="newUpdateResult.status == 'updateAvailable'"
v-model="isUpdateNotificationDialogOpenComputed"
:latest-version="latestVersion"
:new-update-infos="newUpdateInfos"
:latest-version="newUpdateResult.latestVersion"
:new-update-infos="newUpdateResult.newUpdateInfos"
/>
</template>

Expand Down Expand Up @@ -551,11 +552,15 @@ watch(userOrderedCharacterInfos, (userOrderedCharacterInfos) => {
});
// エディタのアップデート確認
const { isCheckingFinished, latestVersion, newUpdateInfos } =
useFetchNewUpdateInfos();
const isUpdateAvailable = computed(() => {
return isCheckingFinished.value && latestVersion.value !== "";
});
if (!import.meta.env.VITE_LATEST_UPDATE_INFOS_URL) {
throw new Error(
"環境変数VITE_LATEST_UPDATE_INFOS_URLが設定されていません。.envに記載してください。"
);
}
const newUpdateResult = useFetchNewUpdateInfos(
() => window.electron.getAppInfos().then((obj) => obj.version), // アプリのバージョン
import.meta.env.VITE_LATEST_UPDATE_INFOS_URL
);
// ソフトウェアを初期化
const isCompletedInitialStartup = ref(false);
Expand Down Expand Up @@ -639,7 +644,8 @@ onMounted(async () => {
import.meta.env.MODE !== "development" &&
store.state.acceptTerms !== "Accepted";
isUpdateNotificationDialogOpenComputed.value = isUpdateAvailable.value;
isUpdateNotificationDialogOpenComputed.value =
newUpdateResult.value.status == "updateAvailable";
isCompletedInitialStartup.value = true;
});
Expand Down
56 changes: 56 additions & 0 deletions tests/unit/composable/useFetchNewUpdateInfos.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Ref } from "vue";
import { UpdateInfo } from "@/type/preload";
import { useFetchNewUpdateInfos } from "@/composables/useFetchNewUpdateInfos";

// 最新バージョンの情報をfetchするモックを作成する
const setupFetchMock = (latestVersion: string) => {
// fetchのモックを作成
const updateInfos: UpdateInfo[] = [
{
version: latestVersion,
descriptions: [],
contributors: [],
},
];
vi.stubGlobal("fetch", async () => {
return new Response(JSON.stringify(updateInfos), { status: 200 });
});
};

// 準備完了まで待機
const waitFinished = async (result: Ref<{ status: string }>) => {
await vi.waitFor(() => {
if (result.value.status === "updateChecking") throw new Error();
});
};

it("新バージョンがある場合、latestVersionに最新バージョンが代入される", async () => {
const currentVersion = "1.0.0";
const latestVersion = "2.0.0";
setupFetchMock(latestVersion);

const result = useFetchNewUpdateInfos(
async () => currentVersion,
"Dummy Url"
);

await waitFinished(result);
expect(result.value).toMatchObject({
status: "updateAvailable",
latestVersion,
});
});

it("新バージョンがない場合は状態が変わるだけ", async () => {
const currentVersion = "1.0.0";
const latestVersion = "1.0.0";
setupFetchMock(latestVersion);

const result = useFetchNewUpdateInfos(
async () => currentVersion,
"Dummy Url"
);

await waitFinished(result);
expect(result.value).toMatchObject({ status: "updateNotAvailable" });
});

0 comments on commit 80a3eb0

Please sign in to comment.