mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-04 21:04:37 +08:00
In-source unit tests (#429)
Co-authored-by: Konsti Wohlwend <n2d4xc@gmail.com>
This commit is contained in:
parent
1c1bc42b94
commit
816d64c850
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@ -8,7 +8,8 @@
|
||||
"streetsidesoftware.code-spell-checker",
|
||||
"YoavBls.pretty-ts-errors",
|
||||
"mxsdev.typescript-explorer",
|
||||
"github.vscode-github-actions"
|
||||
"github.vscode-github-actions",
|
||||
"fabiospampinato.vscode-highlight"
|
||||
],
|
||||
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
||||
"unwantedRecommendations": [
|
||||
|
||||
41
.vscode/settings.json
vendored
41
.vscode/settings.json
vendored
@ -103,5 +103,44 @@
|
||||
"**/start-server.js",
|
||||
"**/turbo/**"
|
||||
],
|
||||
"files.insertFinalNewline": true
|
||||
"files.insertFinalNewline": true,
|
||||
"highlight.regexes": {
|
||||
"(import\\.meta\\.vitest\\?\\.test\\()[\"'`]([^\"'`]*)(.*)": [
|
||||
{
|
||||
"isWholeLine": true,
|
||||
"before": {
|
||||
"contentText": "test> ",
|
||||
"color": "#008080",
|
||||
"fontStyle": "italic"
|
||||
},
|
||||
}
|
||||
],
|
||||
"((?<=(?:import\\.meta\\.vitest\\?\\.test\\(.*\\n)(?:(?!(\\n\\}?\\);))[\\s\\S])*))\\n": [
|
||||
{
|
||||
"isWholeLine": true,
|
||||
"before": {
|
||||
"contentText": " ",
|
||||
"color": "#008080",
|
||||
"fontStyle": "italic"
|
||||
},
|
||||
},
|
||||
],
|
||||
"(import\\.meta\\.vitest\\?\\.test\\([\\s\\S]*?(\\n\\}?\\);))": [
|
||||
{},
|
||||
{
|
||||
"isWholeLine": true,
|
||||
"before": {
|
||||
"contentText": " ",
|
||||
"color": "#008080",
|
||||
"fontStyle": "italic"
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
// disable the default TODO highlighting
|
||||
"((?:<!-- *)?(?:#|// @|//|./\\*+|<!--|--|\\* @|{!|{{!--|{{!) *TODO(?:\\s*\\([^)]+\\))?:?)((?!\\w)(?: *-->| *\\*/| *!}| *--}}| *}}|(?= *(?:[^:]//|/\\*+|<!--|@|--|{!|{{!--|{{!))|(?: +[^\\n@]*?)(?= *(?:[^:]//|/\\*+|<!--|@|--(?!>)|{!|{{!--|{{!))|(?: +[^@\\n]+)?))": [],
|
||||
"((?:<!-- *)?(?:#|// @|//|./\\*+|<!--|--|\\* @|{!|{{!--|{{!) *(?:FIXME|FIX|BUG|UGLY|DEBUG|HACK)(?:\\s*\\([^)]+\\))?:?)((?!\\w)(?: *-->| *\\*/| *!}| *--}}| *}}|(?= *(?:[^:]//|/\\*+|<!--|@|--|{!|{{!--|{{!))|(?: +[^\\n@]*?)(?= *(?:[^:]//|/\\*+|<!--|@|--(?!>)|{!|{{!--|{{!))|(?: +[^@\\n]+)?))": [],
|
||||
"((?:<!-- *)?(?:#|// @|//|./\\*+|<!--|--|\\* @|{!|{{!--|{{!) *(?:REVIEW|OPTIMIZE|TSC)(?:\\s*\\([^)]+\\))?:?)((?!\\w)(?: *-->| *\\*/| *!}| *--}}| *}}|(?= *(?:[^:]//|/\\*+|<!--|@|--|{!|{{!--|{{!))|(?: +[^\\n@]*?)(?= *(?:[^:]//|/\\*+|<!--|@|--(?!>)|{!|{{!--|{{!))|(?: +[^@\\n]+)?))": [],
|
||||
"((?:<!-- *)?(?:#|// @|//|./\\*+|<!--|--|\\* @|{!|{{!--|{{!) *(?:IDEA)(?:\\s*\\([^)]+\\))?:?)((?!\\w)(?: *-->| *\\*/| *!}| *--}}| *}}|(?= *(?:[^:]//|/\\*+|<!--|@|--|{!|{{!--|{{!))|(?: +[^\\n@]*?)(?= *(?:[^:]//|/\\*+|<!--|@|--(?!>)|{!|{{!--|{{!))|(?: +[^@\\n]+)?))": [],
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,10 @@
|
||||
"./src/*"
|
||||
]
|
||||
},
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"vitest/importMeta"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
|
||||
7
apps/backend/vitest.config.ts
Normal file
7
apps/backend/vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||
import sharedConfig from '../../vitest.shared'
|
||||
|
||||
export default mergeConfig(
|
||||
sharedConfig,
|
||||
defineConfig({}),
|
||||
)
|
||||
@ -27,7 +27,10 @@
|
||||
"./src/*"
|
||||
]
|
||||
},
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"vitest/importMeta"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
|
||||
7
apps/dashboard/vitest.config.ts
Normal file
7
apps/dashboard/vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||
import sharedConfig from '../../vitest.shared'
|
||||
|
||||
export default mergeConfig(
|
||||
sharedConfig,
|
||||
defineConfig({}),
|
||||
)
|
||||
@ -10,7 +10,10 @@
|
||||
"esModuleInterop": true,
|
||||
"noErrorTruncation": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"vitest/importMeta"
|
||||
]
|
||||
},
|
||||
"include": ["tests/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
import react from '@vitejs/plugin-react'
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||
import sharedConfig from '../../vitest.shared'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
test: {
|
||||
environment: 'node',
|
||||
testTimeout: 20_000,
|
||||
globalSetup: './tests/global-setup.ts',
|
||||
setupFiles: [
|
||||
"./tests/setup.ts",
|
||||
],
|
||||
snapshotSerializers: ["./tests/snapshot-serializer.ts"],
|
||||
},
|
||||
})
|
||||
export default mergeConfig(
|
||||
sharedConfig,
|
||||
defineConfig({
|
||||
plugins: [react()],
|
||||
test: {
|
||||
environment: 'node',
|
||||
testTimeout: 20_000,
|
||||
globalSetup: './tests/global-setup.ts',
|
||||
setupFiles: [
|
||||
"./tests/setup.ts",
|
||||
],
|
||||
snapshotSerializers: ["./tests/snapshot-serializer.ts"],
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
7
apps/oauth-mock-server/vitest.config.ts
Normal file
7
apps/oauth-mock-server/vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||
import sharedConfig from '../../vitest.shared'
|
||||
|
||||
export default mergeConfig(
|
||||
sharedConfig,
|
||||
defineConfig({}),
|
||||
)
|
||||
@ -39,6 +39,8 @@
|
||||
"peek": "pnpm pre && pnpm release --peek",
|
||||
"changeset": "pnpm pre && changeset",
|
||||
"test": "pnpm pre && vitest",
|
||||
"test:e2e": "pnpm pre && vitest e2e/tests",
|
||||
"test:unit": "pnpm pre && vitest src",
|
||||
"verify-data-integrity": "pnpm pre && pnpm -C apps/backend run verify-data-integrity",
|
||||
"generate-docs": "pnpm pre && turbo run generate-docs",
|
||||
"generate-keys": "pnpm pre && turbo run generate-keys",
|
||||
|
||||
7
packages/init-stack/vitest.config.ts
Normal file
7
packages/init-stack/vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||
import sharedConfig from '../../vitest.shared'
|
||||
|
||||
export default mergeConfig(
|
||||
sharedConfig,
|
||||
defineConfig({}),
|
||||
)
|
||||
@ -11,7 +11,10 @@
|
||||
"esModuleInterop": true,
|
||||
"noErrorTruncation": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"vitest/importMeta"
|
||||
]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
|
||||
7
packages/stack-emails/vitest.config.ts
Normal file
7
packages/stack-emails/vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||
import sharedConfig from '../../vitest.shared'
|
||||
|
||||
export default mergeConfig(
|
||||
sharedConfig,
|
||||
defineConfig({}),
|
||||
)
|
||||
@ -11,7 +11,10 @@
|
||||
"esModuleInterop": true,
|
||||
"noErrorTruncation": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true
|
||||
"strict": true,
|
||||
"types": [
|
||||
"vitest/importMeta"
|
||||
]
|
||||
},
|
||||
"include": ["src/**/*", "next-env.d.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
|
||||
7
packages/stack-sc/vitest.config.ts
Normal file
7
packages/stack-sc/vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||
import sharedConfig from '../../vitest.shared'
|
||||
|
||||
export default mergeConfig(
|
||||
sharedConfig,
|
||||
defineConfig({}),
|
||||
)
|
||||
@ -7,6 +7,7 @@
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run",
|
||||
"clean": "rimraf dist && rimraf node_modules",
|
||||
"dev": "tsc -w --preserveWatchOutput --declarationMap",
|
||||
"lint": "eslint --ext .tsx,.ts ."
|
||||
|
||||
33
packages/stack-shared/src/utils/strings.test.ts
Normal file
33
packages/stack-shared/src/utils/strings.test.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { templateIdentity } from "./strings";
|
||||
|
||||
describe("templateIdentity", () => {
|
||||
it("should be equivalent to a regular template string", () => {
|
||||
const adjective = "scientific";
|
||||
const noun = "railgun";
|
||||
expect(templateIdentity`a certain scientific railgun`).toBe("a certain scientific railgun");
|
||||
expect(templateIdentity`a certain ${adjective} railgun`).toBe(`a certain scientific railgun`);
|
||||
expect(templateIdentity`a certain ${adjective} ${noun}`).toBe(`a certain scientific railgun`);
|
||||
expect(templateIdentity`${adjective}${noun}`).toBe(`scientificrailgun`);
|
||||
});
|
||||
|
||||
it("should work with empty strings", () => {
|
||||
expect(templateIdentity``).toBe("");
|
||||
expect(templateIdentity`${""}`).toBe("");
|
||||
expect(templateIdentity`${""}${""}`).toBe("");
|
||||
});
|
||||
|
||||
it("should work with normal arrays", () => {
|
||||
expect(templateIdentity(
|
||||
["a ", " scientific ", "gun"],
|
||||
"certain", "rail")
|
||||
).toBe("a certain scientific railgun");
|
||||
expect(templateIdentity(["a"])).toBe("a");
|
||||
});
|
||||
|
||||
it("should throw an error with wrong number of value arguments", () => {
|
||||
expect(() => templateIdentity([])).toThrow();
|
||||
expect(() => templateIdentity(["a", "b"])).toThrow();
|
||||
expect(() => templateIdentity(["a", "b", "c"], "a", "b", "c")).toThrow();
|
||||
});
|
||||
});
|
||||
@ -70,6 +70,19 @@ export function trimEmptyLinesEnd(s: string): string {
|
||||
export function trimLines(s: string): string {
|
||||
return trimEmptyLinesEnd(trimEmptyLinesStart(s));
|
||||
}
|
||||
import.meta.vitest?.test("trimLines", ({ expect }) => {
|
||||
expect(trimLines("")).toBe("");
|
||||
expect(trimLines(" ")).toBe("");
|
||||
expect(trimLines(" \n ")).toBe("");
|
||||
expect(trimLines(" abc ")).toBe(" abc ");
|
||||
expect(trimLines("\n \nLine1\nLine2\n \n")).toBe("Line1\nLine2");
|
||||
expect(trimLines("Line1\n \nLine2")).toBe("Line1\n \nLine2");
|
||||
expect(trimLines(" \n \n\t")).toBe("");
|
||||
expect(trimLines(" Hello World")).toBe(" Hello World");
|
||||
expect(trimLines("\n")).toBe("");
|
||||
expect(trimLines("\t \n\t\tLine1 \n \nLine2\t\t\n\t ")).toBe("\t\tLine1 \n \nLine2\t\t");
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* A template literal tag that returns the same string as the template literal without a tag.
|
||||
@ -77,8 +90,26 @@ export function trimLines(s: string): string {
|
||||
* Useful for implementing your own template literal tags.
|
||||
*/
|
||||
export function templateIdentity(strings: TemplateStringsArray | readonly string[], ...values: string[]): string {
|
||||
if (values.length !== strings.length - 1) throw new StackAssertionError("Invalid number of values; must be one less than strings", { strings, values });
|
||||
|
||||
return strings.reduce((result, str, i) => result + str + (values[i] ?? ''), '');
|
||||
}
|
||||
import.meta.vitest?.test("templateIdentity", ({ expect }) => {
|
||||
expect(templateIdentity`Hello World`).toBe("Hello World");
|
||||
expect(templateIdentity`${"Hello"}`).toBe("Hello");
|
||||
const greeting = "Hello";
|
||||
const subject = "World";
|
||||
expect(templateIdentity`${greeting}, ${subject}!`).toBe("Hello, World!");
|
||||
expect(templateIdentity`${"A"}${"B"}${"C"}`).toBe("ABC");
|
||||
expect(templateIdentity`Start${""}Middle${""}End`).toBe("StartMiddleEnd");
|
||||
expect(templateIdentity``).toBe("");
|
||||
expect(templateIdentity`Line1
|
||||
Line2`).toBe("Line1\nLine2");
|
||||
expect(templateIdentity(["a ", " scientific ", "gun"], "certain", "rail")).toBe("a certain scientific railgun");
|
||||
expect(templateIdentity(["only one part"])).toBe("only one part");
|
||||
expect(() => templateIdentity(["a ", "b", "c"], "only one")).toThrow("Invalid number of values");
|
||||
expect(() => templateIdentity(["a", "b"], "x", "y")).toThrow("Invalid number of values");
|
||||
});
|
||||
|
||||
|
||||
export function deindent(code: string): string;
|
||||
@ -86,7 +117,7 @@ export function deindent(strings: TemplateStringsArray | readonly string[], ...v
|
||||
export function deindent(strings: string | readonly string[], ...values: any[]): string {
|
||||
if (typeof strings === "string") return deindent([strings]);
|
||||
if (strings.length === 0) return "";
|
||||
if (values.length !== strings.length - 1) throw new Error("Invalid number of values; must be one less than strings");
|
||||
if (values.length !== strings.length - 1) throw new StackAssertionError("Invalid number of values; must be one less than strings", { strings, values });
|
||||
|
||||
const trimmedStrings = [...strings];
|
||||
trimmedStrings[0] = trimEmptyLinesStart(trimmedStrings[0]);
|
||||
|
||||
@ -6,12 +6,15 @@
|
||||
"declaration": true,
|
||||
"target": "ES2021",
|
||||
"lib": ["DOM", "DOM.Iterable", "ES2021", "ES2022.Error"],
|
||||
"module": "ES2015",
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "Bundler",
|
||||
"esModuleInterop": true,
|
||||
"noErrorTruncation": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"vitest/importMeta"
|
||||
]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
|
||||
7
packages/stack-shared/vitest.config.ts
Normal file
7
packages/stack-shared/vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||
import sharedConfig from '../../vitest.shared'
|
||||
|
||||
export default mergeConfig(
|
||||
sharedConfig,
|
||||
defineConfig({}),
|
||||
)
|
||||
@ -11,7 +11,10 @@
|
||||
"esModuleInterop": true,
|
||||
"noErrorTruncation": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
"skipLibCheck": true,
|
||||
"types": [
|
||||
"vitest/importMeta"
|
||||
]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
|
||||
7
packages/stack-ui/vitest.config.ts
Normal file
7
packages/stack-ui/vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||
import sharedConfig from '../../vitest.shared'
|
||||
|
||||
export default mergeConfig(
|
||||
sharedConfig,
|
||||
defineConfig({}),
|
||||
)
|
||||
@ -13,7 +13,10 @@
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"sourceMap": true,
|
||||
"declarationMap": true
|
||||
"declarationMap": true,
|
||||
"types": [
|
||||
"vitest/importMeta"
|
||||
]
|
||||
},
|
||||
"include": ["next-env.d.ts", "src/**/*", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
|
||||
7
packages/template/vitest.config.ts
Normal file
7
packages/template/vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { defineConfig, mergeConfig } from 'vitest/config'
|
||||
import sharedConfig from '../../vitest.shared'
|
||||
|
||||
export default mergeConfig(
|
||||
sharedConfig,
|
||||
defineConfig({}),
|
||||
)
|
||||
8
vitest.shared.ts
Normal file
8
vitest.shared.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { defineConfig } from 'vitest/config'
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ['**/*.test.{js,ts,jsx,tsx}'],
|
||||
includeSource: ['**/*.{js,ts,jsx,tsx}'],
|
||||
},
|
||||
})
|
||||
@ -1,6 +1,8 @@
|
||||
export default [
|
||||
import { defineWorkspace } from 'vitest/config';
|
||||
|
||||
export default defineWorkspace([
|
||||
'packages/*',
|
||||
'apps/*',
|
||||
'examples/*',
|
||||
'docs',
|
||||
];
|
||||
]);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user