From fff87e4a50ce83d4f0a55b144c144eb592385a56 Mon Sep 17 00:00:00 2001 From: Felix Kling Date: Wed, 19 Jul 2023 16:58:29 +0200 Subject: [PATCH] sveltekit: Setup unit tests with vitest (#54953) This PR adds vitest and faker for unit testing, and to use it properly already I refactored the promise->store helper to be more flexible. **Unit testing** vitest works prefectly together with vite (it's from the same author/community). It will use the same configuration and so there is very little additional configuration necessary. I only had to update vite.config.ts to not overwrite `process` (but according to https://vitejs.dev/config/shared-options.html#define I might not be doing it right anyway... will look into this another time). The API is pretty compatible with jest, so there shouldn't be any surprises. Tests can be run with `pnpm vitest`. **Faker** I stared to use faker on a differnt branch to generate more (and more realistic) test data for storybook stories and unit test. Eventually I'd like to use this to generate mock data for any of our GraphQL APIs. One great feature is the ability to _seed_ the random number generator so that you can get random but repeatable values in tests. **Promise<>store utility** Working with promises in a reactive way can be tricky. There is a risk of stale data ovewriting current data when an older promise resolves after a newer one. Observables can help here but since we are trying to move away from them, I introduced a simple store to handle promises. I extended it now to handle more cases, especially being able to access the previous value while a new promise is loading. The API might seem clunky (and I'd be happy to improve it eventually), but this way makes it easier to remember to call `set` whenever the promise changes. ## Test plan `pnpm vitest` Run dev server, open pages affected by promise store changes (repo pages) and verify that they behave as expected. --- client/BUILD.bazel | 2 + client/web-sveltekit/package.json | 4 +- client/web-sveltekit/src/lib/Commit.svelte | 2 +- .../src/lib/repo/GitReference.svelte | 2 +- client/web-sveltekit/src/lib/repo/api/tree.ts | 2 +- .../src/lib/temporarySettings.ts | 6 +- client/web-sveltekit/src/lib/utils.ts | 90 ----- .../lib/utils/__snapshots__/time.test.ts.snap | 45 +++ client/web-sveltekit/src/lib/utils/index.ts | 3 + .../src/lib/utils/promises.test.ts | 107 ++++++ .../web-sveltekit/src/lib/utils/promises.ts | 92 +++++ .../src/lib/utils/stores.test.ts | 41 +++ client/web-sveltekit/src/lib/utils/stores.ts | 30 ++ .../web-sveltekit/src/lib/utils/time.test.ts | 68 ++++ .../lib/{relativeTime.ts => utils/time.ts} | 0 .../routes/[...repo]/(code)/+layout.svelte | 2 +- .../src/routes/[...repo]/(code)/+page.svelte | 22 +- .../(code)/-/blob/[...path]/+page.svelte | 33 +- .../(code)/-/tree/[...path]/+page.svelte | 26 +- .../routes/[...repo]/(code)/FileTree.svelte | 6 +- .../routes/[...repo]/-/branches/+page.svelte | 49 +-- .../[...repo]/-/branches/all/+page.svelte | 11 +- .../-/commit/[...revspec]/+page.svelte | 25 +- .../routes/[...repo]/-/commits/+page.svelte | 11 +- .../-/stats/contributors/+page.svelte | 33 +- .../src/routes/[...repo]/-/tags/+page.svelte | 12 +- client/web-sveltekit/vite.config.ts | 17 +- pnpm-lock.yaml | 325 ++++++++++++++++-- 28 files changed, 817 insertions(+), 249 deletions(-) delete mode 100644 client/web-sveltekit/src/lib/utils.ts create mode 100644 client/web-sveltekit/src/lib/utils/__snapshots__/time.test.ts.snap create mode 100644 client/web-sveltekit/src/lib/utils/index.ts create mode 100644 client/web-sveltekit/src/lib/utils/promises.test.ts create mode 100644 client/web-sveltekit/src/lib/utils/promises.ts create mode 100644 client/web-sveltekit/src/lib/utils/stores.test.ts create mode 100644 client/web-sveltekit/src/lib/utils/stores.ts create mode 100644 client/web-sveltekit/src/lib/utils/time.test.ts rename client/web-sveltekit/src/lib/{relativeTime.ts => utils/time.ts} (100%) diff --git a/client/BUILD.bazel b/client/BUILD.bazel index d6d210a73a8..07e92772acd 100644 --- a/client/BUILD.bazel +++ b/client/BUILD.bazel @@ -14,6 +14,8 @@ # gazelle:js_test_files **/__mocks__/**/*.{ts,tsx} # gazelle:js_test_files **/fixtures/**/*.{ts,tsx} # gazelle:js_test_files **/WebStory.{ts,tsx} +# TODO(bazel): sveltekit tests +# gazelle:exclude **/web-sveltekit/**/*.test.ts # TODO(bazel): put fixtures + testutils + ? into own rules # js_{fixture}_files **/*.{fixture,fixtures}.{ts,tsx} diff --git a/client/web-sveltekit/package.json b/client/web-sveltekit/package.json index 58acea3ddff..cfd977dfd5b 100644 --- a/client/web-sveltekit/package.json +++ b/client/web-sveltekit/package.json @@ -18,6 +18,7 @@ "build-storybook": "storybook build" }, "devDependencies": { + "@faker-js/faker": "^8.0.2", "@playwright/test": "1.25.0", "@storybook/addon-essentials": "^7.0.26", "@storybook/addon-interactions": "^7.0.26", @@ -41,7 +42,8 @@ "svelte": "^4.0.0", "svelte-check": "^3.4.3", "tslib": "2.1.0", - "vite": "^4.3.9" + "vite": "^4.3.9", + "vitest": "^0.33.0" }, "type": "module", "dependencies": { diff --git a/client/web-sveltekit/src/lib/Commit.svelte b/client/web-sveltekit/src/lib/Commit.svelte index 64219fd364f..0654eacc6e5 100644 --- a/client/web-sveltekit/src/lib/Commit.svelte +++ b/client/web-sveltekit/src/lib/Commit.svelte @@ -3,9 +3,9 @@ import type { GitCommitFields } from '$lib/graphql-operations' import Icon from '$lib/Icon.svelte' - import { getRelativeTime } from '$lib/relativeTime' import { currentDate as now } from '$lib/stores' import UserAvatar from '$lib/UserAvatar.svelte' + import { getRelativeTime } from '$lib/utils' export let commit: GitCommitFields export let alwaysExpanded: boolean = false diff --git a/client/web-sveltekit/src/lib/repo/GitReference.svelte b/client/web-sveltekit/src/lib/repo/GitReference.svelte index 3f77eed5a66..15325dcba56 100644 --- a/client/web-sveltekit/src/lib/repo/GitReference.svelte +++ b/client/web-sveltekit/src/lib/repo/GitReference.svelte @@ -1,8 +1,8 @@ {#if !$sidebarOpen} @@ -32,10 +38,10 @@

{/if} - {#if !$treeEntries.loading && $treeEntries.data} + {#if $treeOrError && !isErrorLike($treeOrError)}

Files and directories