mirror of
https://github.com/open-goal/launcher.git
synced 2024-10-19 14:47:36 -04:00
tests: Start writing tests, Splash and some of the lib/
functions (#280)
This commit is contained in:
parent
ab4b38c792
commit
620c41ceb4
33
.github/workflows/test.yaml
vendored
Normal file
33
.github/workflows/test.yaml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
name: 🧪 Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- v*
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
frontend:
|
||||
name: Frontend
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
cache: yarn
|
||||
|
||||
- name: Install NPM Dependencies
|
||||
run: yarn install --frozen-lockfile
|
||||
|
||||
- name: Run Tests
|
||||
run: yarn test
|
||||
|
||||
# TODO - capture and report on coverage
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -41,3 +41,4 @@ TODO.md
|
|||
vite.config.ts.timestamp*
|
||||
.yarn/
|
||||
.yarnrc.yml
|
||||
coverage/
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"test": "vitest",
|
||||
"coverage": "vitest run --coverage",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"tauri": "tauri",
|
||||
|
@ -25,6 +27,8 @@
|
|||
"@sveltejs/vite-plugin-svelte": "^2.4.2",
|
||||
"@tauri-apps/cli": "^1.4.0",
|
||||
"@tauri-apps/tauricon": "github:tauri-apps/tauricon",
|
||||
"@testing-library/svelte": "^4.0.3",
|
||||
"@vitest/coverage-v8": "^0.33.0",
|
||||
"@tsconfig/svelte": "^5.0.0",
|
||||
"ansi-to-span": "^0.0.1",
|
||||
"autoprefixer": "^10.4.14",
|
||||
|
@ -33,6 +37,7 @@
|
|||
"execa": "^7.1.1",
|
||||
"flowbite": "^1.6.5",
|
||||
"flowbite-svelte": "^0.39.2",
|
||||
"jsdom": "^22.1.0",
|
||||
"postcss": "^8.4.26",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"prettier": "^2.8.8",
|
||||
|
@ -42,6 +47,7 @@
|
|||
"svelte-preprocess": "^5.0.3",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^5.1.3",
|
||||
"vitest": "^0.33.0",
|
||||
"vite": "^4.4.4"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
extractNewTexturePack,
|
||||
listExtractedTexturePackInfo,
|
||||
} from "$lib/rpc/features";
|
||||
import { filePrompt } from "$lib/utils/file";
|
||||
import { filePrompt } from "$lib/utils/file-dialogs";
|
||||
import Icon from "@iconify/svelte";
|
||||
import { convertFileSrc } from "@tauri-apps/api/tauri";
|
||||
import {
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
runCompiler,
|
||||
runDecompiler,
|
||||
} from "$lib/rpc/binaries";
|
||||
import { folderPrompt, isoPrompt } from "$lib/utils/file";
|
||||
import { folderPrompt, isoPrompt } from "$lib/utils/file-dialogs";
|
||||
import {
|
||||
finalizeInstallation,
|
||||
isAVXRequirementMet,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { saveFilePrompt } from "$lib/utils/file";
|
||||
import { saveFilePrompt } from "$lib/utils/file-dialogs";
|
||||
import { invoke_rpc } from "./rpc";
|
||||
|
||||
export async function generateSupportPackage(): Promise<void> {
|
||||
|
|
14
src/lib/utils/common.test.ts
Normal file
14
src/lib/utils/common.test.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { isInDebugMode } from "./common";
|
||||
|
||||
describe("isInDebugMode", () => {
|
||||
it("should return true when in debug mode", async () => {
|
||||
process.env["NODE_ENV"] = "development";
|
||||
expect(isInDebugMode()).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should return true when in debug mode", async () => {
|
||||
process.env["NODE_ENV"] = "not-development";
|
||||
expect(isInDebugMode()).toBeFalsy();
|
||||
});
|
||||
});
|
284
src/lib/utils/github.test.ts
Normal file
284
src/lib/utils/github.test.ts
Normal file
|
@ -0,0 +1,284 @@
|
|||
import { afterEach, describe, expect, it, vi, type Mock } from "vitest";
|
||||
import { arch, platform } from "@tauri-apps/api/os";
|
||||
import { listOfficialReleases } from "./github";
|
||||
|
||||
vi.mock("@tauri-apps/api/os");
|
||||
global.fetch = vi.fn();
|
||||
|
||||
function createFetchResponse(data: any) {
|
||||
return { json: () => new Promise((resolve) => resolve(data)) };
|
||||
}
|
||||
|
||||
function createFakeGithubReleaseAsset(assetName) {
|
||||
return {
|
||||
url: "https://api.github.com/repos/open-goal/jak-project/releases/assets/115111791",
|
||||
id: 115111791,
|
||||
node_id: "RA_kwDOEUK6OM4G3Hdv",
|
||||
name: assetName,
|
||||
label: "",
|
||||
uploader: {
|
||||
login: "github-actions[bot]",
|
||||
id: 41898282,
|
||||
node_id: "MDM6Qm90NDE4OTgyODI=",
|
||||
avatar_url: "https://avatars.githubusercontent.com/in/15368?v=4",
|
||||
gravatar_id: "",
|
||||
url: "https://api.github.com/users/github-actions%5Bbot%5D",
|
||||
html_url: "https://github.com/apps/github-actions",
|
||||
followers_url:
|
||||
"https://api.github.com/users/github-actions%5Bbot%5D/followers",
|
||||
following_url:
|
||||
"https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",
|
||||
gists_url:
|
||||
"https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",
|
||||
starred_url:
|
||||
"https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",
|
||||
subscriptions_url:
|
||||
"https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",
|
||||
organizations_url:
|
||||
"https://api.github.com/users/github-actions%5Bbot%5D/orgs",
|
||||
repos_url: "https://api.github.com/users/github-actions%5Bbot%5D/repos",
|
||||
events_url:
|
||||
"https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",
|
||||
received_events_url:
|
||||
"https://api.github.com/users/github-actions%5Bbot%5D/received_events",
|
||||
type: "Bot",
|
||||
site_admin: false,
|
||||
},
|
||||
content_type: "application/x-gtar",
|
||||
state: "uploaded",
|
||||
size: 21698082,
|
||||
download_count: 399,
|
||||
created_at: "2023-07-01T06:38:26Z",
|
||||
updated_at: "2023-07-01T06:38:28Z",
|
||||
browser_download_url: `https://github.com/open-goal/jak-project/releases/download/v0.1.38/${assetName}`,
|
||||
};
|
||||
}
|
||||
|
||||
function createFakeGithubRelease(assetNames: string[]) {
|
||||
const assets = [];
|
||||
for (const assetName of assetNames) {
|
||||
assets.push(createFakeGithubReleaseAsset(assetName));
|
||||
}
|
||||
return {
|
||||
url: "https://api.github.com/repos/open-goal/jak-project/releases/110648537",
|
||||
assets_url:
|
||||
"https://api.github.com/repos/open-goal/jak-project/releases/110648537/assets",
|
||||
upload_url:
|
||||
"https://uploads.github.com/repos/open-goal/jak-project/releases/110648537/assets{?name,label}",
|
||||
html_url: "https://github.com/open-goal/jak-project/releases/tag/v0.1.38",
|
||||
id: 110648537,
|
||||
author: {
|
||||
login: "OpenGOALBot",
|
||||
id: 99294829,
|
||||
node_id: "U_kgDOBesebQ",
|
||||
avatar_url: "https://avatars.githubusercontent.com/u/99294829?v=4",
|
||||
gravatar_id: "",
|
||||
url: "https://api.github.com/users/OpenGOALBot",
|
||||
html_url: "https://github.com/OpenGOALBot",
|
||||
followers_url: "https://api.github.com/users/OpenGOALBot/followers",
|
||||
following_url:
|
||||
"https://api.github.com/users/OpenGOALBot/following{/other_user}",
|
||||
gists_url: "https://api.github.com/users/OpenGOALBot/gists{/gist_id}",
|
||||
starred_url:
|
||||
"https://api.github.com/users/OpenGOALBot/starred{/owner}{/repo}",
|
||||
subscriptions_url:
|
||||
"https://api.github.com/users/OpenGOALBot/subscriptions",
|
||||
organizations_url: "https://api.github.com/users/OpenGOALBot/orgs",
|
||||
repos_url: "https://api.github.com/users/OpenGOALBot/repos",
|
||||
events_url: "https://api.github.com/users/OpenGOALBot/events{/privacy}",
|
||||
received_events_url:
|
||||
"https://api.github.com/users/OpenGOALBot/received_events",
|
||||
type: "User",
|
||||
site_admin: false,
|
||||
},
|
||||
node_id: "RE_kwDOEUK6OM4GmFzZ",
|
||||
tag_name: "v0.1.38",
|
||||
target_commitish: "master",
|
||||
name: "v0.1.38",
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
created_at: "2023-07-01T06:09:09Z",
|
||||
published_at: "2023-07-01T06:38:29Z",
|
||||
assets: assets,
|
||||
tarball_url:
|
||||
"https://api.github.com/repos/open-goal/jak-project/tarball/v0.1.38",
|
||||
zipball_url:
|
||||
"https://api.github.com/repos/open-goal/jak-project/zipball/v0.1.38",
|
||||
body: "## What's Changed\n* ci: ensure linux runners have the proper OpenGL headers by @xTVaser in https://github.com/open-goal/jak-project/pull/2790\n\n\n**Full Changelog**: https://github.com/open-goal/jak-project/compare/v0.1.37...v0.1.38",
|
||||
reactions: {
|
||||
url: "https://api.github.com/repos/open-goal/jak-project/releases/110648537/reactions",
|
||||
total_count: 4,
|
||||
"+1": 0,
|
||||
"-1": 0,
|
||||
laugh: 0,
|
||||
hooray: 3,
|
||||
confused: 0,
|
||||
heart: 0,
|
||||
rocket: 0,
|
||||
eyes: 1,
|
||||
},
|
||||
mentions_count: 1,
|
||||
};
|
||||
}
|
||||
|
||||
describe("listOfficialReleases", () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it("should retrieve intel macOS releases properly", async () => {
|
||||
vi.mocked(platform).mockResolvedValue("darwin");
|
||||
vi.mocked(arch).mockResolvedValue("x86_64");
|
||||
(fetch as Mock).mockResolvedValue(
|
||||
createFetchResponse([
|
||||
createFakeGithubRelease([
|
||||
"opengoal-macos-intel-v0.0.1.tar.gz",
|
||||
"opengoal-windows-v0.0.1.zip",
|
||||
"opengoal-linux-v0.0.1.tar.gz",
|
||||
]),
|
||||
])
|
||||
);
|
||||
const releases = await listOfficialReleases();
|
||||
expect(releases.length).toBe(1);
|
||||
expect(
|
||||
releases[0].downloadUrl.endsWith("opengoal-macos-intel-v0.0.1.tar.gz")
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should not retrieve macOS ARM releases", async () => {
|
||||
vi.mocked(platform).mockResolvedValue("darwin");
|
||||
vi.mocked(arch).mockResolvedValue("arm");
|
||||
(fetch as Mock).mockResolvedValue(
|
||||
createFetchResponse([
|
||||
createFakeGithubRelease([
|
||||
"opengoal-macos-intel-v0.0.1.tar.gz",
|
||||
"opengoal-windows-v0.0.1.zip",
|
||||
"opengoal-linux-v0.0.1.tar.gz",
|
||||
]),
|
||||
])
|
||||
);
|
||||
const releases = await listOfficialReleases();
|
||||
expect(releases.length).toBe(1);
|
||||
expect(releases[0].downloadUrl).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should retrieve windows releases properly", async () => {
|
||||
vi.mocked(platform).mockResolvedValue("win32");
|
||||
vi.mocked(arch).mockResolvedValue("x86_64");
|
||||
(fetch as Mock).mockResolvedValue(
|
||||
createFetchResponse([
|
||||
createFakeGithubRelease([
|
||||
"opengoal-macos-intel-v0.0.1.tar.gz",
|
||||
"opengoal-windows-v0.0.1.zip",
|
||||
"opengoal-linux-v0.0.1.tar.gz",
|
||||
]),
|
||||
])
|
||||
);
|
||||
const releases = await listOfficialReleases();
|
||||
expect(releases.length).toBe(1);
|
||||
expect(
|
||||
releases[0].downloadUrl.endsWith("opengoal-windows-v0.0.1.zip")
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should retrieve linux releases properly", async () => {
|
||||
vi.mocked(platform).mockResolvedValue("linux");
|
||||
vi.mocked(arch).mockResolvedValue("x86_64");
|
||||
(fetch as Mock).mockResolvedValue(
|
||||
createFetchResponse([
|
||||
createFakeGithubRelease([
|
||||
"opengoal-macos-intel-v0.0.1.tar.gz",
|
||||
"opengoal-windows-v0.0.1.zip",
|
||||
"opengoal-linux-v0.0.1.tar.gz",
|
||||
]),
|
||||
])
|
||||
);
|
||||
const releases = await listOfficialReleases();
|
||||
expect(releases.length).toBe(1);
|
||||
expect(
|
||||
releases[0].downloadUrl.endsWith("opengoal-linux-v0.0.1.tar.gz")
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("getLatestOfficialRelease", () => {
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it("should retrieve intel macOS releases properly", async () => {
|
||||
vi.mocked(platform).mockResolvedValue("darwin");
|
||||
vi.mocked(arch).mockResolvedValue("x86_64");
|
||||
(fetch as Mock).mockResolvedValue(
|
||||
createFetchResponse([
|
||||
createFakeGithubRelease([
|
||||
"opengoal-macos-intel-v0.0.1.tar.gz",
|
||||
"opengoal-windows-v0.0.1.zip",
|
||||
"opengoal-linux-v0.0.1.tar.gz",
|
||||
]),
|
||||
])
|
||||
);
|
||||
const releases = await listOfficialReleases();
|
||||
expect(releases.length).toBe(1);
|
||||
expect(
|
||||
releases[0].downloadUrl.endsWith("opengoal-macos-intel-v0.0.1.tar.gz")
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should not retrieve macOS ARM releases", async () => {
|
||||
vi.mocked(platform).mockResolvedValue("darwin");
|
||||
vi.mocked(arch).mockResolvedValue("arm");
|
||||
(fetch as Mock).mockResolvedValue(
|
||||
createFetchResponse([
|
||||
createFakeGithubRelease([
|
||||
"opengoal-macos-intel-v0.0.1.tar.gz",
|
||||
"opengoal-windows-v0.0.1.zip",
|
||||
"opengoal-linux-v0.0.1.tar.gz",
|
||||
]),
|
||||
])
|
||||
);
|
||||
const releases = await listOfficialReleases();
|
||||
expect(releases.length).toBe(1);
|
||||
expect(releases[0].downloadUrl).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should retrieve windows releases properly", async () => {
|
||||
vi.mocked(platform).mockResolvedValue("win32");
|
||||
vi.mocked(arch).mockResolvedValue("x86_64");
|
||||
(fetch as Mock).mockResolvedValue(
|
||||
createFetchResponse([
|
||||
createFakeGithubRelease([
|
||||
"opengoal-macos-intel-v0.0.1.tar.gz",
|
||||
"opengoal-windows-v0.0.1.zip",
|
||||
"opengoal-linux-v0.0.1.tar.gz",
|
||||
]),
|
||||
])
|
||||
);
|
||||
const releases = await listOfficialReleases();
|
||||
expect(releases.length).toBe(1);
|
||||
expect(
|
||||
releases[0].downloadUrl.endsWith("opengoal-windows-v0.0.1.zip")
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should retrieve linux releases properly", async () => {
|
||||
vi.mocked(platform).mockResolvedValue("linux");
|
||||
vi.mocked(arch).mockResolvedValue("x86_64");
|
||||
(fetch as Mock).mockResolvedValue(
|
||||
createFetchResponse([
|
||||
createFakeGithubRelease([
|
||||
"opengoal-macos-intel-v0.0.1.tar.gz",
|
||||
"opengoal-windows-v0.0.1.zip",
|
||||
"opengoal-linux-v0.0.1.tar.gz",
|
||||
]),
|
||||
])
|
||||
);
|
||||
const releases = await listOfficialReleases();
|
||||
expect(releases.length).toBe(1);
|
||||
expect(
|
||||
releases[0].downloadUrl.endsWith("opengoal-linux-v0.0.1.tar.gz")
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
|
@ -10,30 +10,54 @@ export interface ReleaseInfo {
|
|||
pendingAction: boolean;
|
||||
}
|
||||
|
||||
function isIntelMacOsRelease(
|
||||
platform: string,
|
||||
architecture: string,
|
||||
assetName: string
|
||||
): boolean {
|
||||
return (
|
||||
platform === "darwin" &&
|
||||
architecture === "x86_64" &&
|
||||
assetName.startsWith("opengoal-macos-intel-v")
|
||||
);
|
||||
}
|
||||
|
||||
// TODO - go back and fix old asset names so windows/linux can be simplified
|
||||
function isWindowsRelease(
|
||||
platform: string,
|
||||
architecture: string,
|
||||
assetName: string
|
||||
): boolean {
|
||||
return (
|
||||
platform === "win32" &&
|
||||
(assetName.startsWith("opengoal-windows-v") ||
|
||||
(assetName.startsWith("opengoal-v") && assetName.includes("windows")))
|
||||
);
|
||||
}
|
||||
|
||||
function isLinuxRelease(
|
||||
platform: string,
|
||||
architecture: string,
|
||||
assetName: string
|
||||
): boolean {
|
||||
return (
|
||||
platform === "linux" &&
|
||||
(assetName.startsWith("opengoal-linux-v") ||
|
||||
(assetName.startsWith("opengoal-v") && assetName.includes("linux")))
|
||||
);
|
||||
}
|
||||
|
||||
async function getDownloadLinkForCurrentPlatform(
|
||||
release
|
||||
release: any
|
||||
): Promise<string | undefined> {
|
||||
const platformName = await platform();
|
||||
const archName = await arch();
|
||||
for (const asset of release.assets) {
|
||||
if (
|
||||
platformName === "darwin" &&
|
||||
archName === "x86_64" &&
|
||||
asset.name.startsWith("opengoal-macos-intel-v")
|
||||
// macOS doesn't have the old naming scheme
|
||||
) {
|
||||
if (isIntelMacOsRelease(platformName, archName, asset.name)) {
|
||||
return asset.browser_download_url;
|
||||
} else if (
|
||||
platformName === "win32" &&
|
||||
(asset.name.startsWith("opengoal-windows-v") ||
|
||||
(asset.name.startsWith("opengoal-v") && asset.name.includes("windows")))
|
||||
) {
|
||||
} else if (isWindowsRelease(platformName, archName, asset.name)) {
|
||||
return asset.browser_download_url;
|
||||
} else if (
|
||||
platformName === "linux" &&
|
||||
(asset.name.startsWith("opengoal-linux-v") ||
|
||||
(asset.name.startsWith("opengoal-v") && asset.name.includes("linux")))
|
||||
) {
|
||||
} else if (isLinuxRelease(platformName, archName, asset.name)) {
|
||||
return asset.browser_download_url;
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +68,6 @@ export async function listOfficialReleases(): Promise<ReleaseInfo[]> {
|
|||
let releases = [];
|
||||
// TODO - handle rate limiting
|
||||
// TODO - long term - handle pagination (more than 100 releases)
|
||||
// TODO - even longer term - extract this out into an API we control (avoid github rate limiting) -- will be needed for unofficial releases as well anyway
|
||||
const resp = await fetch(
|
||||
"https://api.github.com/repos/open-goal/jak-project/releases?per_page=100"
|
||||
);
|
||||
|
@ -68,7 +91,6 @@ export async function listOfficialReleases(): Promise<ReleaseInfo[]> {
|
|||
|
||||
export async function getLatestOfficialRelease(): Promise<ReleaseInfo> {
|
||||
// TODO - handle rate limiting
|
||||
// TODO - even longer term - extract this out into an API we control (avoid github rate limiting) -- will be needed for unofficial releases as well anyway
|
||||
const resp = await fetch(
|
||||
"https://api.github.com/repos/open-goal/jak-project/releases/latest"
|
||||
);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
setInstallationDirectory,
|
||||
} from "$lib/rpc/config";
|
||||
import { VersionStore } from "$lib/stores/VersionStore";
|
||||
import { folderPrompt } from "$lib/utils/file";
|
||||
import { folderPrompt } from "$lib/utils/file-dialogs";
|
||||
import { Label, Input } from "flowbite-svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import { openMainWindow } from "$lib/rpc/window";
|
||||
import { onMount } from "svelte";
|
||||
import logo from "$assets/images/icon.webp";
|
||||
import { folderPrompt } from "$lib/utils/file";
|
||||
import { folderPrompt } from "$lib/utils/file-dialogs";
|
||||
import {
|
||||
deleteOldDataDirectory,
|
||||
getInstallationDirectory,
|
||||
|
@ -12,10 +12,10 @@
|
|||
setLocale,
|
||||
} from "$lib/rpc/config";
|
||||
import { AVAILABLE_LOCALES } from "$lib/i18n/i18n";
|
||||
import { _ } from "svelte-i18n";
|
||||
import { locale as svelteLocale, _ } from "svelte-i18n";
|
||||
|
||||
let currentProgress = 10;
|
||||
let currentStatusText = $_("splash_step_readingSettings");
|
||||
let currentStatusText = "Loading Locales...";
|
||||
|
||||
let selectLocale = false;
|
||||
let installationDirSet = true;
|
||||
|
@ -26,6 +26,7 @@
|
|||
onMount(async () => {
|
||||
// First, see if the user has selected a locale
|
||||
await checkLocale();
|
||||
currentStatusText = $_("splash_step_readingSettings");
|
||||
});
|
||||
|
||||
// TODO - cleanup this code and make it easier to add steps like with
|
||||
|
@ -36,6 +37,7 @@
|
|||
if (locale === null) {
|
||||
// Prompt the user to select a locale
|
||||
selectLocale = true;
|
||||
svelteLocale.set("en-US");
|
||||
} else {
|
||||
// Set locale and continue
|
||||
setLocale(locale);
|
||||
|
@ -74,25 +76,35 @@
|
|||
currentStatusText = $_("splash_step_errorOpening");
|
||||
}
|
||||
}
|
||||
|
||||
async function handleLocaleChange(evt: Event) {
|
||||
const selectElement = evt.target as HTMLSelectElement;
|
||||
setLocale(selectElement.value);
|
||||
selectLocale = false;
|
||||
await checkDirectories();
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="content" data-tauri-drag-region>
|
||||
<div class="splash-logo no-pointer-events">
|
||||
<img src={logo} aria-label="" draggable="false" />
|
||||
<img
|
||||
src={logo}
|
||||
data-testId="splash-logo"
|
||||
alt="OpenGOAL logo"
|
||||
aria-label="OpenGOAL logo"
|
||||
draggable="false"
|
||||
/>
|
||||
</div>
|
||||
<div class="splash-contents no-pointer-events">
|
||||
{#if selectLocale}
|
||||
<span class="mb-1">{$_("splash_selectLocale")}</span>
|
||||
<div class="splash-select">
|
||||
<select
|
||||
name="cars"
|
||||
id="cars"
|
||||
data-testId="locale-select"
|
||||
name="locales"
|
||||
id="locales"
|
||||
class="pointer-events emoji-font"
|
||||
on:change={async (evt) => {
|
||||
setLocale(evt.target.value);
|
||||
selectLocale = false;
|
||||
await checkDirectories();
|
||||
}}
|
||||
on:change={handleLocaleChange}
|
||||
>
|
||||
<option disabled selected value hidden />
|
||||
{#each AVAILABLE_LOCALES as locale}
|
||||
|
@ -107,6 +119,7 @@
|
|||
<br />
|
||||
<span>
|
||||
<button
|
||||
data-testId="delete-old-data-dir-button"
|
||||
class="splash-button pointer-events"
|
||||
on:click={() => {
|
||||
oldDataDirToClean = false;
|
||||
|
@ -114,6 +127,7 @@
|
|||
}}>{$_("splash_button_deleteOldInstallDir_yes")}</button
|
||||
>
|
||||
<button
|
||||
data-testId="dont-delete-old-data-dir-button"
|
||||
class="splash-button pointer-events"
|
||||
on:click={() => {
|
||||
oldDataDirToClean = false;
|
||||
|
@ -128,6 +142,7 @@
|
|||
{/if}
|
||||
<br />
|
||||
<button
|
||||
data-testId="pick-install-folder-button"
|
||||
class="splash-button pointer-events"
|
||||
on:click={async () => {
|
||||
// This is part of what allows for the user to install the games and such wherever they want
|
||||
|
|
198
src/splash/splash.test.ts
Normal file
198
src/splash/splash.test.ts
Normal file
|
@ -0,0 +1,198 @@
|
|||
import {
|
||||
render,
|
||||
waitFor,
|
||||
screen,
|
||||
cleanup,
|
||||
fireEvent,
|
||||
} from "@testing-library/svelte";
|
||||
import Splash from "./Splash.svelte";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { mockIPC } from "@tauri-apps/api/mocks";
|
||||
import { folderPrompt } from "$lib/utils/file-dialogs";
|
||||
|
||||
vi.mock("$lib/utils/file-dialogs");
|
||||
|
||||
describe("Splash.svelte", () => {
|
||||
// TODO: @testing-library/svelte claims to add this automatically but it doesn't work without explicit afterEach
|
||||
afterEach(() => {
|
||||
cleanup();
|
||||
vi.clearAllMocks();
|
||||
vi.resetAllMocks();
|
||||
});
|
||||
|
||||
it("should render the splash", async () => {
|
||||
render(Splash, {});
|
||||
const logo = screen.getByTestId("splash-logo");
|
||||
expect(logo).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should display the locale dropdown", async () => {
|
||||
// TODO - generalize into function
|
||||
mockIPC((cmd, args) => {
|
||||
if (cmd === "get_locale") {
|
||||
return null;
|
||||
} else {
|
||||
console.log(`Unhandled Tauri IPC: ${cmd}`);
|
||||
}
|
||||
});
|
||||
render(Splash, {});
|
||||
const localeSelect = await screen.findByTestId("locale-select");
|
||||
expect(localeSelect).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should set the locale when selected", async () => {
|
||||
// TODO - generalize into function
|
||||
mockIPC((cmd, args) => {
|
||||
if (cmd === "get_locale") {
|
||||
return null;
|
||||
}
|
||||
if (cmd === "set_locale") {
|
||||
return;
|
||||
} else {
|
||||
console.log(`Unhandled Tauri IPC: ${cmd}`);
|
||||
}
|
||||
});
|
||||
render(Splash, {});
|
||||
const localeSelect = (await screen.findByTestId(
|
||||
"locale-select"
|
||||
)) as HTMLSelectElement;
|
||||
expect(localeSelect).toBeTruthy();
|
||||
fireEvent.change(localeSelect, { target: { value: "en-US" } });
|
||||
expect(localeSelect.value).toBe("en-US");
|
||||
});
|
||||
|
||||
it("should prompt user to delete old data directory - delete it", async () => {
|
||||
// TODO - generalize into function
|
||||
// return an object that tracks mock calls / args
|
||||
let oldDataDirDeleted = false;
|
||||
mockIPC((cmd, args) => {
|
||||
if (cmd === "get_locale") {
|
||||
return "en-US";
|
||||
} else if (cmd === "get_install_directory") {
|
||||
return null;
|
||||
} else if (cmd === "has_old_data_directory") {
|
||||
return true;
|
||||
} else if (cmd === "delete_old_data_directory") {
|
||||
oldDataDirDeleted = true;
|
||||
} else {
|
||||
console.log(`Unhandled Tauri IPC: ${cmd}`);
|
||||
}
|
||||
});
|
||||
render(Splash, {});
|
||||
const deleteOldDataDirButton = await screen.findByTestId(
|
||||
"delete-old-data-dir-button"
|
||||
);
|
||||
expect(deleteOldDataDirButton).toBeTruthy();
|
||||
// delete the dir, it'll go away
|
||||
fireEvent.click(deleteOldDataDirButton);
|
||||
expect(oldDataDirDeleted).toBeTruthy();
|
||||
const pickInstallFolderButton = await screen.findByTestId(
|
||||
"pick-install-folder-button"
|
||||
);
|
||||
expect(pickInstallFolderButton).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should prompt user to select installation directory - cancelled dialog", async () => {
|
||||
// TODO - generalize into function
|
||||
// return an object that tracks mock calls / args
|
||||
mockIPC((cmd, args) => {
|
||||
if (cmd === "get_locale") {
|
||||
return "en-US";
|
||||
} else if (cmd === "get_install_directory") {
|
||||
return null;
|
||||
} else if (cmd === "has_old_data_directory") {
|
||||
return false;
|
||||
} else {
|
||||
console.log(`Unhandled Tauri IPC: ${cmd}`);
|
||||
}
|
||||
});
|
||||
vi.mocked(folderPrompt).mockResolvedValue(undefined);
|
||||
render(Splash, {});
|
||||
let pickInstallFolderButton = await screen.findByTestId(
|
||||
"pick-install-folder-button"
|
||||
);
|
||||
expect(pickInstallFolderButton).toBeTruthy();
|
||||
fireEvent.click(pickInstallFolderButton);
|
||||
// It's still there since the user didn't pick a folder
|
||||
pickInstallFolderButton = await screen.findByTestId(
|
||||
"pick-install-folder-button"
|
||||
);
|
||||
expect(pickInstallFolderButton).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should prompt user to select installation directory - successful dialog", async () => {
|
||||
// TODO - generalize into function
|
||||
// return an object that tracks mock calls / args
|
||||
let setInstallDirectorySet = false;
|
||||
let mainWindowOpened = false;
|
||||
mockIPC((cmd, args) => {
|
||||
if (cmd === "get_locale") {
|
||||
return "en-US";
|
||||
} else if (cmd === "get_install_directory") {
|
||||
return null;
|
||||
} else if (cmd === "has_old_data_directory") {
|
||||
return false;
|
||||
} else if (cmd === "set_install_directory") {
|
||||
setInstallDirectorySet = true;
|
||||
return null;
|
||||
} else if (cmd === "open_main_window") {
|
||||
mainWindowOpened = true;
|
||||
return;
|
||||
} else {
|
||||
console.log(`Unhandled Tauri IPC: ${cmd}`);
|
||||
}
|
||||
});
|
||||
vi.mocked(folderPrompt).mockResolvedValue("/wow/good/job/nice/folder");
|
||||
render(Splash, {});
|
||||
let pickInstallFolderButton = await screen.findByTestId(
|
||||
"pick-install-folder-button"
|
||||
);
|
||||
expect(pickInstallFolderButton).toBeTruthy();
|
||||
fireEvent.click(pickInstallFolderButton);
|
||||
await waitFor(() => {
|
||||
expect(setInstallDirectorySet).toBeTruthy();
|
||||
});
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(mainWindowOpened).toBeTruthy();
|
||||
},
|
||||
{ timeout: 5000 }
|
||||
);
|
||||
});
|
||||
|
||||
it("should prompt user to select installation directory - bad directory choosen", async () => {
|
||||
// TODO - generalize into function
|
||||
// return an object that tracks mock calls / args
|
||||
let mainWindowOpened = false;
|
||||
mockIPC((cmd, args) => {
|
||||
if (cmd === "get_locale") {
|
||||
return "en-US";
|
||||
} else if (cmd === "get_install_directory") {
|
||||
return null;
|
||||
} else if (cmd === "has_old_data_directory") {
|
||||
return false;
|
||||
} else if (cmd === "set_install_directory") {
|
||||
return "wow that was a terrible directory";
|
||||
} else if (cmd === "open_main_window") {
|
||||
mainWindowOpened = true;
|
||||
return;
|
||||
} else {
|
||||
console.log(`Unhandled Tauri IPC: ${cmd}`);
|
||||
}
|
||||
});
|
||||
vi.mocked(folderPrompt).mockResolvedValue("/wow/good/job/nice/folder");
|
||||
render(Splash, {});
|
||||
let pickInstallFolderButton = await screen.findByTestId(
|
||||
"pick-install-folder-button"
|
||||
);
|
||||
expect(pickInstallFolderButton).toBeTruthy();
|
||||
fireEvent.click(pickInstallFolderButton);
|
||||
await waitFor(() => {
|
||||
screen.findByText("wow that was a terrible directory");
|
||||
});
|
||||
pickInstallFolderButton = await screen.findByTestId(
|
||||
"pick-install-folder-button"
|
||||
);
|
||||
expect(pickInstallFolderButton).toBeTruthy();
|
||||
});
|
||||
});
|
5
src/tests/setup.ts
Normal file
5
src/tests/setup.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { vi, beforeAll } from "vitest";
|
||||
|
||||
beforeAll(() => {
|
||||
window.__TAURI_IPC__ = vi.fn();
|
||||
});
|
|
@ -24,7 +24,8 @@
|
|||
* Typecheck JS in `.svelte` and `.js` files by default.
|
||||
* Disable this if you'd like to use dynamic types.
|
||||
*/
|
||||
"checkJs": true
|
||||
"checkJs": true,
|
||||
"types": ["vitest/types"]
|
||||
},
|
||||
/**
|
||||
* Use global.d.ts instead of compilerOptions.types
|
||||
|
|
|
@ -7,7 +7,7 @@ export default defineConfig({
|
|||
server: {
|
||||
port: 3000, // The port the server will listen on.
|
||||
},
|
||||
plugins: [svelte()],
|
||||
plugins: [svelte({ hot: !process.env.VITEST })],
|
||||
resolve: {
|
||||
alias: {
|
||||
$lib: fileURLToPath(new URL("./src/lib", import.meta.url)),
|
||||
|
|
20
vitest.config.ts
Normal file
20
vitest.config.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { defineConfig } from "vitest/config";
|
||||
import { svelte } from "@sveltejs/vite-plugin-svelte";
|
||||
import { fileURLToPath, URL } from "url";
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [svelte({ hot: !process.env.VITEST })],
|
||||
resolve: {
|
||||
alias: {
|
||||
$lib: fileURLToPath(new URL("./src/lib", import.meta.url)),
|
||||
$assets: fileURLToPath(new URL("./src/assets", import.meta.url)),
|
||||
},
|
||||
},
|
||||
test: {
|
||||
alias: [{ find: /^svelte$/, replacement: "svelte/internal" }],
|
||||
include: ["./src/**/*.test.ts"],
|
||||
globals: true,
|
||||
environment: "jsdom",
|
||||
setupFiles: ["./src/tests/setup.ts"],
|
||||
},
|
||||
});
|
Loading…
Reference in a new issue