diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c9265703..5ce91257 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,10 +19,17 @@ jobs: - run: npm --prefix users/userservice ci - run: npm --prefix gatewayservice ci - run: npm --prefix webapp ci + - run: npm --prefix game/gameservice ci + - run: npm --prefix game/groupservice ci + - run: npm --prefix game/qgservice ci + - run: npm --prefix multiplayerservice ci - run: npm --prefix users/authservice test -- --coverage - run: npm --prefix users/userservice test -- --coverage - run: npm --prefix gatewayservice test -- --coverage - run: npm --prefix webapp test -- --coverage + - run: npm --prefix game/gameservice test -- --coverage + - run: npm --prefix game/groupservice test -- --coverage + - run: npm --prefix game/qgservice test -- --coverage - name: Analyze with SonarCloud uses: sonarsource/sonarcloud-github-action@master env: diff --git a/docs/src/14_usability_test.adoc b/docs/src/14_usability_test.adoc new file mode 100644 index 00000000..0e3bad08 --- /dev/null +++ b/docs/src/14_usability_test.adoc @@ -0,0 +1,21 @@ +ifndef::imagesdir[:imagesdir: ../images] + +[[section-load_test]] +== Anex II: Usability test +The tests were carried out with a sample of 10 users with different backgrounds. Being 3 of them students from Software Engineering. + +=== Effectiveness + +* 100% of users completed the tasks on the first try. +* 80% of users did not need extra help to navigate the web. + +=== Efficiency + +* All users did each task in less than 10 seconds, including answering the questions of the game. +* 80% of users did not need extra help to navigate the web. + +=== Satisfaction + +* 1 user though the questions should be harder. +* 2 users found a bug that is now fixed: when you play, close session, login again and go to profile, the last questions do not appear. +* 6 users tried to login with google, but it only works with test users. \ No newline at end of file diff --git a/game/gameservice/GameController.js b/game/gameservice/GameController.js index dfce9b6a..55d77926 100644 --- a/game/gameservice/GameController.js +++ b/game/gameservice/GameController.js @@ -1,6 +1,5 @@ let Game = require('./game-model'); const { createGame } = require('./queries/CreateGame'); -const mongoose = require('mongoose'); let GameController = { /* HACER EN USER - GET LAST GAME BY USER @@ -11,10 +10,9 @@ let GameController = { },*/ create: async (req, res) => { try{ - const { questions, players } = req.body; - console.log(questions, players) - const game = await createGame(questions, players); - res.json(game); + const { questions, players } = req.body; + const game = await createGame(questions, players); + res.json(game); } catch(error){ res.status(500).json({ message: error.message }); } diff --git a/game/gameservice/game-service.test.js b/game/gameservice/game-service.test.js index 68cbfdbd..aab8b42c 100644 --- a/game/gameservice/game-service.test.js +++ b/game/gameservice/game-service.test.js @@ -1,5 +1,7 @@ const request = require('supertest'); const { MongoMemoryServer } = require('mongodb-memory-server'); +const Game = require('./game-model'); +const { createGame } = require('./queries/CreateGame'); let mongoServer; let app; @@ -18,23 +20,99 @@ afterAll(async () => { describe('Game service', () => { - // mock data - const questions = [{ _id: 'question1_id' }, { _id: 'question2_id' }]; - const users = [{ _id: 'user1_id' }, { _id: 'user2_id' }]; - it('should create a game and update user lastGame field', async () => { - const response = await request(app).post('/creategame').send({questions,users}); + + const questions = [{ uuid: 'question1_id' }, { uuid: 'question2_id' }]; + const players = [{ uuid: 'user1_id' }, { uuid: 'user2_id' }]; + + const response = await request(app).post('/creategame').send({questions,players}); expect(response.status).toBe(200); expect(response.body).toHaveProperty('_id'); - const gameId = response.body._id; - const gameFromDB = await mongoose.model('Game').findById(gameId); - const user1FromDB = await mongoose.model('User').findById('user1_id'); - const user2FromDB = await mongoose.model('User').findById('user2_id'); + const gameUUId = response.body.uuid; + + const gameInDB = await Game.findOne({ uuid: gameUUId }); + // expect the game to exist + expect(gameInDB).toBeTruthy(); + + // Expect the game to have the correct questions + expect(gameInDB.questions.length).toBe(questions.length); + for (let i = 0; i < questions.length; i++) { + expect(gameInDB.questions[i]).toBe(questions[i].uuid); + } + + // Expect the game to have the correct players + expect(gameInDB.players.length).toBe(players.length); + for (let i = 0; i < players.length; i++) { + expect(gameInDB.players[i]).toBe(players[i].uuid); + } - // Assertions for the database state - expect(gameFromDB).toBeTruthy(); - expect(user1FromDB.lastGame.toString()).toBe(gameId); - expect(user2FromDB.lastGame.toString()).toBe(gameId); }); + + it('should return status 500 when sending invalid data', async () => { + const invalidData = {}; // Sending empty object as invalid data + + const response = await request(app).post('/creategame').send(invalidData); + + expect(response.status).toBe(500); + expect(response.body).toHaveProperty('message'); +}); + +it('should delete a game', async () => { + // Create a game to be deleted + const newGame = await Game.create({ uuid: 'game_to_delete_id' }); + + // Send request to delete the game + const response = await request(app).delete(`/deletegame/${newGame.uuid}`); + + // Expect response status to be 200 + expect(response.status).toBe(200); + expect(response.body).toHaveProperty('message', 'Game deleted'); + + // Verify that the game is deleted from the database + const deletedGame = await Game.findOne({ uuid: newGame.uuid }); + expect(deletedGame).toBeNull(); // Expect deletedGame to be null, indicating it doesn't exist in the database +}); + +it('should return a game by its ID', async () => { + // Create a game to retrieve + const newGame = await Game.create({ uuid: 'game_to_retrieve_id' }); + + // Send request to retrieve the game by its ID + const response = await request(app).get(`/getgame/${newGame.uuid}`); + + // Expect response status to be 200 + expect(response.status).toBe(200); + expect(response.body).toHaveLength(1); // Assuming the endpoint always returns an array of games + expect(response.body[0]).toHaveProperty('uuid', newGame.uuid); // Assuming the game object contains a UUID property +}); + +it('should return a JSON response with "hi" message', async () => { + const response = await request(app).get('/'); + + // Expect response status to be 200 + expect(response.status).toBe(200); + + // Expect response body to contain the expected JSON object + expect(response.body).toEqual({ hi: 'game service' }); +}); + +it('should throw an error if no players are found', async () => { + // Prepare test data with empty players array + const questions = [{ uuid: 'question1_id' }, { uuid: 'question2_id' }]; + const players = []; + + // Expect createGame function to throw an error when called with empty players array + await expect(createGame(questions, players)).rejects.toThrow('No players found'); +}); + +it('should throw an error if player UUID is null or undefined', async () => { + // Prepare test data with null or undefined player UUID + const questions = [{ uuid: 'question1_id' }, { uuid: 'question2_id' }]; + const players = [{ uuid: null }, { uuid: undefined }]; + + // Expect createGame function to throw an error when called with player UUID null or undefined + await expect(createGame(questions, players)).rejects.toThrow('No players found'); +}); + }); \ No newline at end of file diff --git a/game/gameservice/gameservice.js b/game/gameservice/gameservice.js index 9f365232..beb5f97b 100644 --- a/game/gameservice/gameservice.js +++ b/game/gameservice/gameservice.js @@ -1,15 +1,13 @@ // gameservice.js const express = require('express'); -const axios = require('axios'); const mongoose = require('mongoose'); -const { createGame } = require('./queries/CreateGame'); +const bodyParser = require('body-parser'); const GameController = require('./GameController'); const app = express(); const port = 8004; -// app.use(bodyParser.json()); -app.use(express.json()); +app.use(bodyParser.json()); const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/userdb'; mongoose.connect(mongoUri); @@ -29,4 +27,8 @@ const server = app.listen(port, () => { console.log(`Question generator Service listening at http://localhost:${port}`); }); +server.on('close', () => { + mongoose.connection.close(); +}); + module.exports = server; diff --git a/game/gameservice/queries/CreateGame.js b/game/gameservice/queries/CreateGame.js index b1712e93..03daca65 100644 --- a/game/gameservice/queries/CreateGame.js +++ b/game/gameservice/queries/CreateGame.js @@ -5,11 +5,10 @@ const uuid = require('uuid') async function createGame(questions, players) { try { // Create a new Game instance - console.log(players) - if(players.length == 0){ + if(players.length === 0){ throw new Error('No players found') } - if(players[0].uuid == null || players[0].uuid == undefined){ + if(players[0].uuid === null || players[0].uuid === undefined){ throw new Error('No players found') } const game = new Game({ diff --git a/game/groupservice/GroupController.js b/game/groupservice/GroupController.js index 3f41e600..ec9ee715 100644 --- a/game/groupservice/GroupController.js +++ b/game/groupservice/GroupController.js @@ -35,20 +35,17 @@ let GroupController = { res.json(response); }catch(error){ - console.log(error) - res.status(400).json({error: error.message}) + res.status(500).json({error: error.message}) } }, leaveGroup: async (req,res) => { try{ - console.log(req.body) requiredFields = ['expelledUUID','groupName', 'adminUUID'] validateRequiredFields(req, requiredFields); const group = await getGroupByName(req.body.groupName); - console.log(req.body.adminUUID +" - "+ req.body.expelledUUID) + if(req.body.adminUUID != group.admin && req.body.adminUUID != req.body.expelledUUID){ - console.log("entra en la condicion") res.json({ message: 'User is unable to perform this operation' }); return; } @@ -76,12 +73,11 @@ let GroupController = { createGroup: async (req,res) =>{ try{ - requiredFields =['groupName','creatorUUID','description','isPublic'] + let requiredFields =['groupName','creatorUUID','description','isPublic'] validateRequiredFields(req,requiredFields); - let newGroup; - if(req.body.isPublic){ + if(req.body.isPublic){ newGroup = new Group({ admin: req.body.creatorUUID, members: [req.body.creatorUUID], @@ -92,25 +88,22 @@ let GroupController = { groupName: req.body.groupName, uuid: uuid.v4(), }) - await newGroup.save(); - - } else { - const joinCode = generateJoinCode(); - - newGroup = new Group({ - groupName: req.body.groupName, - admin: req.body.creatorUUID, - members: [req.body.creatorUUID], - maxNumUsers: maxNumUsers, - description: req.body.description, - isPublic: false, - joinCode: joinCode, - creationDate: Date(), - uuid: uuid.v4(), - }); - await newGroup.save(); - } - res.json(newGroup); + } else { + const joinCode = generateJoinCode(); + newGroup = new Group({ + groupName: req.body.groupName, + admin: req.body.creatorUUID, + members: [req.body.creatorUUID], + maxNumUsers: maxNumUsers, + description: req.body.description, + isPublic: false, + joinCode: joinCode, + creationDate: Date(), + uuid: uuid.v4(), + }); + } + const savedGroup = await newGroup.save() + res.json(savedGroup); } catch(error){ res.status(500).json({error: error.message}) @@ -144,9 +137,8 @@ let GroupController = { async function getGroupByName(name) { try { const group = await Group.findOne({ groupName: name }); - if (!group) { - throw new Error('This group does not exist'); + throw new Error('This group does not exist'); } return group; @@ -164,4 +156,4 @@ function validateRequiredFields(req, requiredFields) { } } -module.exports = GroupController; \ No newline at end of file +module.exports = {GroupController, getGroupByName}; \ No newline at end of file diff --git a/game/groupservice/group-service.js b/game/groupservice/group-service.js index ddf87c7b..402e3299 100644 --- a/game/groupservice/group-service.js +++ b/game/groupservice/group-service.js @@ -1,6 +1,6 @@ const express = require('express'); const mongoose = require('mongoose'); -const GroupController = require('./GroupController'); +const {GroupController} = require('./GroupController'); const app = express(); const port = 8005; diff --git a/game/groupservice/group-service.test.js b/game/groupservice/group-service.test.js index 81adad56..c22560e0 100644 --- a/game/groupservice/group-service.test.js +++ b/game/groupservice/group-service.test.js @@ -1,18 +1,23 @@ const request = require('supertest'); const { MongoMemoryServer } = require('mongodb-memory-server'); -const mongoose = require('mongoose'); -const app = require('./group-service'); // Replace 'your-app-file' with the filename where your app is defined const Group = require('./group-model'); -const uuid = require('uuid'); +const { getGroupByName } = require('./GroupController') let mongoServer; +let app; describe('Group Service API Tests', () => { beforeAll(async () => { mongoServer = await MongoMemoryServer.create(); const mongoUri = mongoServer.getUri(); process.env.MONGODB_URI = mongoUri; - }); + app = require('./group-service'); + }); + + afterEach(async () => { + jest.restoreAllMocks(); + await Group.deleteMany({}); + }); afterAll(async () => { app.close(); @@ -25,152 +30,331 @@ describe('Group Service API Tests', () => { expect(response.body.message).toBe('Welcome to group service module'); }); - it('POST /joinGroup should join a user to a group with valid data', async () => { - const uuidGroup = uuid.v4(); - const admin = uuid.v4(); - const group = new Group({ - groupName: 'Test Group', - members: [admin], - isPublic: true, - admin: admin, - uuid: uuidGroup, - joinCode: '123456', - description: 'Test group', - creationDate: Date(), - maxNumUsers: 10, - }); - await group.save(); + it('should create a group when all required fields are provided public group', async () => { + // Prepare request body with all required fields + const requestBody = { + groupName: 'Test Group1', + creatorUUID: 'creator_id1', + description: 'Test description', + isPublic: true + }; - const newUserUUID = uuid.v4(); - const joinData = { - uuid: newUserUUID, - groupName: 'Test Group', + const response = await request(app).post('/createGroup').send(requestBody); + expect(response.status).toBe(200); + + // Expect response body to contain the created group + expect(response.body).toHaveProperty('groupName', requestBody.groupName); + expect(response.body).toHaveProperty('admin', requestBody.creatorUUID); + expect(response.body).toHaveProperty('description', requestBody.description); + expect(response.body).toHaveProperty('isPublic', requestBody.isPublic); + expect(response.body).toHaveProperty('uuid'); + }); + + it('should create a group when all required fields are provided private group', async () => { + // Prepare request body with all required fields + const requestBody = { + groupName: 'Test Group2', + creatorUUID: 'creator_id2', + description: 'Test description', + isPublic: false }; - const res = await request(app) - .post('/joinGroup') - .send(joinData) - .expect(200); + const response = await request(app).post('/createGroup').send(requestBody); + expect(response.status).toBe(200); - await Group.findOneAndDelete({uuid: uuidGroup}); - expect(res.body.members).toContain(newUserUUID); + // Expect response body to contain the created group + expect(response.body).toHaveProperty('groupName', requestBody.groupName); + expect(response.body).toHaveProperty('admin', requestBody.creatorUUID); + expect(response.body).toHaveProperty('description', requestBody.description); + expect(response.body).toHaveProperty('isPublic', requestBody.isPublic); + expect(response.body).toHaveProperty('uuid'); + expect(response.body).toHaveProperty('joinCode'); +}); + + it('should return status 500 when one or more required fields are missing', async () => { + const requestBody = { + groupName: 'Test Group', + creatorUUID: 'creator_id', + }; + + const response = await request(app).post('/createGroup').send(requestBody); + expect(response.status).toBe(500); + expect(response.body).toHaveProperty('error', expect.stringContaining('Missing required field')); }); - it('POST /joinGroup should return an error if the user is already in the group', async () => { - const uuidGroup = uuid.v4(); - const admin = uuid.v4(); - const testUser = uuid.v4(); - const group = new Group({ - groupName: 'Test Group2', - members: [admin, testUser], - isPublic: true, - admin: admin, - uuid: uuidGroup, - joinCode: '123456', - description: 'Test group2', - creationDate: Date(), - maxNumUsers: 10, + it('should successfully add user to the group', async () => { + const group = await Group.create({ + uuid: 'successfully_added_group_uuid', + groupName: 'Succesfully added Test Group', + admin: 'admin_id', + members: ['admin_id'], + maxNumUsers: 5, + isPublic: true, }); - await group.save(); - const joinData = { - uuid: testUser, - groupName: 'Test Group2', + const requestBody = { + uuid: 'user_to_join_uuid', + groupName: 'Succesfully added Test Group', }; - const res = await request(app) - .post('/joinGroup') - .send(joinData) - .expect(200); - - await Group.findOneAndDelete({uuid: uuidGroup}); - expect(res.body.message).toBe('User is already in this group'); - }); + const response = await request(app).post('/joingroup').send(requestBody); + expect(response.status).toBe(200); + expect(response.body).toHaveProperty('members'); + expect(response.body.members).toContain(requestBody.uuid); +}); - it('POST /leaveGroup should remove a user from the group with valid data', async () => { - const uuidGroup = uuid.v4(); - const admin = uuid.v4(); - const testUser = uuid.v4(); - const group = new Group({ - groupName: 'Test Group2', - members: [admin, testUser], - isPublic: true, - admin: admin, - uuid: uuidGroup, - joinCode: '123456', - description: 'Test group2', - creationDate: Date(), - maxNumUsers: 10, +it('should return message when user is already in the group', async () => { + await Group.create({ + uuid: 'user_already_in_group_uuid', + groupName: 'User already in group Test Group', + members: ['userInGroup_id', 'admin_id'], + admin: 'admin_id', + maxNumUsers: 5, + isPublic: true }); - await group.save(); - const leaveData = { - expelledUUID: testUser, - groupName: 'Test Group2', - adminUUID: admin + const requestBody = { + uuid: 'userInGroup_id', + groupName: 'User already in group Test Group' }; - const res = await request(app) - .post('/leaveGroup') - .send(leaveData) - .expect(200); + const response = await request(app).post('/joingroup').send(requestBody); + expect(response.status).toBe(200); + expect(response.body).toEqual({ message: 'User is already in this group' }); +}); + +it('should return message when group is full', async () => { + await Group.create({ + uuid: 'full_group_uuid', + groupName: 'Full group Test Group', + members: Array(30).fill("member_uuid"), + admin: 'admin_id2', + maxNumUsers: 30, + isPublic: true, + }); + + const requestBody = { + uuid: 'userToJoinFullGroup_id', + groupName: 'Full group Test Group' + }; - await Group.findOneAndDelete({uuid: uuidGroup}); - expect(res.body.members).not.toContain(testUser); + const response = await request(app).post('/joingroup').send(requestBody); + expect(response.status).toBe(200); + expect(response.body).toEqual({ message: 'This group is full' }); +}); + +it('should return message when join code is incorrect for a private group', async () => { + await Group.create({ + uuid: 'incorrect_join_code_group_uuid', + groupName: 'Test Group Incorrect Join Code', + members: ['admin_id3'], + maxNumUsers: 5, + admin: 'admin_id', + isPublic: false, + joinCode: 'correct_join_code' }); - it('POST /leaveGroup should assign a new admin if the expelled user was the admin', async () => { - const uuidGroup = uuid.v4(); - const admin = uuid.v4(); - const testUser = uuid.v4(); - const group = new Group({ - groupName: 'Test Group2', - members: [admin, testUser], + const requestBody = { + uuid: 'user_id', + groupName: 'Test Group Incorrect Join Code', + joinCode: 'incorrect_join_code' + }; + + const response = await request(app).post('/joingroup').send(requestBody); + + expect(response.status).toBe(200); + expect(response.body).toEqual({ message: 'Invalid join code' }); +}); +it('should return status 500 and error message when an error occurs', async () => { + const mockError = new Error('Internal server error'); + jest.spyOn(Group, 'findOne').mockRejectedValue(mockError); + const requestBody = { + uuid: 'user_id', + groupName: 'Test Group Failure' + }; + const response = await request(app).post('/joingroup').send(requestBody); + + expect(response.status).toBe(500); + expect(response.body).toEqual({ error: 'Internal server error' }); +}); + +it('should successfully remove user from the group and remove the group when nobody is left', async () => { + await Group.create({ + uuid: 'successfully_remove_member_group_and_remove_group_uuid', + groupName: 'Succesfully remove member, and group Test Group', + members: ['admin_id'], + admin: 'admin_id', isPublic: true, - admin: admin, - uuid: uuidGroup, - joinCode: '123456', - description: 'Test group2', - creationDate: Date(), - maxNumUsers: 10, - }); - await group.save(); + maxNumUsers: 5 + }); - const leaveData = { - expelledUUID: admin, - groupName: 'Test Group2', - adminUUID: admin - }; + const requestBody = { + expelledUUID: 'admin_id', + groupName: 'Succesfully remove member, and group Test Group', + adminUUID: 'admin_id' + }; - const res = await request(app) - .post('/leaveGroup') - .send(leaveData) - .expect(200); + const response = await request(app).post('/leaveGroup').send(requestBody); + expect(response.status).toBe(200); + expect(response.body).toHaveProperty('message'); + expect(response.body.message).toEqual('Group deleted'); +}); - await Group.findOneAndDelete({uuid: uuidGroup}); - expect(res.body.members).not.toContain(admin); - expect(res.body.admin).toBe(testUser); +it('should successfully remove user from the group and remove the group when nobody is left', async () => { + const group = await Group.create({ + uuid: 'successfully_remove_member_group_and_remove_group_uuid', + groupName: 'Succesfully remove member, and change admin group Test Group', + members: ['admin_id','user_id'], + admin: 'admin_id', + isPublic: true, + maxNumUsers: 5 }); - it('POST /createGroup should create a public group with valid data', async () => { - const admin = uuid.v4(); - const groupData = { - groupName: 'Public Test Group', - creatorUUID: admin, - description: 'This is a public test group', - isPublic: true - }; + const requestBody = { + expelledUUID: 'admin_id', + groupName: 'Succesfully remove member, and change admin group Test Group', + adminUUID: 'admin_id' + }; + + const response = await request(app).post('/leaveGroup').send(requestBody); + expect(response.status).toBe(200); + expect(response.body).toHaveProperty('members'); + expect(response.body.members).not.toContain(requestBody.expelledUUID); + expect(response.body.admin).toBe('user_id'); +}); - const res = await request(app) - .post('/createGroup') - .send(groupData) - .expect(200); - - await Group.findOneAndDelete({uuid: res.body.uuid}); // Delete the group after testing - expect(res.body.groupName).toBe(groupData.groupName); - expect(res.body.admin).toBe(groupData.creatorUUID); - expect(res.body.members).toContain(groupData.creatorUUID); - expect(res.body.isPublic).toBe(true); - +it('should return message when user is unable to perform the operation leaveGroup', async () => { + const group = await Group.create({ + uuid: 'group_uuid', + groupName: 'Test Group', + members: ['user_id'], + admin: 'different_admin_id', + isPublic: true, + maxNumUsers: 5 }); -}); \ No newline at end of file + const requestBody = { + expelledUUID: 'user_id', + groupName: 'Test Group', + adminUUID: 'admin_id' + }; + + const response = await request(app).post('/leavegroup').send(requestBody); + expect(response.status).toBe(200); + expect(response.body).toEqual({ message: 'User is unable to perform this operation' }); +}); + +it('should return status 500 and error message when an error occurs', async () => { + const mockError = new Error('Internal server error'); + jest.spyOn(Group, 'findOne').mockRejectedValue(mockError); + + const requestBody = { + expelledUUID: 'user_id', + groupName: 'Test Group', + adminUUID: 'admin_id' + }; + + const response = await request(app).post('/leavegroup').send(requestBody); + expect(response.status).toBe(500); + expect(response.body).toEqual({ error: 'Internal server error' }); +}); + +it('should return the group when it exists', async () => { + const group = { + uuid: 'group_uuid', + groupName: 'Test Group', + members: ['user_id'], + admin: 'different_admin_id', + isPublic: true, + maxNumUsers: 5 + }; + + const savedGroup = await Group.create(group); + const expectedResponse = { + _id: savedGroup._id.toString(), + __v: savedGroup.__v, + uuid: savedGroup.uuid, + groupName: savedGroup.groupName, + members: savedGroup.members, + admin: savedGroup.admin, + isPublic: savedGroup.isPublic, + maxNumUsers: savedGroup.maxNumUsers, + creationDate: savedGroup.creationDate.toISOString(), + }; + + const response = await request(app).get(`/getGroup/${group.uuid}`); + expect(response.status).toBe(200); + expect(response.body).toEqual(expectedResponse); +}); + +it('should return status 404 and error message when group is not found', async () => { + const response = await request(app).get('/getGroup/non_existent_uuid'); + expect(response.status).toBe(404); + expect(response.body).toEqual({ error: 'Group not found' }); +}); + +it('should return all groups', async () => { + // Create some groups in the database + const groups = [ + { + uuid: 'group_uuid1', + groupName: 'Test Group1', + members: ['user_id1'], + admin: 'admin_id1', + isPublic: true, + maxNumUsers: 5 + }, + { + uuid: 'group_uuid2', + groupName: 'Test Group2', + members: ['user_id2'], + admin: 'admin_id2', + isPublic: true, + maxNumUsers: 5 + }, + { + uuid: 'group_uuid3', + groupName: 'Test Group3', + members: ['user_id3'], + admin: 'admin_id3', + isPublic: true, + maxNumUsers: 5 + } + ]; + await Group.create(groups); + + const response = await request(app).get('/getGroups'); + expect(response.status).toBe(200); + expect(response.body).toBeInstanceOf(Array); + expect(response.body.length).toBe(3); + + // Assert that the names of the groups in the response match the expected names + expect(response.body.map(group => group.groupName)).toEqual( + expect.arrayContaining(groups.map(group => group.groupName)) + ); +}); + +it('should return status 500 and error message when an error occurs', async () => { + const mockError = new Error('Internal server error'); + jest.spyOn(Group, 'find').mockRejectedValue(mockError); + const response = await request(app).get('/getGroups'); + expect(response.status).toBe(500); + expect(response.body).toEqual({ error: 'Internal server error' }); +}); + +it('should return status 500 and error message when an error occurs', async () => { + // Mock the behavior of the findOne function to throw an error + const mockError = new Error('Internal server error'); + jest.spyOn(Group, 'findOne').mockRejectedValue(mockError); + + const response = await request(app).get('/getGroup/group_uuid'); + expect(response.status).toBe(500); + expect(response.body).toEqual({ error: 'Internal server error' }); +}); + +it('should throw an error with the message "This group does not exist"', async () => { + jest.spyOn(Group, 'findOne').mockResolvedValue(null); + + await expect(getGroupByName('NonExistentGroup')).rejects.toThrow('This group does not exist'); +}); + +}) \ No newline at end of file diff --git a/game/qgservice/QGController.js b/game/qgservice/QGController.js index cbb12aa1..85d4c7cf 100644 --- a/game/qgservice/QGController.js +++ b/game/qgservice/QGController.js @@ -77,16 +77,13 @@ let QGController = { getQuestionsByIds: async (req, res) => { try { const { ids } = req.body; - console.log(ids) const questions = []; for (const id of ids) { const question = await Question4Answers.find({uuid: id}) - console.log(question) questions.push(question); } res.json(questions); } catch (error) { - console.log(error) res.status(500).json({ error: 'Internal Server Error' }); } } diff --git a/game/qgservice/generatorLogic/MathQuestions.js b/game/qgservice/generatorLogic/MathQuestions.js index 89de09b7..facb674a 100644 --- a/game/qgservice/generatorLogic/MathQuestions.js +++ b/game/qgservice/generatorLogic/MathQuestions.js @@ -54,4 +54,4 @@ function generateRandomMathQuestion() { } } -module.exports = { createMathQuestions }; \ No newline at end of file +module.exports = { createMathQuestions, generateRandomMathQuestion }; \ No newline at end of file diff --git a/game/qgservice/qg-service.js b/game/qgservice/qg-service.js index 72b41bad..24c21865 100644 --- a/game/qgservice/qg-service.js +++ b/game/qgservice/qg-service.js @@ -14,7 +14,7 @@ mongoose.connect(mongoUri); app.get('/', (req, res) => { res.json({ - "hi": "question generator" + "message": "Welcome to question generator service module" }); }); @@ -26,4 +26,8 @@ const server = app.listen(port, () => { console.log(`Question generator Service listening at http://localhost:${port}`); }); +server.on('close', () => { + mongoose.connection.close(); +}); + module.exports = server; diff --git a/game/qgservice/qg.test.js b/game/qgservice/qg.test.js new file mode 100644 index 00000000..8e655dca --- /dev/null +++ b/game/qgservice/qg.test.js @@ -0,0 +1,495 @@ +const request = require('supertest'); +const { MongoMemoryServer } = require('mongodb-memory-server'); +const Question4Answers = require('./Question4Answers'); +const expectQuestionProperties = require('./test-utils/ExpectQuestionProperties') +const { generateQuestionCapital, generateQuestionPopulation, generateQuestionChemical, generateQuestionMonument } = require('./generatorLogic/questiongenerator') +const { executeSparqlQuery } = require('./generatorLogic/SparqlQuery') +const { bindCapitalsResults, bindPopulationResults, bindChemicalResults, bindMonumentResults } = require('./generatorLogic/BindResults') +const { createMathQuestions, generateRandomMathQuestion } = require('./generatorLogic/MathQuestions') +const axios = require('axios'); +const { capitalQuestion, populationQuestion, chemicalQuestion, monumentQuestion } = require('./generatorLogic/questionLanguage') +const {capitalTestData,chemicalTestData,monumentTestData,populationTestData} = require('./test-utils/BindTestResults') + +let app; +let mongoServer; + +describe('Question generator Service API Tests', () => { + beforeAll(async () => { + mongoServer = await MongoMemoryServer.create(); + const mongoUri = mongoServer.getUri(); + process.env.MONGODB_URI = mongoUri; + app = require('./qg-service'); + }); + + afterEach(async () => { + jest.restoreAllMocks(); + await Question4Answers.deleteMany({}); + }); + + afterAll(async () => { + app.close(); + await mongoServer.stop(); + }); + + it('GET / should return welcome message', async () => { + const response = await request(app).get('/'); + expect(response.status).toBe(200); + expect(response.body.message).toBe('Welcome to question generator service module'); + }); + + it('should return questions by their IDs', async () => { + + const findMock = jest.spyOn(Question4Answers, 'find'); + + // Mock the return values for the find method + findMock.mockReturnValueOnce( + Promise.resolve([ + { uuid: 'question_uuid1', question: 'Question 1', correctAnswer: 'Answer 1', incorrectAnswer1: 'Answer 2', incorrectAnswer2: 'Answer 3', incorrectAnswer3: 'Answer 4' }, + ]) + ); + findMock.mockReturnValueOnce( + Promise.resolve([ + { uuid: 'question_uuid2', question: 'Question 2', correctAnswer: 'Answer 1', incorrectAnswer1: 'Answer 2', incorrectAnswer2: 'Answer 3', incorrectAnswer3: 'Answer 4' }, + ]) + ); + + const requestBody = { + ids: ['question_uuid1', 'question_uuid2'] + }; + + const response = await request(app).post('/getQuestionsByIds').send(requestBody); + + expect(response.status).toBe(200); + expect(response.body).toBeInstanceOf(Array); + expect(response.body.length).toBe(2); + + // Assert properties of the first question + expect(response.body[0]).toHaveLength(1); // Nested array with one question + expect(response.body[0][0]).toEqual({ + uuid: 'question_uuid1', + question: 'Question 1', + correctAnswer: 'Answer 1', + incorrectAnswer1: 'Answer 2', + incorrectAnswer2: 'Answer 3', + incorrectAnswer3: 'Answer 4' + }); + + // Assert properties of the second question + expect(response.body[1]).toHaveLength(1); // Nested array with one question + expect(response.body[1][0]).toEqual({ + uuid: 'question_uuid2', + question: 'Question 2', + correctAnswer: 'Answer 1', + incorrectAnswer1: 'Answer 2', + incorrectAnswer2: 'Answer 3', + incorrectAnswer3: 'Answer 4' + }); + + // Restore the original implementation of the find method + findMock.mockRestore(); + }); + + it('should return status 500 and error message when an error occurs', async () => { + const mockError = new Error('Internal server error'); + jest.spyOn(Question4Answers, 'find').mockRejectedValue(mockError); + + const requestBody = { + ids: ['question_uuid1', 'question_uuid2'] + }; + + const response = await request(app).post('/getQuestionsByIds').send(requestBody); + + expect(response.status).toBe(500); + expect(response.body).toEqual({ error: 'Internal Server Error' }); + }); + + it('should execute SPARQL query and return response data', async () => { + const responseData = { results: { bindings: [{ label: { value: 'Example Label' } }] } }; + const axiosGetMock = jest.spyOn(axios, 'get').mockResolvedValue({ data: responseData }); + + const query = 'SELECT ?label WHERE { wd:Q42 rdfs:label ?label }'; + const response = await executeSparqlQuery(query); + + expect(axiosGetMock).toHaveBeenCalledWith('https://query.wikidata.org/sparql', { + headers: { + 'User-Agent': 'Your User Agent', + 'Accept': 'application/json', + }, + params: { + query: query, + format: 'json', + }, + }); + + expect(response).toEqual(responseData); +}); + +it('should throw an error when an error occurs during execution', async () => { + const errorMessage = 'Network Error'; + const axiosGetMock = jest.spyOn(axios, 'get').mockRejectedValue(new Error(errorMessage)); + + const query = 'SELECT ?label WHERE { wd:Q42 rdfs:label ?label }'; + + await expect(executeSparqlQuery(query)).rejects.toThrow(errorMessage); + + expect(axiosGetMock).toHaveBeenCalledWith('https://query.wikidata.org/sparql', { + headers: { + 'User-Agent': 'Your User Agent', + 'Accept': 'application/json', + }, + params: { + query: query, + format: 'json', + }, + }); +}); + +it('should bind query results to a Map of capitals', () => { + // Mock query result + const queryResult = { + results: { + bindings: [ + { countryLabel: { value: 'France' }, capitalLabel: { value: 'Paris' } }, + { countryLabel: { value: 'Germany' }, capitalLabel: { value: 'Berlin' } } + ] + } + }; + + // Call the function with the mocked query result + const capitalsMap = bindCapitalsResults(queryResult); + + // Assertions + expect(capitalsMap).toBeInstanceOf(Map); + expect(capitalsMap.size).toBe(2); + expect(capitalsMap.get('France')).toBe('Paris'); + expect(capitalsMap.get('Germany')).toBe('Berlin'); +}); + +it('should handle empty query result', () => { + // Mock empty query result + const queryResult = { + results: { bindings: [] } + }; + + // Call the function with the empty query result + const capitalsMap = bindCapitalsResults(queryResult); + + // Assertions + expect(capitalsMap).toBeInstanceOf(Map); + expect(capitalsMap.size).toBe(0); +}); + +it('should generate a math question with valid operands and operator', () => { + + const mathQuestion = generateRandomMathQuestion(); + + expect(mathQuestion).toHaveProperty('uuid'); + expect(mathQuestion).toHaveProperty('question'); + expect(mathQuestion).toHaveProperty('correctAnswer'); + expect(mathQuestion).toHaveProperty('incorrectAnswer1'); + expect(mathQuestion).toHaveProperty('incorrectAnswer2'); + expect(mathQuestion).toHaveProperty('incorrectAnswer3'); + + const [operand1, operator, operand2] = mathQuestion.question.split(' '); + + expect(parseInt(operand1)).toBeGreaterThanOrEqual(1); + expect(parseInt(operand1)).toBeLessThanOrEqual(100); + expect(parseInt(operand2)).toBeGreaterThanOrEqual(1); + expect(parseInt(operand2)).toBeLessThanOrEqual(100); + + expect(['+', '-', '*', '/']).toContain(operator); + + const correctAnswer = eval(mathQuestion.question); + expect(mathQuestion.correctAnswer).toEqual(correctAnswer.toString()); + + expect(mathQuestion.incorrectAnswer1).not.toEqual(correctAnswer.toString()); + expect(mathQuestion.incorrectAnswer2).not.toEqual(correctAnswer.toString()); + expect(mathQuestion.incorrectAnswer3).not.toEqual(correctAnswer.toString()); +}); + +it('should create math questions and return them', async () => { + const numberOfQuestions = 3; + + const result = await createMathQuestions(numberOfQuestions); + + expect(Array.isArray(result)).toBe(true); + expect(result.length).toBe(3); + + result.forEach((question) => { + expect(question).toHaveProperty('correctAnswer'); + expect(question).toHaveProperty('incorrectAnswer1'); + expect(question).toHaveProperty('incorrectAnswer2'); + expect(question).toHaveProperty('incorrectAnswer3'); + expect(question).toHaveProperty('question'); + expect(question).toHaveProperty('uuid'); + expect(typeof question.correctAnswer).toBe('string'); + expect(typeof question.incorrectAnswer1).toBe('string'); + expect(typeof question.incorrectAnswer2).toBe('string'); + expect(typeof question.incorrectAnswer3).toBe('string'); + expect(typeof question.question).toBe('string'); + expect(typeof question.uuid).toBe('string'); + }); +}); + +it('should bind query results to a Map of populations', () => { + + // Call the function with the mocked query result + const populationMap = bindPopulationResults(populationTestData); + + // Assertions + expect(populationMap).toBeInstanceOf(Map); + expect(populationMap.size).toBe(4); + expect(populationMap.get('Tokyo')).toBe(13929286); + expect(populationMap.get('Delhi')).toBe(18978000); + expect(populationMap.get('Madrid')).toBe(3550000); +}); + +it('should handle empty query result', () => { + // Mock empty query result + const queryResult = { + results: { bindings: [] } + }; + + // Call the function with the empty query result + const populationMap = bindPopulationResults(queryResult); + + // Assertions + expect(populationMap).toBeInstanceOf(Map); + expect(populationMap.size).toBe(0); +}); + +it('should bind query results to a Map of chemical elements', () => { + + // Call the function with the mocked query result + const chemicalElementMap = bindChemicalResults(chemicalTestData); + + // Assertions + expect(chemicalElementMap).toBeInstanceOf(Map); + expect(chemicalElementMap.size).toBe(4); + expect(chemicalElementMap.get('H')).toBe('Hydrogen'); + expect(chemicalElementMap.get('O')).toBe('Oxygen'); + expect(chemicalElementMap.get('C')).toBe('Carbon'); +}); + +it('should handle empty query result', () => { + // Mock empty query result + const queryResult = { + results: { bindings: [] } + }; + + // Call the function with the empty query result + const chemicalElementMap = bindChemicalResults(queryResult); + + // Assertions + expect(chemicalElementMap).toBeInstanceOf(Map); + expect(chemicalElementMap.size).toBe(0); +}); + +it('should bind query results to a Map of monuments', () => { + + // Call the function with the mocked query result + const monumentMap = bindMonumentResults(monumentTestData); + + // Assertions + expect(monumentMap).toBeInstanceOf(Map); + expect(monumentMap.size).toBe(4); + expect(monumentMap.get('Eiffel Tower')).toBe('France'); + expect(monumentMap.get('Taj Mahal')).toBe('India'); + expect(monumentMap.get('Statue of Liberty')).toBe('United States'); + expect(monumentMap.get('Great Wall of China')).toBe('China'); +}); + +it('should handle empty query result', () => { + // Mock empty query result + const queryResult = { + results: { bindings: [] } + }; + + // Call the function with the empty query result + const monumentMap = bindMonumentResults(queryResult); + + // Assertions + expect(monumentMap).toBeInstanceOf(Map); + expect(monumentMap.size).toBe(0); +}); + +it('should generate a population question with valid data', () => { + const cityPopulationMap = bindPopulationResults(populationTestData); + const question = generateQuestionPopulation(cityPopulationMap, 'en'); + + expectQuestionProperties(question) +}); + +it('should handle error when saving question to MongoDB', async () => { + const queryResult = { + results: { + bindings: [ + { cityLabel: { value: 'Tokyo' }, population: { value: '13929286' } }, + { cityLabel: { value: 'Delhi' }, population: { value: '18978000' } }, + { cityLabel: { value: 'Shanghai' }, population: { value: '24150000' } }, + { cityLabel: { value: 'Madrid' }, population: { value: '3550000' } } + ] + } + }; + + const cityPopulationMap = bindPopulationResults(queryResult); + + const mockSaveError = new Error('Failed to save question'); + jest.spyOn(Question4Answers.prototype, 'save').mockRejectedValue(mockSaveError); + + try { + await generateQuestionPopulation(cityPopulationMap, 'en'); + } catch (error) { + expect(error).toBe(mockSaveError); + expect(console.error).toHaveBeenCalledWith('Error saving question to MongoDB:', mockSaveError.message); + } +}); + +it('should generate a capital question with valid data', () => { + // Call the function with the mocked query result + const countryCapitalMap = bindCapitalsResults(capitalTestData); + + const question = generateQuestionCapital(countryCapitalMap, 'en'); + + expectQuestionProperties(question) +}); + +it('should handle error when saving question to MongoDB', async () => { + const capitalsMap = bindCapitalsResults(capitalTestData); + + const mockSaveError = new Error('Failed to save question'); + jest.spyOn(Question4Answers.prototype, 'save').mockRejectedValue(mockSaveError); + + try { + await generateQuestionCapital(capitalsMap, 'en'); + } catch (error) { + expect(error).toBe(mockSaveError); + expect(console.error).toHaveBeenCalledWith('Error saving question to MongoDB:', mockSaveError.message); + } +}); + +it('should generate a chemical question with valid data', () => { + // Call the function with the mocked query result + const chemicalElementMap = bindChemicalResults(chemicalTestData); + + const question = generateQuestionChemical(chemicalElementMap, 'en'); + + // Assertions + expectQuestionProperties(question) +}); + +it('should handle error when saving question to MongoDB', async () => { + const queryResult = { + results: { + bindings: [ + { elementLabel: { value: 'Oxygen' }, symbol: { value: 'O' } }, + { elementLabel: { value: 'Hydrogen' }, symbol: { value: 'H' } }, + { elementLabel: { value: 'Carbon' }, symbol: { value: 'C' } }, + { elementLabel: { value: 'Nitrogen' }, symbol: { value: 'N' } } + ] + } + }; + + const chemicalsMap = bindChemicalResults(queryResult); + + const mockSaveError = new Error('Failed to save question'); + jest.spyOn(Question4Answers.prototype, 'save').mockRejectedValue(mockSaveError); + + try { + await generateQuestionChemical(chemicalsMap, 'en'); + } catch (error) { + expect(error).toBe(mockSaveError); + expect(console.error).toHaveBeenCalledWith('Error saving question to MongoDB:', mockSaveError.message); + } +}); + +it('should generate a monument question with valid data', () => { + // Call the function with the mocked query result + const monumentMap = bindMonumentResults(monumentTestData); + + const question = generateQuestionMonument(monumentMap, 'en'); + + // Assertions + expectQuestionProperties(question) +}); + +it('should handle error when saving question to MongoDB', async () => { + const monumentsMap = bindMonumentResults(monumentTestData); + + const mockSaveError = new Error('Failed to save question'); + jest.spyOn(Question4Answers.prototype, 'save').mockRejectedValue(mockSaveError); + + try { + await generateQuestionMonument(monumentsMap, 'en'); + } catch (error) { + expect(error).toBe(mockSaveError); + expect(console.error).toHaveBeenCalledWith('Error saving question to MongoDB:', mockSaveError.message); + } +}) + +it('should return the capital question in English', () => { + const lang = 'en'; + const country = 'France'; + const expectedQuestion = 'What is the capital of France?'; + const question = capitalQuestion(lang, country); + expect(question).toBe(expectedQuestion); +}); + +it('should return the capital question in Spanish', () => { + const lang = 'es'; + const country = 'France'; + const expectedQuestion = '¿Cual es la capital de France?'; + const question = capitalQuestion(lang, country); + expect(question).toBe(expectedQuestion); +}); + +it('should return the population question in English', () => { + const lang = 'en'; + const city = 'Tokyo'; + const expectedQuestion = 'What is the population of Tokyo?'; + const question = populationQuestion(lang, city); + expect(question).toBe(expectedQuestion); +}); + +it('should return the population question in Spanish', () => { + const lang = 'es'; + const city = 'Tokyo'; + const expectedQuestion = '¿Cual es la población de Tokyo?'; + const question = populationQuestion(lang, city); + expect(question).toBe(expectedQuestion); +}); + +it('should return the chemical question in English', () => { + const lang = 'en'; + const chemical = 'Oxygen'; + const expectedQuestion = 'What is the chemical symbol of Oxygen?'; + const question = chemicalQuestion(lang, chemical); + expect(question).toBe(expectedQuestion); +}); + +it('should return the chemical question in Spanish', () => { + const lang = 'es'; + const chemical = 'Oxygen'; + const expectedQuestion = '¿Cual es el símbolo químico de Oxygen?'; + const question = chemicalQuestion(lang, chemical); + expect(question).toBe(expectedQuestion); +}); + +it('should return the monument question in English', () => { + const lang = 'en'; + const monument = 'Eiffel Tower'; + const expectedQuestion = 'Where is Eiffel Tower?'; + const question = monumentQuestion(lang, monument); + expect(question).toBe(expectedQuestion); +}); + +it('should return the monument question in Spanish', () => { + const lang = 'es'; + const monument = 'Eiffel Tower'; + const expectedQuestion = '¿Dónde está Eiffel Tower?'; + const question = monumentQuestion(lang, monument); + expect(question).toBe(expectedQuestion); +}); + + +}) \ No newline at end of file diff --git a/game/qgservice/test-utils/BindTestResults.js b/game/qgservice/test-utils/BindTestResults.js new file mode 100644 index 00000000..6e9eb131 --- /dev/null +++ b/game/qgservice/test-utils/BindTestResults.js @@ -0,0 +1,45 @@ +const monumentTestData = { + results: { + bindings: [ + { monumentLabel: { value: 'Eiffel Tower' }, countryLabel: { value: 'France' } }, + { monumentLabel: { value: 'Taj Mahal' }, countryLabel: { value: 'India' } }, + { monumentLabel: { value: 'Statue of Liberty' }, countryLabel: { value: 'United States' } }, + { monumentLabel: { value: 'Great Wall of China' }, countryLabel: { value: 'China' } } + ] + } + }; + +const chemicalTestData = { + results: { + bindings: [ + { elementLabel: { value: 'Oxygen' }, symbol: { value: 'O' } }, + { elementLabel: { value: 'Hydrogen' }, symbol: { value: 'H' } }, + { elementLabel: { value: 'Carbon' }, symbol: { value: 'C' } }, + { elementLabel: { value: 'Nitrogen' }, symbol: { value: 'N' } } + ] + } +}; + +const capitalTestData = { + results: { + bindings: [ + { countryLabel: { value: 'France' }, capitalLabel: { value: 'Paris' } }, + { countryLabel: { value: 'Germany' }, capitalLabel: { value: 'Berlin' } }, + { countryLabel: { value: 'Italy' }, capitalLabel: { value: 'Rome' } }, + { countryLabel: { value: 'Spain' }, capitalLabel: { value: 'Madrid' } } + ] + } + }; + + const populationTestData = { + results: { + bindings: [ + { cityLabel: { value: 'Tokyo' }, population: { value: '13929286' } }, + { cityLabel: { value: 'Delhi' }, population: { value: '18978000' } }, + { cityLabel: { value: 'Shanghai' }, population: { value: '24150000' } }, + { cityLabel: { value: 'Madrid' }, population: { value: '3550000' } } + ] + } + }; + + module.exports = { monumentTestData, chemicalTestData, capitalTestData, populationTestData }; \ No newline at end of file diff --git a/game/qgservice/test-utils/ExpectQuestionProperties.js b/game/qgservice/test-utils/ExpectQuestionProperties.js new file mode 100644 index 00000000..3b04a3f5 --- /dev/null +++ b/game/qgservice/test-utils/ExpectQuestionProperties.js @@ -0,0 +1,16 @@ +function expectQuestionProperties(question) { + expect(question).toHaveProperty('uuid'); + expect(question).toHaveProperty('question'); + expect(question).toHaveProperty('correctAnswer'); + expect(question).toHaveProperty('incorrectAnswer1'); + expect(question).toHaveProperty('incorrectAnswer2'); + expect(question).toHaveProperty('incorrectAnswer3'); + expect(typeof question.uuid).toBe('string'); + expect(typeof question.question).toBe('string'); + expect(typeof question.correctAnswer).toBe('string'); + expect(typeof question.incorrectAnswer1).toBe('string'); + expect(typeof question.incorrectAnswer2).toBe('string'); + expect(typeof question.incorrectAnswer3).toBe('string'); + } + +module.exports = expectQuestionProperties; \ No newline at end of file diff --git a/game/qgservice/user-service.test.js b/game/qgservice/user-service.test.js deleted file mode 100644 index 462169cf..00000000 --- a/game/qgservice/user-service.test.js +++ /dev/null @@ -1,32 +0,0 @@ -/* -const request = require('supertest'); -const { MongoMemoryServer } = require('mongodb-memory-server'); - -let mongoServer; -let app; - -beforeAll(async () => { - mongoServer = await MongoMemoryServer.create(); - const mongoUri = mongoServer.getUri(); - process.env.MONGODB_URI = mongoUri; - app = require('./qg-service'); -}); - -afterAll(async () => { - app.close(); - await mongoServer.stop(); -}); - -describe('User Service', () => { - it('should add a new user on POST /adduser', async () => { - const newUser = { - username: 'testuser', - password: 'testpassword', - }; - - const response = await request(app).post('/adduser').send(newUser); - expect(response.status).toBe(200); - expect(response.body).toHaveProperty('username', 'testuser'); - }); -}); -*/ \ No newline at end of file diff --git a/webapp/src/components/g-login-button/GLoginButton.tsx b/webapp/src/components/g-login-button/GLoginButton.tsx index c8942360..b8572585 100644 --- a/webapp/src/components/g-login-button/GLoginButton.tsx +++ b/webapp/src/components/g-login-button/GLoginButton.tsx @@ -7,7 +7,7 @@ const GLoginButton = () => const { t } = useTranslation(); return( - { console.log(credentialResponse);