test: add initial unit tests (#56)

* chore: add initial db migration

* test: add unit tests for packages auth, common, widgets

* fix: deep source issues

* fix: format issues

* wip: add unit tests for api routers

* fix: deep source issues

* test:  add missing unit tests for integration router

* wip: board tests

* test: add unit tests for board router

* fix: remove unnecessary null assertions

* fix: deepsource issues

* fix: formatting

* fix: pnpm lock

* fix: lint and typecheck issues

* chore: address pull request feedback

* fix: non-null assertions

* fix: lockfile broken
This commit is contained in:
Meier Lukas
2024-02-10 19:00:08 +01:00
committed by GitHub
parent 13aae82790
commit f070a0cb0a
34 changed files with 3014 additions and 129 deletions

View File

@@ -7,4 +7,5 @@ export default {
schema: "./schema",
driver: "better-sqlite",
dbCredentials: { url: process.env.DB_URL! },
out: "./migrations",
} satisfies Config;

View File

@@ -8,7 +8,7 @@ export const schema = sqliteSchema;
export * from "drizzle-orm";
const sqlite = new Database(process.env.DB_URL);
export const sqlite = new Database(process.env.DB_URL);
export const db = drizzle(sqlite, { schema });

View File

@@ -0,0 +1,112 @@
CREATE TABLE `account` (
`userId` text NOT NULL,
`type` text NOT NULL,
`provider` text NOT NULL,
`providerAccountId` text NOT NULL,
`refresh_token` text,
`access_token` text,
`expires_at` integer,
`token_type` text,
`scope` text,
`id_token` text,
`session_state` text,
PRIMARY KEY(`provider`, `providerAccountId`),
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `board` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`is_public` integer DEFAULT false NOT NULL,
`page_title` text,
`meta_title` text,
`logo_image_url` text,
`favicon_image_url` text,
`background_image_url` text,
`background_image_attachment` text DEFAULT 'fixed' NOT NULL,
`background_image_repeat` text DEFAULT 'no-repeat' NOT NULL,
`background_image_size` text DEFAULT 'cover' NOT NULL,
`primary_color` text DEFAULT 'red' NOT NULL,
`secondary_color` text DEFAULT 'orange' NOT NULL,
`primary_shade` integer DEFAULT 6 NOT NULL,
`app_opacity` integer DEFAULT 100 NOT NULL,
`custom_css` text,
`show_right_sidebar` integer DEFAULT false NOT NULL,
`show_left_sidebar` integer DEFAULT false NOT NULL,
`column_count` integer DEFAULT 10 NOT NULL
);
--> statement-breakpoint
CREATE TABLE `integration_item` (
`item_id` text NOT NULL,
`integration_id` text NOT NULL,
PRIMARY KEY(`integration_id`, `item_id`),
FOREIGN KEY (`item_id`) REFERENCES `item`(`id`) ON UPDATE no action ON DELETE cascade,
FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `integrationSecret` (
`kind` text NOT NULL,
`value` text NOT NULL,
`updated_at` integer NOT NULL,
`integration_id` text NOT NULL,
PRIMARY KEY(`integration_id`, `kind`),
FOREIGN KEY (`integration_id`) REFERENCES `integration`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `integration` (
`id` text PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`url` text NOT NULL,
`kind` text NOT NULL
);
--> statement-breakpoint
CREATE TABLE `item` (
`id` text PRIMARY KEY NOT NULL,
`section_id` text NOT NULL,
`kind` text NOT NULL,
`x_offset` integer NOT NULL,
`y_offset` integer NOT NULL,
`width` integer NOT NULL,
`height` integer NOT NULL,
`options` text DEFAULT '{"json": {}}' NOT NULL,
FOREIGN KEY (`section_id`) REFERENCES `section`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `section` (
`id` text PRIMARY KEY NOT NULL,
`board_id` text NOT NULL,
`kind` text NOT NULL,
`position` integer NOT NULL,
`name` text,
FOREIGN KEY (`board_id`) REFERENCES `board`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `session` (
`sessionToken` text PRIMARY KEY NOT NULL,
`userId` text NOT NULL,
`expires` integer NOT NULL,
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `user` (
`id` text PRIMARY KEY NOT NULL,
`name` text,
`email` text,
`emailVerified` integer,
`image` text,
`password` text,
`salt` text
);
--> statement-breakpoint
CREATE TABLE `verificationToken` (
`identifier` text NOT NULL,
`token` text NOT NULL,
`expires` integer NOT NULL,
PRIMARY KEY(`identifier`, `token`)
);
--> statement-breakpoint
CREATE INDEX `userId_idx` ON `account` (`userId`);--> statement-breakpoint
CREATE INDEX `integration_secret__kind_idx` ON `integrationSecret` (`kind`);--> statement-breakpoint
CREATE INDEX `integration_secret__updated_at_idx` ON `integrationSecret` (`updated_at`);--> statement-breakpoint
CREATE INDEX `integration__kind_idx` ON `integration` (`kind`);--> statement-breakpoint
CREATE INDEX `user_id_idx` ON `session` (`userId`);

View File

@@ -0,0 +1,696 @@
{
"version": "5",
"dialect": "sqlite",
"id": "c9ea435a-5bbf-4439-84a1-55d3e2581b13",
"prevId": "00000000-0000-0000-0000-000000000000",
"tables": {
"account": {
"name": "account",
"columns": {
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"type": {
"name": "type",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"provider": {
"name": "provider",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"providerAccountId": {
"name": "providerAccountId",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"refresh_token": {
"name": "refresh_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"access_token": {
"name": "access_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"expires_at": {
"name": "expires_at",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"token_type": {
"name": "token_type",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"scope": {
"name": "scope",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"id_token": {
"name": "id_token",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"session_state": {
"name": "session_state",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {
"userId_idx": {
"name": "userId_idx",
"columns": ["userId"],
"isUnique": false
}
},
"foreignKeys": {
"account_userId_user_id_fk": {
"name": "account_userId_user_id_fk",
"tableFrom": "account",
"tableTo": "user",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"account_provider_providerAccountId_pk": {
"columns": ["provider", "providerAccountId"],
"name": "account_provider_providerAccountId_pk"
}
},
"uniqueConstraints": {}
},
"board": {
"name": "board",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"is_public": {
"name": "is_public",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"page_title": {
"name": "page_title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"meta_title": {
"name": "meta_title",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"logo_image_url": {
"name": "logo_image_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"favicon_image_url": {
"name": "favicon_image_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"background_image_url": {
"name": "background_image_url",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"background_image_attachment": {
"name": "background_image_attachment",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'fixed'"
},
"background_image_repeat": {
"name": "background_image_repeat",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'no-repeat'"
},
"background_image_size": {
"name": "background_image_size",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'cover'"
},
"primary_color": {
"name": "primary_color",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'red'"
},
"secondary_color": {
"name": "secondary_color",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'orange'"
},
"primary_shade": {
"name": "primary_shade",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 6
},
"app_opacity": {
"name": "app_opacity",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 100
},
"custom_css": {
"name": "custom_css",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"show_right_sidebar": {
"name": "show_right_sidebar",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"show_left_sidebar": {
"name": "show_left_sidebar",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": false
},
"column_count": {
"name": "column_count",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 10
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"integration_item": {
"name": "integration_item",
"columns": {
"item_id": {
"name": "item_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"integration_id": {
"name": "integration_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"integration_item_item_id_item_id_fk": {
"name": "integration_item_item_id_item_id_fk",
"tableFrom": "integration_item",
"tableTo": "item",
"columnsFrom": ["item_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"integration_item_integration_id_integration_id_fk": {
"name": "integration_item_integration_id_integration_id_fk",
"tableFrom": "integration_item",
"tableTo": "integration",
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integration_item_item_id_integration_id_pk": {
"columns": ["integration_id", "item_id"],
"name": "integration_item_item_id_integration_id_pk"
}
},
"uniqueConstraints": {}
},
"integrationSecret": {
"name": "integrationSecret",
"columns": {
"kind": {
"name": "kind",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"value": {
"name": "value",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"updated_at": {
"name": "updated_at",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"integration_id": {
"name": "integration_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"integration_secret__kind_idx": {
"name": "integration_secret__kind_idx",
"columns": ["kind"],
"isUnique": false
},
"integration_secret__updated_at_idx": {
"name": "integration_secret__updated_at_idx",
"columns": ["updated_at"],
"isUnique": false
}
},
"foreignKeys": {
"integrationSecret_integration_id_integration_id_fk": {
"name": "integrationSecret_integration_id_integration_id_fk",
"tableFrom": "integrationSecret",
"tableTo": "integration",
"columnsFrom": ["integration_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"integrationSecret_integration_id_kind_pk": {
"columns": ["integration_id", "kind"],
"name": "integrationSecret_integration_id_kind_pk"
}
},
"uniqueConstraints": {}
},
"integration": {
"name": "integration",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"url": {
"name": "url",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"kind": {
"name": "kind",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"integration__kind_idx": {
"name": "integration__kind_idx",
"columns": ["kind"],
"isUnique": false
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"item": {
"name": "item",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"section_id": {
"name": "section_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"kind": {
"name": "kind",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"x_offset": {
"name": "x_offset",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"y_offset": {
"name": "y_offset",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"width": {
"name": "width",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"height": {
"name": "height",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"options": {
"name": "options",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": "'{\"json\": {}}'"
}
},
"indexes": {},
"foreignKeys": {
"item_section_id_section_id_fk": {
"name": "item_section_id_section_id_fk",
"tableFrom": "item",
"tableTo": "section",
"columnsFrom": ["section_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"section": {
"name": "section",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"board_id": {
"name": "board_id",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"kind": {
"name": "kind",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"position": {
"name": "position",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {
"section_board_id_board_id_fk": {
"name": "section_board_id_board_id_fk",
"tableFrom": "section",
"tableTo": "board",
"columnsFrom": ["board_id"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"session": {
"name": "session",
"columns": {
"sessionToken": {
"name": "sessionToken",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"userId": {
"name": "userId",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"expires": {
"name": "expires",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {
"user_id_idx": {
"name": "user_id_idx",
"columns": ["userId"],
"isUnique": false
}
},
"foreignKeys": {
"session_userId_user_id_fk": {
"name": "session_userId_user_id_fk",
"tableFrom": "session",
"tableTo": "user",
"columnsFrom": ["userId"],
"columnsTo": ["id"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user": {
"name": "user",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"email": {
"name": "email",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"emailVerified": {
"name": "emailVerified",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"image": {
"name": "image",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"password": {
"name": "password",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"salt": {
"name": "salt",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"verificationToken": {
"name": "verificationToken",
"columns": {
"identifier": {
"name": "identifier",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"token": {
"name": "token",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"expires": {
"name": "expires",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {
"verificationToken_identifier_token_pk": {
"columns": ["identifier", "token"],
"name": "verificationToken_identifier_token_pk"
}
},
"uniqueConstraints": {}
}
},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}

View File

@@ -0,0 +1,13 @@
{
"version": "5",
"dialect": "sqlite",
"entries": [
{
"idx": 0,
"version": "5",
"when": 1707511343363,
"tag": "0000_true_red_wolf",
"breakpoints": true
}
]
}

View File

@@ -4,7 +4,8 @@
"exports": {
".": "./index.ts",
"./client": "./client.ts",
"./schema/sqlite": "./schema/sqlite.ts"
"./schema/sqlite": "./schema/sqlite.ts",
"./test": "./test/index.ts"
},
"private": true,
"main": "./index.ts",
@@ -14,6 +15,7 @@
"clean": "rm -rf .turbo node_modules",
"lint": "eslint .",
"format": "prettier --check . --ignore-path ../../.gitignore",
"migration:generate": "drizzle-kit generate:sqlite",
"push": "drizzle-kit push:sqlite",
"studio": "drizzle-kit studio",
"typecheck": "tsc --noEmit"

View File

@@ -0,0 +1,14 @@
import Database from "better-sqlite3";
import { drizzle } from "drizzle-orm/better-sqlite3";
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
import { schema } from "..";
export const createDb = () => {
const sqlite = new Database(":memory:");
const db = drizzle(sqlite, { schema });
migrate(db, {
migrationsFolder: "./packages/db/migrations",
});
return db;
};

View File

@@ -0,0 +1 @@
export * from "./db-mock";