feat: add song crd and tests (#80)

Co-authored-by: Zoe Roux <zoe.roux@sdg.moe>
This commit is contained in:
Bluub
2022-09-26 23:21:55 +09:00
committed by GitHub
parent 014c64d52d
commit 38ddea057d
39 changed files with 548 additions and 169 deletions

7
back/.gitignore vendored
View File

@@ -32,4 +32,9 @@ lerna-debug.log*
!.vscode/settings.json !.vscode/settings.json
!.vscode/tasks.json !.vscode/tasks.json
!.vscode/launch.json !.vscode/launch.json
!.vscode/extensions.json !.vscode/extensions.json
# Robots tests
log.html
output.xml
report.html

View File

@@ -0,0 +1,61 @@
-- CreateTable
CREATE TABLE "User" (
"id" SERIAL NOT NULL,
"username" TEXT NOT NULL,
"password" TEXT NOT NULL,
"email" TEXT NOT NULL,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Song" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
"description" TEXT NOT NULL,
"artistId" INTEGER NOT NULL,
"albumId" INTEGER,
"genreId" INTEGER NOT NULL,
"difficulties" JSONB NOT NULL,
CONSTRAINT "Song_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Genre" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
CONSTRAINT "Genre_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Artist" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
CONSTRAINT "Artist_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "Album" (
"id" SERIAL NOT NULL,
"name" TEXT NOT NULL,
CONSTRAINT "Album_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
-- CreateIndex
CREATE UNIQUE INDEX "Song_name_key" ON "Song"("name");
-- AddForeignKey
ALTER TABLE "Song" ADD CONSTRAINT "Song_genreId_fkey" FOREIGN KEY ("genreId") REFERENCES "Genre"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Song" ADD CONSTRAINT "Song_artistId_fkey" FOREIGN KEY ("artistId") REFERENCES "Artist"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "Song" ADD CONSTRAINT "Song_albumId_fkey" FOREIGN KEY ("albumId") REFERENCES "Album"("id") ON DELETE SET NULL ON UPDATE CASCADE;

View File

@@ -0,0 +1,8 @@
-- DropForeignKey
ALTER TABLE "Song" DROP CONSTRAINT "Song_genreId_fkey";
-- AlterTable
ALTER TABLE "Song" ALTER COLUMN "genreId" DROP NOT NULL;
-- AddForeignKey
ALTER TABLE "Song" ADD CONSTRAINT "Song_genreId_fkey" FOREIGN KEY ("genreId") REFERENCES "Genre"("id") ON DELETE SET NULL ON UPDATE CASCADE;

View File

@@ -0,0 +1,8 @@
-- DropForeignKey
ALTER TABLE "Song" DROP CONSTRAINT "Song_artistId_fkey";
-- AlterTable
ALTER TABLE "Song" ALTER COLUMN "artistId" DROP NOT NULL;
-- AddForeignKey
ALTER TABLE "Song" ADD CONSTRAINT "Song_artistId_fkey" FOREIGN KEY ("artistId") REFERENCES "Artist"("id") ON DELETE SET NULL ON UPDATE CASCADE;

View File

@@ -0,0 +1,8 @@
/*
Warnings:
- You are about to drop the column `description` on the `Song` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "Song" DROP COLUMN "description";

View File

@@ -17,6 +17,39 @@ model User {
LessonHistory LessonHistory[] LessonHistory LessonHistory[]
} }
model Song {
id Int @id @default(autoincrement())
name String @unique
artistId Int?
artist Artist? @relation(fields: [artistId], references: [id])
albumId Int?
album Album? @relation(fields: [albumId], references: [id])
genreId Int?
genre Genre? @relation(fields: [genreId], references: [id])
difficulties Json
}
model Genre {
id Int @id @default(autoincrement())
name String
Song Song[]
}
model Artist {
id Int @id @default(autoincrement())
name String
Song Song[]
}
model Album {
id Int @id @default(autoincrement())
name String
Song Song[]
}
model Lesson { model Lesson {
id Int @id @default(autoincrement()) id Int @id @default(autoincrement())
name String name String

View File

@@ -3,20 +3,20 @@ import { AppController } from './app.controller';
import { AppService } from './app.service'; import { AppService } from './app.service';
describe('AppController', () => { describe('AppController', () => {
let appController: AppController; let appController: AppController;
beforeEach(async () => { beforeEach(async () => {
const app: TestingModule = await Test.createTestingModule({ const app: TestingModule = await Test.createTestingModule({
controllers: [AppController], controllers: [AppController],
providers: [AppService], providers: [AppService],
}).compile(); }).compile();
appController = app.get<AppController>(AppController); appController = app.get<AppController>(AppController);
}); });
describe('root', () => { describe('root', () => {
it('should return "Hello World!"', () => { it('should return "Hello World!"', () => {
expect(appController.getHello()).toBe('Hello World!'); expect(appController.getHello()).toBe('Hello World!');
}); });
}); });
}); });

View File

@@ -3,10 +3,10 @@ import { AppService } from './app.service';
@Controller() @Controller()
export class AppController { export class AppController {
constructor(private readonly appService: AppService) {} constructor(private readonly appService: AppService) {}
@Get() @Get()
getHello(): string { getHello(): string {
return this.appService.getHello(); return this.appService.getHello();
} }
} }

View File

@@ -5,10 +5,11 @@ import { PrismaService } from './prisma/prisma.service';
import { UsersModule } from './users/users.module'; import { UsersModule } from './users/users.module';
import { PrismaModule } from './prisma/prisma.module'; import { PrismaModule } from './prisma/prisma.module';
import { AuthModule } from './auth/auth.module'; import { AuthModule } from './auth/auth.module';
import { SongModule } from './song/song.module';
import { LessonModule } from './lesson/lesson.module'; import { LessonModule } from './lesson/lesson.module';
@Module({ @Module({
imports: [UsersModule, PrismaModule, AuthModule, LessonModule], imports: [UsersModule, PrismaModule, AuthModule, SongModule, LessonModule],
controllers: [AppController], controllers: [AppController],
providers: [AppService, PrismaService], providers: [AppService, PrismaService],
}) })

View File

@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
@Injectable() @Injectable()
export class AppService { export class AppService {
getHello(): string { getHello(): string {
return 'Hello World!'; return 'Hello World!';
} }
} }

View File

@@ -2,17 +2,17 @@ import { Test, TestingModule } from '@nestjs/testing';
import { AuthController } from './auth.controller'; import { AuthController } from './auth.controller';
describe('AuthController', () => { describe('AuthController', () => {
let controller: AuthController; let controller: AuthController;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
controllers: [AuthController], controllers: [AuthController],
}).compile(); }).compile();
controller = module.get<AuthController>(AuthController); controller = module.get<AuthController>(AuthController);
}); });
it('should be defined', () => { it('should be defined', () => {
expect(controller).toBeDefined(); expect(controller).toBeDefined();
}); });
}); });

View File

@@ -7,7 +7,7 @@ import {
Body, Body,
Delete, Delete,
BadRequestException, BadRequestException,
HttpCode, HttpCode,
} from '@nestjs/common'; } from '@nestjs/common';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
import { JwtAuthGuard } from './jwt-auth.guard'; import { JwtAuthGuard } from './jwt-auth.guard';
@@ -62,7 +62,7 @@ export class AuthController {
@UseGuards(JwtAuthGuard) @UseGuards(JwtAuthGuard)
@ApiBearerAuth() @ApiBearerAuth()
@ApiOkResponse({ description: 'Successfully deleted', type: User}) @ApiOkResponse({ description: 'Successfully deleted', type: User })
@ApiUnauthorizedResponse({ description: 'Invalid token' }) @ApiUnauthorizedResponse({ description: 'Invalid token' })
@Delete('me') @Delete('me')
deleteSelf(@Request() req: any): Promise<User> { deleteSelf(@Request() req: any): Promise<User> {

View File

@@ -10,16 +10,20 @@ import { ConfigService } from '@nestjs/config';
import { JwtStrategy } from './jwt.strategy'; import { JwtStrategy } from './jwt.strategy';
@Module({ @Module({
imports: [ConfigModule, UsersModule, PassportModule, imports: [
JwtModule.registerAsync({ ConfigModule,
imports: [ConfigModule], UsersModule,
useFactory: async (configService: ConfigService) => ({ PassportModule,
secret: configService.get('JWT_SECRET'), JwtModule.registerAsync({
signOptions: { expiresIn: '1h' }, imports: [ConfigModule],
}), useFactory: async (configService: ConfigService) => ({
inject: [ConfigService], secret: configService.get('JWT_SECRET'),
})], signOptions: { expiresIn: '1h' },
providers: [AuthService, LocalStrategy, JwtStrategy], }),
controllers: [AuthController] inject: [ConfigService],
}),
],
providers: [AuthService, LocalStrategy, JwtStrategy],
controllers: [AuthController],
}) })
export class AuthModule {} export class AuthModule {}

View File

@@ -2,17 +2,17 @@ import { Test, TestingModule } from '@nestjs/testing';
import { AuthService } from './auth.service'; import { AuthService } from './auth.service';
describe('AuthService', () => { describe('AuthService', () => {
let service: AuthService; let service: AuthService;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
providers: [AuthService], providers: [AuthService],
}).compile(); }).compile();
service = module.get<AuthService>(AuthService); service = module.get<AuthService>(AuthService);
}); });
it('should be defined', () => { it('should be defined', () => {
expect(service).toBeDefined(); expect(service).toBeDefined();
}); });
}); });

View File

@@ -1,12 +1,11 @@
import { Injectable } from "@nestjs/common"; import { Injectable } from '@nestjs/common';
import { ConfigService } from "@nestjs/config"; import { ConfigService } from '@nestjs/config';
@Injectable() @Injectable()
export class Constants { export class Constants {
constructor(private configService: ConfigService) {} constructor(private configService: ConfigService) {}
getSecret = () => { getSecret = () => {
return this.configService.get("JWT_SECRET"); return this.configService.get('JWT_SECRET');
} };
} }

View File

@@ -1,4 +1,4 @@
import { IsNotEmpty } from "class-validator"; import { IsNotEmpty } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
export class LoginDto { export class LoginDto {

View File

@@ -1,4 +1,4 @@
import { IsNotEmpty } from "class-validator"; import { IsNotEmpty } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger'; import { ApiProperty } from '@nestjs/swagger';
export class RegisterDto { export class RegisterDto {

View File

@@ -1,4 +1,4 @@
export default interface PayloadInterface { export default interface PayloadInterface {
username: string; username: string;
id: number; id: number;
} }

View File

@@ -2,4 +2,4 @@ import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';
@Injectable() @Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {} export class JwtAuthGuard extends AuthGuard('jwt') {}

View File

@@ -1,4 +1,3 @@
import { ExtractJwt, Strategy } from 'passport-jwt'; import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '@nestjs/passport'; import { PassportStrategy } from '@nestjs/passport';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
@@ -6,15 +5,15 @@ import { ConfigService } from '@nestjs/config';
@Injectable() @Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) { export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private configService: ConfigService) { constructor(private configService: ConfigService) {
super({ super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false, ignoreExpiration: false,
secretOrKey: configService.get('JWT_SECRET'), secretOrKey: configService.get('JWT_SECRET'),
}); });
} }
async validate(payload: any) { async validate(payload: any) {
return { id: payload.id, username: payload.username }; return { id: payload.id, username: payload.username };
} }
} }

View File

@@ -1,4 +1,3 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport'; import { AuthGuard } from '@nestjs/passport';

View File

@@ -2,17 +2,17 @@ import { Test, TestingModule } from '@nestjs/testing';
import { LessonController } from './lesson.controller'; import { LessonController } from './lesson.controller';
describe('LessonController', () => { describe('LessonController', () => {
let controller: LessonController; let controller: LessonController;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
controllers: [LessonController], controllers: [LessonController],
}).compile(); }).compile();
controller = module.get<LessonController>(LessonController); controller = module.get<LessonController>(LessonController);
}); });
it('should be defined', () => { it('should be defined', () => {
expect(controller).toBeDefined(); expect(controller).toBeDefined();
}); });
}); });

View File

@@ -2,17 +2,17 @@ import { Test, TestingModule } from '@nestjs/testing';
import { LessonService } from './lesson.service'; import { LessonService } from './lesson.service';
describe('LessonService', () => { describe('LessonService', () => {
let service: LessonService; let service: LessonService;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
providers: [LessonService], providers: [LessonService],
}).compile(); }).compile();
service = module.get<LessonService>(LessonService); service = module.get<LessonService>(LessonService);
}); });
it('should be defined', () => { it('should be defined', () => {
expect(service).toBeDefined(); expect(service).toBeDefined();
}); });
}); });

View File

@@ -4,18 +4,18 @@ import { PrismaService } from './prisma/prisma.service';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
async function bootstrap() { async function bootstrap() {
const app = await NestFactory.create(AppModule); const app = await NestFactory.create(AppModule);
const prismaService = app.get(PrismaService); const prismaService = app.get(PrismaService);
await prismaService.enableShutdownHooks(app); await prismaService.enableShutdownHooks(app);
const config = new DocumentBuilder() const config = new DocumentBuilder()
.setTitle('Chromacase') .setTitle('Chromacase')
.setDescription('The chromacase API') .setDescription('The chromacase API')
.setVersion('1.0') .setVersion('1.0')
.build(); .build();
const document = SwaggerModule.createDocument(app, config); const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document); SwaggerModule.setup('api', app, document);
await app.listen(3000); await app.listen(3000);
} }
bootstrap(); bootstrap();

View File

@@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { PrismaService } from './prisma.service'; import { PrismaService } from './prisma.service';
@Module({ @Module({
providers: [PrismaService], providers: [PrismaService],
exports: [PrismaService] exports: [PrismaService],
}) })
export class PrismaModule {} export class PrismaModule {}

View File

@@ -2,17 +2,17 @@ import { Test, TestingModule } from '@nestjs/testing';
import { PrismaService } from './prisma.service'; import { PrismaService } from './prisma.service';
describe('PrismaService', () => { describe('PrismaService', () => {
let service: PrismaService; let service: PrismaService;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
providers: [PrismaService], providers: [PrismaService],
}).compile(); }).compile();
service = module.get<PrismaService>(PrismaService); service = module.get<PrismaService>(PrismaService);
}); });
it('should be defined', () => { it('should be defined', () => {
expect(service).toBeDefined(); expect(service).toBeDefined();
}); });
}); });

View File

@@ -3,13 +3,13 @@ import { PrismaClient } from '@prisma/client';
@Injectable() @Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit { export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() { async onModuleInit() {
await this.$connect(); await this.$connect();
} }
async enableShutdownHooks(app: INestApplication) { async enableShutdownHooks(app: INestApplication) {
this.$on('beforeExit', async () => { this.$on('beforeExit', async () => {
await app.close(); await app.close();
}); });
} }
} }

View File

@@ -0,0 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty } from 'class-validator';
export class CreateSongDto {
@IsNotEmpty()
@ApiProperty()
name: string;
@IsNotEmpty()
@ApiProperty()
difficulties: object;
}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { SongController } from './song.controller';
describe('SongController', () => {
let controller: SongController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [SongController],
}).compile();
controller = module.get<SongController>(SongController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@@ -0,0 +1,65 @@
import {
BadRequestException,
Body,
Controller,
DefaultValuePipe,
Delete,
Get,
NotFoundException,
Param,
ParseIntPipe,
Post,
Query,
Req,
} from '@nestjs/common';
import { Plage } from 'src/models/plage';
import { CreateSongDto } from './dto/create-song.dto';
import { SongService } from './song.service';
import { Request } from 'express';
import { Prisma, Song } from '@prisma/client';
@Controller('song')
export class SongController {
constructor(private readonly songService: SongService) {}
@Post()
async create(@Body() createSongDto: CreateSongDto) {
return await this.songService.createSong(createSongDto);
}
@Delete(':id')
async remove(@Param('id', ParseIntPipe) id: number) {
return await this.songService.deleteSong({ id });
}
@Get()
async findAll(
@Req() req: Request,
@Query() filter: Prisma.SongWhereInput,
@Query('skip', new DefaultValuePipe(0), ParseIntPipe) skip: number,
@Query('take', new DefaultValuePipe(20), ParseIntPipe) take: number,
): Promise<Plage<Song>> {
try {
const ret = await this.songService.songs({
skip,
take,
where: {
...filter,
id: filter.id ? +filter.id : undefined,
},
});
return new Plage(ret, req);
} catch (e) {
console.log(e);
throw new BadRequestException(null, e?.toString());
}
}
@Get(':id')
async findOne(@Param('id', ParseIntPipe) id: number) {
let res = await this.songService.song({ id });
if (res === null) throw new NotFoundException('Song not found');
return res;
}
}

View File

@@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { SongService } from './song.service';
import { SongController } from './song.controller';
import { PrismaModule } from 'src/prisma/prisma.module';
@Module({
imports: [PrismaModule],
providers: [SongService],
controllers: [SongController],
})
export class SongModule {}

View File

@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { SongService } from './song.service';
describe('SongService', () => {
let service: SongService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [SongService],
}).compile();
service = module.get<SongService>(SongService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@@ -0,0 +1,45 @@
import { Injectable } from '@nestjs/common';
import { Prisma, Song } from '@prisma/client';
import { PrismaService } from 'src/prisma/prisma.service';
@Injectable()
export class SongService {
constructor(private prisma: PrismaService) {}
async createSong(data: Prisma.SongCreateInput): Promise<Song> {
return this.prisma.song.create({
data,
});
}
async song(
songWhereUniqueInput: Prisma.SongWhereUniqueInput,
): Promise<Song | null> {
return this.prisma.song.findUnique({
where: songWhereUniqueInput,
});
}
async songs(params: {
skip?: number;
take?: number;
cursor?: Prisma.SongWhereUniqueInput;
where?: Prisma.SongWhereInput;
orderBy?: Prisma.SongOrderByWithRelationInput;
}): Promise<Song[]> {
const { skip, take, cursor, where, orderBy } = params;
return this.prisma.song.findMany({
skip,
take,
cursor,
where,
orderBy,
});
}
async deleteSong(where: Prisma.SongWhereUniqueInput): Promise<Song> {
return this.prisma.song.delete({
where,
});
}
}

View File

@@ -3,18 +3,18 @@ import { UsersController } from './users.controller';
import { UsersService } from './users.service'; import { UsersService } from './users.service';
describe('UsersController', () => { describe('UsersController', () => {
let controller: UsersController; let controller: UsersController;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
controllers: [UsersController], controllers: [UsersController],
providers: [UsersService], providers: [UsersService],
}).compile(); }).compile();
controller = module.get<UsersController>(UsersController); controller = module.get<UsersController>(UsersController);
}); });
it('should be defined', () => { it('should be defined', () => {
expect(controller).toBeDefined(); expect(controller).toBeDefined();
}); });
}); });

View File

@@ -4,9 +4,9 @@ import { UsersController } from './users.controller';
import { PrismaModule } from 'src/prisma/prisma.module'; import { PrismaModule } from 'src/prisma/prisma.module';
@Module({ @Module({
imports: [PrismaModule], imports: [PrismaModule],
controllers: [UsersController], controllers: [UsersController],
providers: [UsersService], providers: [UsersService],
exports: [UsersService] exports: [UsersService],
}) })
export class UsersModule {} export class UsersModule {}

View File

@@ -2,17 +2,17 @@ import { Test, TestingModule } from '@nestjs/testing';
import { UsersService } from './users.service'; import { UsersService } from './users.service';
describe('UsersService', () => { describe('UsersService', () => {
let service: UsersService; let service: UsersService;
beforeEach(async () => { beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({ const module: TestingModule = await Test.createTestingModule({
providers: [UsersService], providers: [UsersService],
}).compile(); }).compile();
service = module.get<UsersService>(UsersService); service = module.get<UsersService>(UsersService);
}); });
it('should be defined', () => { it('should be defined', () => {
expect(service).toBeDefined(); expect(service).toBeDefined();
}); });
}); });

View File

@@ -4,21 +4,21 @@ import * as request from 'supertest';
import { AppModule } from './../src/app.module'; import { AppModule } from './../src/app.module';
describe('AppController (e2e)', () => { describe('AppController (e2e)', () => {
let app: INestApplication; let app: INestApplication;
beforeEach(async () => { beforeEach(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({ const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule], imports: [AppModule],
}).compile(); }).compile();
app = moduleFixture.createNestApplication(); app = moduleFixture.createNestApplication();
await app.init(); await app.init();
}); });
it('/ (GET)', () => { it('/ (GET)', () => {
return request(app.getHttpServer()) return request(app.getHttpServer())
.get('/') .get('/')
.expect(200) .expect(200)
.expect('Hello World!'); .expect('Hello World!');
}); });
}); });

1
back/test/robot/env/lib64 vendored Symbolic link
View File

@@ -0,0 +1 @@
lib

View File

@@ -0,0 +1,84 @@
*** Settings ***
Documentation Tests of the /song route.
... Ensures that the songs CRUD works corectly.
Resource ../rest.resource
*** Keywords ***
*** Test Cases ***
Create a song
[Documentation] Create a song
&{res}= POST /song {"name": "Mama mia", "difficulties": {}}
Output
Integer response status 201
[Teardown] DELETE /song/${res.body.id}
Find a song
[Documentation] Create a song and find it
&{res}= POST /song {"name": "Mama mia", "difficulties": {}}
Output
Integer response status 201
&{get}= GET /song/${res.body.id}
Output
Integer response status 200
Should Be Equal ${res.body} ${get.body}
[Teardown] DELETE /song/${res.body.id}
Find a song non existant
[Documentation] Find non existant song
&{get}= GET /song/9999
Integer response status 404
Find multiples songs
[Documentation] Create two songs and find them
&{res}= POST /song {"name": "Mama mia", "difficulties": {}}
Output
Integer response status 201
&{res2}= POST /song {"name": "Here we go again", "difficulties": {}}
Output
Integer response status 201
&{get}= GET /song
Output
Integer response status 200
Should Contain ${get.body.data} ${res.body}
Should Contain ${get.body.data} ${res2.body}
[Teardown] Run Keywords DELETE /song/${res.body.id}
... AND DELETE /song/${res2.body.id}
Find multiples songs filtered
[Documentation] Create two songs and find them
&{res}= POST /song {"name": "Mamamia", "difficulties": {}}
Output
Integer response status 201
&{res2}= POST /song {"name": "Here we go again", "difficulties": {}}
Output
Integer response status 201
&{get}= GET /song?name=Mamamia
Output
Integer response status 200
Should Contain ${get.body.data} ${res.body}
Should Not Contain ${get.body.data} ${res2.body}
[Teardown] Run Keywords DELETE /song/${res.body.id}
... AND DELETE /song/${res2.body.id}
Find multiples songs filtered by type
[Documentation] Create two songs and find them
&{res}= POST /song {"name": "Mamamia", "difficulties": {}}
Output
Integer response status 201
&{res2}= POST /song {"name": "Here we go again", "difficulties": {}}
Output
Integer response status 201
&{get}= GET /song?id=${res.body.id}
Output
Integer response status 200
Should Contain ${get.body.data} ${res.body}
Should Not Contain ${get.body.data} ${res2.body}
[Teardown] Run Keywords DELETE /song/${res.body.id}
... AND DELETE /song/${res2.body.id}