feat(server): init user module (#2018)
This commit is contained in:
32
.github/workflows/build-master.yml
vendored
32
.github/workflows/build-master.yml
vendored
@@ -195,13 +195,45 @@ jobs:
|
|||||||
name: Server Test
|
name: Server Test
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: development
|
environment: development
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres
|
||||||
|
env:
|
||||||
|
POSTGRES_PASSWORD: affine
|
||||||
|
options: >-
|
||||||
|
--health-cmd pg_isready
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: ./.github/actions/setup-node
|
uses: ./.github/actions/setup-node
|
||||||
|
- name: Initialize database
|
||||||
|
run: |
|
||||||
|
psql -h localhost -U postgres -c "CREATE DATABASE affine;"
|
||||||
|
psql -h localhost -U postgres -c "CREATE USER affine WITH PASSWORD 'affine';"
|
||||||
|
psql -h localhost -U postgres -c "ALTER USER affine WITH SUPERUSER;"
|
||||||
|
env:
|
||||||
|
PGPASSWORD: affine
|
||||||
|
- name: Generate prisma client
|
||||||
|
run: |
|
||||||
|
yarn exec prisma generate
|
||||||
|
yarn exec prisma db push
|
||||||
|
working-directory: apps/server
|
||||||
|
env:
|
||||||
|
DATABASE_URL: postgresql://affine:affine@localhost:5432/affine
|
||||||
|
- name: Run init-db script
|
||||||
|
run: yarn exec ts-node-esm ./scripts/init-db.ts
|
||||||
|
env:
|
||||||
|
DATABASE_URL: postgresql://affine:affine@localhost:5432/affine
|
||||||
- name: Run server tests
|
- name: Run server tests
|
||||||
run: yarn test:coverage
|
run: yarn test:coverage
|
||||||
working-directory: apps/server
|
working-directory: apps/server
|
||||||
|
env:
|
||||||
|
DATABASE_URL: postgresql://affine:affine@localhost:5432/affine
|
||||||
- name: Upload server test coverage results
|
- name: Upload server test coverage results
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
33
.github/workflows/build.yml
vendored
33
.github/workflows/build.yml
vendored
@@ -86,13 +86,46 @@ jobs:
|
|||||||
name: Server Test
|
name: Server Test
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
environment: development
|
environment: development
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres
|
||||||
|
env:
|
||||||
|
POSTGRES_PASSWORD: affine
|
||||||
|
options: >-
|
||||||
|
--health-cmd pg_isready
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: ./.github/actions/setup-node
|
uses: ./.github/actions/setup-node
|
||||||
|
- name: Initialize database
|
||||||
|
run: |
|
||||||
|
psql -h localhost -U postgres -c "CREATE DATABASE affine;"
|
||||||
|
psql -h localhost -U postgres -c "CREATE USER affine WITH PASSWORD 'affine';"
|
||||||
|
psql -h localhost -U postgres -c "ALTER USER affine WITH SUPERUSER;"
|
||||||
|
env:
|
||||||
|
PGPASSWORD: affine
|
||||||
|
- name: Generate prisma client
|
||||||
|
run: |
|
||||||
|
yarn exec prisma generate
|
||||||
|
yarn exec prisma db push
|
||||||
|
working-directory: apps/server
|
||||||
|
env:
|
||||||
|
DATABASE_URL: postgresql://affine:affine@localhost:5432/affine
|
||||||
|
- name: Run init-db script
|
||||||
|
run: yarn exec ts-node-esm ./scripts/init-db.ts
|
||||||
|
working-directory: apps/server
|
||||||
|
env:
|
||||||
|
DATABASE_URL: postgresql://affine:affine@localhost:5432/affine
|
||||||
- name: Run server tests
|
- name: Run server tests
|
||||||
run: yarn test:coverage
|
run: yarn test:coverage
|
||||||
working-directory: apps/server
|
working-directory: apps/server
|
||||||
|
env:
|
||||||
|
DATABASE_URL: postgresql://affine:affine@localhost:5432/affine
|
||||||
- name: Upload server test coverage results
|
- name: Upload server test coverage results
|
||||||
uses: codecov/codecov-action@v3
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
|
|||||||
67
apps/server/migrations/20230418212743_init/migration.sql
Normal file
67
apps/server/migrations/20230418212743_init/migration.sql
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "google_users" (
|
||||||
|
"id" VARCHAR NOT NULL,
|
||||||
|
"user_id" VARCHAR NOT NULL,
|
||||||
|
"google_id" VARCHAR NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "google_users_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "permissions" (
|
||||||
|
"id" VARCHAR NOT NULL,
|
||||||
|
"workspace_id" VARCHAR NOT NULL,
|
||||||
|
"user_id" VARCHAR,
|
||||||
|
"user_email" TEXT,
|
||||||
|
"type" SMALLINT NOT NULL,
|
||||||
|
"accepted" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "permissions_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "seaql_migrations" (
|
||||||
|
"version" VARCHAR NOT NULL,
|
||||||
|
"applied_at" BIGINT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "seaql_migrations_pkey" PRIMARY KEY ("version")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "users" (
|
||||||
|
"id" VARCHAR NOT NULL,
|
||||||
|
"name" VARCHAR NOT NULL,
|
||||||
|
"email" VARCHAR NOT NULL,
|
||||||
|
"avatar_url" VARCHAR,
|
||||||
|
"token_nonce" SMALLINT DEFAULT 0,
|
||||||
|
"password" VARCHAR,
|
||||||
|
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "workspaces" (
|
||||||
|
"id" VARCHAR NOT NULL,
|
||||||
|
"public" BOOLEAN NOT NULL,
|
||||||
|
"type" SMALLINT NOT NULL,
|
||||||
|
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT "workspaces_pkey" PRIMARY KEY ("id")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "google_users_google_id_key" ON "google_users"("google_id");
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "google_users" ADD CONSTRAINT "google_users_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "permissions" ADD CONSTRAINT "permissions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "permissions" ADD CONSTRAINT "permissions_workspace_id_fkey" FOREIGN KEY ("workspace_id") REFERENCES "workspaces"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
3
apps/server/migrations/migration_lock.toml
Normal file
3
apps/server/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (i.e. Git)
|
||||||
|
provider = "postgresql"
|
||||||
@@ -4,10 +4,13 @@
|
|||||||
"version": "0.5.3",
|
"version": "0.5.3",
|
||||||
"description": "Affine Node.js server",
|
"description": "Affine Node.js server",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"bin": {
|
||||||
|
"run-test": "./scripts/run-test.ts"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nodemon ./src/index.ts",
|
"dev": "nodemon ./src/index.ts",
|
||||||
"test": "NODE_ENV=test node --loader ts-node/esm.mjs --es-module-specifier-resolution node --test ./src/tests/*",
|
"test": "ts-node-esm ./scripts/run-test.ts all",
|
||||||
"test:coverage": "NODE_ENV=test c8 node --loader ts-node/esm.mjs --es-module-specifier-resolution node --experimental-test-coverage ./src/tests/*"
|
"test:coverage": "c8 ts-node-esm ./scripts/run-test.ts all"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/server": "^4.6.0",
|
"@apollo/server": "^4.6.0",
|
||||||
@@ -29,8 +32,10 @@
|
|||||||
"@nestjs/testing": "^9.4.0",
|
"@nestjs/testing": "^9.4.0",
|
||||||
"@types/lodash-es": "^4.14.194",
|
"@types/lodash-es": "^4.14.194",
|
||||||
"@types/node": "^18.15.11",
|
"@types/node": "^18.15.11",
|
||||||
|
"@types/supertest": "^2.0.12",
|
||||||
"c8": "^7.13.0",
|
"c8": "^7.13.0",
|
||||||
"nodemon": "^2.0.22",
|
"nodemon": "^2.0.22",
|
||||||
|
"supertest": "^6.3.3",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"typescript": "^5.0.4",
|
"typescript": "^5.0.4",
|
||||||
"vitest": "^0.30.1"
|
"vitest": "^0.30.1"
|
||||||
@@ -64,6 +69,7 @@
|
|||||||
],
|
],
|
||||||
"report-dir": ".coverage",
|
"report-dir": ".coverage",
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
"scripts",
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"**/*.spec.ts"
|
"**/*.spec.ts"
|
||||||
]
|
]
|
||||||
|
|||||||
24
apps/server/scripts/init-db.ts
Normal file
24
apps/server/scripts/init-db.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { randomUUID } from 'node:crypto';
|
||||||
|
|
||||||
|
import userA from '@affine-test/fixtures/userA.json' assert { type: 'json' };
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
await prisma.users.create({
|
||||||
|
data: {
|
||||||
|
id: randomUUID(),
|
||||||
|
...userA,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
|
.then(async () => {
|
||||||
|
await prisma.$disconnect();
|
||||||
|
})
|
||||||
|
.catch(async e => {
|
||||||
|
console.error(e);
|
||||||
|
await prisma.$disconnect();
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
56
apps/server/scripts/run-test.ts
Executable file
56
apps/server/scripts/run-test.ts
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/env ts-node-esm
|
||||||
|
import { resolve } from 'node:path';
|
||||||
|
|
||||||
|
import * as p from '@clack/prompts';
|
||||||
|
import { spawn } from 'child_process';
|
||||||
|
import { readdir } from 'fs/promises';
|
||||||
|
import * as process from 'process';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
import pkg from '../package.json' assert { type: 'json' };
|
||||||
|
const root = fileURLToPath(new URL('..', import.meta.url));
|
||||||
|
const testDir = resolve(root, 'src', 'tests');
|
||||||
|
const files = await readdir(testDir);
|
||||||
|
|
||||||
|
const args = [...pkg.nodemonConfig.nodeArgs, '--test'];
|
||||||
|
|
||||||
|
const env = {
|
||||||
|
PATH: process.env.PATH,
|
||||||
|
NODE_ENV: 'test',
|
||||||
|
DATABASE_URL: process.env.DATABASE_URL,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (process.argv[2] === 'all') {
|
||||||
|
const cp = spawn('node', [...args, resolve(testDir, '*')], {
|
||||||
|
cwd: root,
|
||||||
|
env,
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
cp.on('exit', code => {
|
||||||
|
process.exit(code ?? 0);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const result = await p.group({
|
||||||
|
file: () =>
|
||||||
|
p.select({
|
||||||
|
message: 'Select a file to run',
|
||||||
|
options: files.map(file => ({
|
||||||
|
label: file,
|
||||||
|
value: file as any,
|
||||||
|
})),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const target = resolve(testDir, result.file);
|
||||||
|
|
||||||
|
const cp = spawn('node', [...args, target], {
|
||||||
|
cwd: root,
|
||||||
|
env,
|
||||||
|
stdio: 'inherit',
|
||||||
|
shell: true,
|
||||||
|
});
|
||||||
|
cp.on('exit', code => {
|
||||||
|
process.exit(code ?? 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ export const getDefaultAFFiNEConfig: () => AFFiNEConfig = () => ({
|
|||||||
},
|
},
|
||||||
https: false,
|
https: false,
|
||||||
host: 'localhost',
|
host: 'localhost',
|
||||||
port: 3000,
|
port: 3010,
|
||||||
path: '',
|
path: '',
|
||||||
get origin() {
|
get origin() {
|
||||||
return this.dev
|
return this.dev
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { UsersModule } from './users';
|
||||||
import { WorkspaceModule } from './workspaces';
|
import { WorkspaceModule } from './workspaces';
|
||||||
|
|
||||||
export const BusinessModules = [WorkspaceModule];
|
export const BusinessModules = [WorkspaceModule, UsersModule];
|
||||||
|
|||||||
8
apps/server/src/modules/users/index.ts
Normal file
8
apps/server/src/modules/users/index.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
|
||||||
|
import { UserResolver } from './resolver';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
providers: [UserResolver],
|
||||||
|
})
|
||||||
|
export class UsersModule {}
|
||||||
37
apps/server/src/modules/users/resolver.ts
Normal file
37
apps/server/src/modules/users/resolver.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { Args, Field, ID, ObjectType, Query, Resolver } from '@nestjs/graphql';
|
||||||
|
import type { users } from '@prisma/client';
|
||||||
|
|
||||||
|
import { PrismaService } from '../../prisma/service';
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class User implements users {
|
||||||
|
@Field(() => ID)
|
||||||
|
id!: string;
|
||||||
|
@Field({ description: 'User name' })
|
||||||
|
name!: string;
|
||||||
|
@Field({ description: 'User email' })
|
||||||
|
email!: string;
|
||||||
|
@Field({ description: 'User password', nullable: true })
|
||||||
|
password!: string;
|
||||||
|
@Field({ description: 'User avatar url', nullable: true })
|
||||||
|
avatar_url!: string;
|
||||||
|
@Field({ description: 'User token nonce', nullable: true })
|
||||||
|
token_nonce!: number;
|
||||||
|
@Field({ description: 'User created date', nullable: true })
|
||||||
|
created_at!: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Resolver(() => User)
|
||||||
|
export class UserResolver {
|
||||||
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
|
@Query(() => User, {
|
||||||
|
name: 'user',
|
||||||
|
description: 'Get user by email',
|
||||||
|
})
|
||||||
|
async user(@Args('email') email: string) {
|
||||||
|
return this.prisma.users.findUnique({
|
||||||
|
where: { email },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
|
import { randomUUID } from 'node:crypto';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Args,
|
Args,
|
||||||
Field,
|
Field,
|
||||||
|
ID,
|
||||||
|
Mutation,
|
||||||
ObjectType,
|
ObjectType,
|
||||||
Query,
|
Query,
|
||||||
registerEnumType,
|
registerEnumType,
|
||||||
@@ -17,11 +21,20 @@ export enum WorkspaceType {
|
|||||||
|
|
||||||
registerEnumType(WorkspaceType, {
|
registerEnumType(WorkspaceType, {
|
||||||
name: 'WorkspaceType',
|
name: 'WorkspaceType',
|
||||||
|
description: 'Workspace type',
|
||||||
|
valuesMap: {
|
||||||
|
Normal: {
|
||||||
|
description: 'Normal workspace',
|
||||||
|
},
|
||||||
|
Private: {
|
||||||
|
description: 'Private workspace',
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ObjectType()
|
@ObjectType()
|
||||||
export class Workspace implements workspaces {
|
export class Workspace implements workspaces {
|
||||||
@Field()
|
@Field(() => ID)
|
||||||
id!: string;
|
id!: string;
|
||||||
@Field({ description: 'is Public workspace' })
|
@Field({ description: 'is Public workspace' })
|
||||||
public!: boolean;
|
public!: boolean;
|
||||||
@@ -53,4 +66,20 @@ export class WorkspaceResolver {
|
|||||||
where: { id },
|
where: { id },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create workspace
|
||||||
|
@Mutation(() => Workspace, {
|
||||||
|
name: 'createWorkspace',
|
||||||
|
description: 'Create workspace',
|
||||||
|
})
|
||||||
|
async createWorkspace() {
|
||||||
|
return this.prisma.workspaces.create({
|
||||||
|
data: {
|
||||||
|
id: randomUUID(),
|
||||||
|
type: WorkspaceType.Private,
|
||||||
|
public: false,
|
||||||
|
created_at: new Date(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
100
apps/server/src/tests/app.e2e.ts
Normal file
100
apps/server/src/tests/app.e2e.ts
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
import { equal, ok } from 'node:assert';
|
||||||
|
import { afterEach, beforeEach, describe, test } from 'node:test';
|
||||||
|
|
||||||
|
import { INestApplication } from '@nestjs/common';
|
||||||
|
import { Test } from '@nestjs/testing';
|
||||||
|
import request from 'supertest';
|
||||||
|
|
||||||
|
import { AppModule } from '../app';
|
||||||
|
import { getDefaultAFFiNEConfig } from '../config/default';
|
||||||
|
|
||||||
|
const gql = '/graphql';
|
||||||
|
|
||||||
|
globalThis.AFFiNE = getDefaultAFFiNEConfig();
|
||||||
|
|
||||||
|
// please run `ts-node-esm ./scripts/init-db.ts` before running this test
|
||||||
|
describe('AppModule', () => {
|
||||||
|
let app: INestApplication;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module = await Test.createTestingModule({
|
||||||
|
imports: [AppModule],
|
||||||
|
}).compile();
|
||||||
|
app = module.createNestApplication();
|
||||||
|
await app.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await app.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should init app', async () => {
|
||||||
|
ok(typeof app === 'object');
|
||||||
|
await request(app.getHttpServer())
|
||||||
|
.post(gql)
|
||||||
|
.send({
|
||||||
|
query: `
|
||||||
|
query {
|
||||||
|
error
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
.expect(400);
|
||||||
|
await request(app.getHttpServer())
|
||||||
|
.post(gql)
|
||||||
|
.send({
|
||||||
|
query: `
|
||||||
|
mutation {
|
||||||
|
createWorkspace {
|
||||||
|
id
|
||||||
|
type
|
||||||
|
public
|
||||||
|
created_at
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
.expect(200)
|
||||||
|
.expect(res => {
|
||||||
|
ok(
|
||||||
|
typeof res.body.data.createWorkspace === 'object',
|
||||||
|
'res.body.data.createWorkspace is not an object'
|
||||||
|
);
|
||||||
|
ok(
|
||||||
|
typeof res.body.data.createWorkspace.id === 'string',
|
||||||
|
'res.body.data.createWorkspace.id is not a string'
|
||||||
|
);
|
||||||
|
ok(
|
||||||
|
typeof res.body.data.createWorkspace.type === 'string',
|
||||||
|
'res.body.data.createWorkspace.type is not a string'
|
||||||
|
);
|
||||||
|
ok(
|
||||||
|
typeof res.body.data.createWorkspace.public === 'boolean',
|
||||||
|
'res.body.data.createWorkspace.public is not a boolean'
|
||||||
|
);
|
||||||
|
ok(
|
||||||
|
typeof res.body.data.createWorkspace.created_at === 'string',
|
||||||
|
'res.body.data.createWorkspace.created_at is not a string'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should find default user', async () => {
|
||||||
|
await request(app.getHttpServer())
|
||||||
|
.post(gql)
|
||||||
|
.send({
|
||||||
|
query: `
|
||||||
|
query {
|
||||||
|
user(email: "alex.yang@example.org") {
|
||||||
|
email
|
||||||
|
avatar_url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
.expect(200)
|
||||||
|
.expect(res => {
|
||||||
|
equal(res.body.data.user.email, 'alex.yang@example.org');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -15,6 +15,11 @@
|
|||||||
},
|
},
|
||||||
"include": ["src", "package.json"],
|
"include": ["src", "package.json"],
|
||||||
"exclude": ["dist", "node_modules"],
|
"exclude": ["dist", "node_modules"],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.node.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
"esm": true,
|
"esm": true,
|
||||||
"experimentalSpecifierResolution": "node"
|
"experimentalSpecifierResolution": "node"
|
||||||
|
|||||||
11
apps/server/tsconfig.node.json
Normal file
11
apps/server/tsconfig.node.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"moduleResolution": "Node",
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
},
|
||||||
|
"include": ["./scripts", "package.json"]
|
||||||
|
}
|
||||||
127
yarn.lock
127
yarn.lock
@@ -214,6 +214,7 @@ __metadata:
|
|||||||
"@prisma/client": ^4.12.0
|
"@prisma/client": ^4.12.0
|
||||||
"@types/lodash-es": ^4.14.194
|
"@types/lodash-es": ^4.14.194
|
||||||
"@types/node": ^18.15.11
|
"@types/node": ^18.15.11
|
||||||
|
"@types/supertest": ^2.0.12
|
||||||
c8: ^7.13.0
|
c8: ^7.13.0
|
||||||
dotenv: ^16.0.3
|
dotenv: ^16.0.3
|
||||||
graphql: ^16.6.0
|
graphql: ^16.6.0
|
||||||
@@ -223,9 +224,12 @@ __metadata:
|
|||||||
prisma: ^4.12.0
|
prisma: ^4.12.0
|
||||||
reflect-metadata: ^0.1.13
|
reflect-metadata: ^0.1.13
|
||||||
rxjs: ^7.8.0
|
rxjs: ^7.8.0
|
||||||
|
supertest: ^6.3.3
|
||||||
ts-node: ^10.9.1
|
ts-node: ^10.9.1
|
||||||
typescript: ^5.0.4
|
typescript: ^5.0.4
|
||||||
vitest: ^0.30.1
|
vitest: ^0.30.1
|
||||||
|
bin:
|
||||||
|
run-test: ./scripts/run-test.ts
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
@@ -7545,6 +7549,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/cookiejar@npm:*":
|
||||||
|
version: 2.1.2
|
||||||
|
resolution: "@types/cookiejar@npm:2.1.2"
|
||||||
|
checksum: f6e1903454007f86edd6c3520cbb4d553e1d4e17eaf1f77f6f75e3270f48cc828d74397a113a36942f5fe52f9fa71067bcfa738f53ad468fcca0bc52cb1cbd28
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/debug@npm:^4.1.7":
|
"@types/debug@npm:^4.1.7":
|
||||||
version: 4.1.7
|
version: 4.1.7
|
||||||
resolution: "@types/debug@npm:4.1.7"
|
resolution: "@types/debug@npm:4.1.7"
|
||||||
@@ -8046,6 +8057,25 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/superagent@npm:*":
|
||||||
|
version: 4.1.16
|
||||||
|
resolution: "@types/superagent@npm:4.1.16"
|
||||||
|
dependencies:
|
||||||
|
"@types/cookiejar": "*"
|
||||||
|
"@types/node": "*"
|
||||||
|
checksum: 187d1d32fdafd20b27e81728c46283160d3296ad904d56e0780769cf524105c94cc64bf5bafa170400cf5f1063d30826427de42ff0894d15b54df6d0fa31be4e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@types/supertest@npm:^2.0.12":
|
||||||
|
version: 2.0.12
|
||||||
|
resolution: "@types/supertest@npm:2.0.12"
|
||||||
|
dependencies:
|
||||||
|
"@types/superagent": "*"
|
||||||
|
checksum: f0e2b44f86bec2f708d6a3d0cb209055b487922040773049b0f8c6b557af52d4b5fa904e17dfaa4ce6e610172206bbec7b62420d158fa57b6ffc2de37b1730d3
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@types/testing-library__jest-dom@npm:^5.9.1":
|
"@types/testing-library__jest-dom@npm:^5.9.1":
|
||||||
version: 5.14.5
|
version: 5.14.5
|
||||||
resolution: "@types/testing-library__jest-dom@npm:5.14.5"
|
resolution: "@types/testing-library__jest-dom@npm:5.14.5"
|
||||||
@@ -9201,6 +9231,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"asap@npm:^2.0.0":
|
||||||
|
version: 2.0.6
|
||||||
|
resolution: "asap@npm:2.0.6"
|
||||||
|
checksum: b296c92c4b969e973260e47523207cd5769abd27c245a68c26dc7a0fe8053c55bb04360237cb51cab1df52be939da77150ace99ad331fb7fb13b3423ed73ff3d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"asar@npm:^3.0.0":
|
"asar@npm:^3.0.0":
|
||||||
version: 3.2.0
|
version: 3.2.0
|
||||||
resolution: "asar@npm:3.2.0"
|
resolution: "asar@npm:3.2.0"
|
||||||
@@ -10579,6 +10616,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"component-emitter@npm:^1.3.0":
|
||||||
|
version: 1.3.0
|
||||||
|
resolution: "component-emitter@npm:1.3.0"
|
||||||
|
checksum: b3c46de38ffd35c57d1c02488355be9f218e582aec72d72d1b8bbec95a3ac1b38c96cd6e03ff015577e68f550fbb361a3bfdbd9bb248be9390b7b3745691be6b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"compressible@npm:~2.0.16":
|
"compressible@npm:~2.0.16":
|
||||||
version: 2.0.18
|
version: 2.0.18
|
||||||
resolution: "compressible@npm:2.0.18"
|
resolution: "compressible@npm:2.0.18"
|
||||||
@@ -10767,6 +10811,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"cookiejar@npm:^2.1.4":
|
||||||
|
version: 2.1.4
|
||||||
|
resolution: "cookiejar@npm:2.1.4"
|
||||||
|
checksum: c4442111963077dc0e5672359956d6556a195d31cbb35b528356ce5f184922b99ac48245ac05ed86cf993f7df157c56da10ab3efdadfed79778a0d9b1b092d5b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"copy-anything@npm:^3.0.2":
|
"copy-anything@npm:^3.0.2":
|
||||||
version: 3.0.3
|
version: 3.0.3
|
||||||
resolution: "copy-anything@npm:3.0.3"
|
resolution: "copy-anything@npm:3.0.3"
|
||||||
@@ -11338,6 +11389,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"dezalgo@npm:^1.0.4":
|
||||||
|
version: 1.0.4
|
||||||
|
resolution: "dezalgo@npm:1.0.4"
|
||||||
|
dependencies:
|
||||||
|
asap: ^2.0.0
|
||||||
|
wrappy: 1
|
||||||
|
checksum: 895389c6aead740d2ab5da4d3466d20fa30f738010a4d3f4dcccc9fc645ca31c9d10b7e1804ae489b1eb02c7986f9f1f34ba132d409b043082a86d9a4e745624
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"diff-sequences@npm:^28.1.1":
|
"diff-sequences@npm:^28.1.1":
|
||||||
version: 28.1.1
|
version: 28.1.1
|
||||||
resolution: "diff-sequences@npm:28.1.1"
|
resolution: "diff-sequences@npm:28.1.1"
|
||||||
@@ -12902,7 +12963,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"fast-safe-stringify@npm:2.1.1":
|
"fast-safe-stringify@npm:2.1.1, fast-safe-stringify@npm:^2.1.1":
|
||||||
version: 2.1.1
|
version: 2.1.1
|
||||||
resolution: "fast-safe-stringify@npm:2.1.1"
|
resolution: "fast-safe-stringify@npm:2.1.1"
|
||||||
checksum: a851cbddc451745662f8f00ddb622d6766f9bd97642dabfd9a405fb0d646d69fc0b9a1243cbf67f5f18a39f40f6fa821737651ff1bceeba06c9992ca2dc5bd3d
|
checksum: a851cbddc451745662f8f00ddb622d6766f9bd97642dabfd9a405fb0d646d69fc0b9a1243cbf67f5f18a39f40f6fa821737651ff1bceeba06c9992ca2dc5bd3d
|
||||||
@@ -13330,6 +13391,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"formidable@npm:^2.1.2":
|
||||||
|
version: 2.1.2
|
||||||
|
resolution: "formidable@npm:2.1.2"
|
||||||
|
dependencies:
|
||||||
|
dezalgo: ^1.0.4
|
||||||
|
hexoid: ^1.0.0
|
||||||
|
once: ^1.4.0
|
||||||
|
qs: ^6.11.0
|
||||||
|
checksum: 81c8e5d89f5eb873e992893468f0de22c01678ca3d315db62be0560f9de1c77d4faefc9b1f4575098eb2263b3c81ba1024833a9fc3206297ddbac88a4f69b7a8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"forwarded@npm:0.2.0":
|
"forwarded@npm:0.2.0":
|
||||||
version: 0.2.0
|
version: 0.2.0
|
||||||
resolution: "forwarded@npm:0.2.0"
|
resolution: "forwarded@npm:0.2.0"
|
||||||
@@ -14275,6 +14348,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"hexoid@npm:^1.0.0":
|
||||||
|
version: 1.0.0
|
||||||
|
resolution: "hexoid@npm:1.0.0"
|
||||||
|
checksum: 27a148ca76a2358287f40445870116baaff4a0ed0acc99900bf167f0f708ffd82e044ff55e9949c71963852b580fc024146d3ac6d5d76b508b78d927fa48ae2d
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"highlight.js@npm:^10.4.1, highlight.js@npm:~10.7.0":
|
"highlight.js@npm:^10.4.1, highlight.js@npm:~10.7.0":
|
||||||
version: 10.7.3
|
version: 10.7.3
|
||||||
resolution: "highlight.js@npm:10.7.3"
|
resolution: "highlight.js@npm:10.7.3"
|
||||||
@@ -17229,7 +17309,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"methods@npm:~1.1.2":
|
"methods@npm:^1.1.2, methods@npm:~1.1.2":
|
||||||
version: 1.1.2
|
version: 1.1.2
|
||||||
resolution: "methods@npm:1.1.2"
|
resolution: "methods@npm:1.1.2"
|
||||||
checksum: 0917ff4041fa8e2f2fda5425a955fe16ca411591fbd123c0d722fcf02b73971ed6f764d85f0a6f547ce49ee0221ce2c19a5fa692157931cecb422984f1dcd13a
|
checksum: 0917ff4041fa8e2f2fda5425a955fe16ca411591fbd123c0d722fcf02b73971ed6f764d85f0a6f547ce49ee0221ce2c19a5fa692157931cecb422984f1dcd13a
|
||||||
@@ -17287,7 +17367,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"mime@npm:^2.0.3":
|
"mime@npm:2.6.0, mime@npm:^2.0.3":
|
||||||
version: 2.6.0
|
version: 2.6.0
|
||||||
resolution: "mime@npm:2.6.0"
|
resolution: "mime@npm:2.6.0"
|
||||||
bin:
|
bin:
|
||||||
@@ -19205,7 +19285,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"qs@npm:^6.10.0":
|
"qs@npm:^6.10.0, qs@npm:^6.11.0":
|
||||||
version: 6.11.1
|
version: 6.11.1
|
||||||
resolution: "qs@npm:6.11.1"
|
resolution: "qs@npm:6.11.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -20424,6 +20504,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"semver@npm:^7.3.8":
|
||||||
|
version: 7.5.0
|
||||||
|
resolution: "semver@npm:7.5.0"
|
||||||
|
dependencies:
|
||||||
|
lru-cache: ^6.0.0
|
||||||
|
bin:
|
||||||
|
semver: bin/semver.js
|
||||||
|
checksum: 2d266937756689a76f124ffb4c1ea3e1bbb2b263219f90ada8a11aebebe1280b13bb76cca2ca96bdee3dbc554cbc0b24752eb895b2a51577aa644427e9229f2b
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"semver@npm:~7.0.0":
|
"semver@npm:~7.0.0":
|
||||||
version: 7.0.0
|
version: 7.0.0
|
||||||
resolution: "semver@npm:7.0.0"
|
resolution: "semver@npm:7.0.0"
|
||||||
@@ -21387,6 +21478,24 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"superagent@npm:^8.0.5":
|
||||||
|
version: 8.0.9
|
||||||
|
resolution: "superagent@npm:8.0.9"
|
||||||
|
dependencies:
|
||||||
|
component-emitter: ^1.3.0
|
||||||
|
cookiejar: ^2.1.4
|
||||||
|
debug: ^4.3.4
|
||||||
|
fast-safe-stringify: ^2.1.1
|
||||||
|
form-data: ^4.0.0
|
||||||
|
formidable: ^2.1.2
|
||||||
|
methods: ^1.1.2
|
||||||
|
mime: 2.6.0
|
||||||
|
qs: ^6.11.0
|
||||||
|
semver: ^7.3.8
|
||||||
|
checksum: 5d00cdc7ceb5570663da80604965750e6b1b8d7d7442b7791e285c62bcd8d578a8ead0242a2426432b59a255fb42eb3a196d636157538a1392e7b6c5f1624810
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"superjson@npm:^1.12.2":
|
"superjson@npm:^1.12.2":
|
||||||
version: 1.12.2
|
version: 1.12.2
|
||||||
resolution: "superjson@npm:1.12.2"
|
resolution: "superjson@npm:1.12.2"
|
||||||
@@ -21396,6 +21505,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"supertest@npm:^6.3.3":
|
||||||
|
version: 6.3.3
|
||||||
|
resolution: "supertest@npm:6.3.3"
|
||||||
|
dependencies:
|
||||||
|
methods: ^1.1.2
|
||||||
|
superagent: ^8.0.5
|
||||||
|
checksum: 38239e517f7ba62b7a139a79c5c48d55f8d67b5ff4b6e51d5b07732ca8bbc4a28ffa1b10916fbb403dd013a054dbf028edc5850057d9a43aecbff439d494673e
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"supports-color@npm:^5.3.0, supports-color@npm:^5.5.0":
|
"supports-color@npm:^5.3.0, supports-color@npm:^5.5.0":
|
||||||
version: 5.5.0
|
version: 5.5.0
|
||||||
resolution: "supports-color@npm:5.5.0"
|
resolution: "supports-color@npm:5.5.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user