6080-a3-BigBrain / backend / test / main.test.js
main.test.js
Raw
import request from 'supertest';
import server from '../src/server';
import { reset } from '../src/service';

const THUMBNAIL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const QUESTIONS = [
  {

  },
  {

  },
  {

  },
];
const PLAYERS = ['HAYDEN1','HAYDEN2','HAYDEN3','HAYDEN4','HAYDEN5'];
const PLAYER_IDS = [];

const postTry = async (path, status, payload, token) => sendTry('post', path, status, payload, token);
const getTry = async (path, status, payload, token) => sendTry('get', path, status, payload, token);
const deleteTry = async (path, status, payload, token) => sendTry('delete', path, status, payload, token);
const putTry = async (path, status, payload, token) => sendTry('put', path, status, payload, token);

const sendTry = async (typeFn, path, status = 200, payload = {}, token = null) => {
  let req = request(server);
  if (typeFn === 'post') {
    req = req.post(path);
  } else if (typeFn === 'get') {
    req = req.get(path);
  } else if (typeFn === 'delete') {
    req = req.delete(path);
  } else if (typeFn === 'put') {
    req = req.put(path);
  }
  if (token !== null) {
    req = req.set('Authorization', `Bearer ${token}`);
  }
  const response = await req.send(payload);
  expect(response.statusCode).toBe(status);
  return response.body;
};

const validToken = async () => {
  const { token } = await postTry('/admin/auth/login', 200, {
    email: 'hayden.smith@unsw.edu.au',
    password: 'bananapie',
  });
  return token;
}

const singleQuizId = async () => {
  const { quizzes } = await getTry('/admin/quiz', 200, {}, await validToken());
  const quizid = quizzes[0].id;
  return quizid;
};

const singleSessionStatus = async () => {
  const { quizzes } = await getTry('/admin/quiz', 200, {}, await validToken());
  const sessionid = quizzes[0].active;
  const body = await getTry(`/admin/session/${sessionid}/status`, 200, {}, await validToken());
  return body.results;
};

const singleSessionId = async () => {
  const { quizzes } = await getTry('/admin/quiz', 200, {}, await validToken());
  return quizzes[0].active;
};

describe('Test the root path', () => {

  beforeAll(() => {
    reset();
  });

  beforeAll(() => {
    server.close();
  });

  /***************************************************************
                       Auth Tests
  ***************************************************************/

  test('Registration of initial user', async () => {
    const body = await postTry('/admin/auth/register', 200, {
      email: 'hayden.smith@unsw.edu.au',
      password: 'bananapie',
      name: 'Hayden',
    });
    expect(body.token instanceof String);
  });

  test('Inability to re-register a user', async () => {
    const body = await postTry('/admin/auth/register', 400, {
      email: 'hayden.smith@unsw.edu.au',
      password: 'bananapie',
      name: 'Hayden',
    });
  });

  test('Login to an existing user', async () => {
    const body = await postTry('/admin/auth/login', 200, {
      email: 'hayden.smith@unsw.edu.au',
      password: 'bananapie',
    });
    expect(body.token instanceof String);
  });

  test('Login attempt with invalid credentials 1', async () => {
    const body = await postTry('/admin/auth/login', 400, {
      email: 'hayden.smith@unsw.edu.a',
      password: 'bananapie',
    });
  });

  test('Login attempt with invalid credentials 2', async () => {
    const body = await postTry('/admin/auth/login', 400, {
      email: 'hayden.smith@unsw.edu.au',
      password: 'bananapi',
    });
  });

  test('Logout a valid session', async () => {
    const bodyLogout = await postTry('/admin/auth/logout', 200, {}, await validToken());
    expect(bodyLogout).toMatchObject({});
  });

  test('Logout a session without auth token', async () => {
    const body = await postTry('/admin/auth/logout', 403, {});
    expect(body).toMatchObject({});
  });

  /***************************************************************
                       Quiz Tests
  ***************************************************************/
  test('Initially there are no quizzes', async () => {
    const body = await getTry('/admin/quiz', 200, {}, await validToken());
    expect(body.quizzes).toHaveLength(0);
  });

  test('Creating a single quiz, value missing', async () => {
    const body = await postTry('/admin/quiz/new', 400, {}, await validToken());
  });

  test('Creating a single quiz, token missing', async () => {
    const body = await postTry('/admin/quiz/new', 403, {
      name: 'QUIZ',
    });
  });

  test('Creating a single quiz', async () => {
    const body = await postTry('/admin/quiz/new', 200, {
      name: 'QUIZ',
    }, await validToken());
  });

  test('That there is now one quiz', async () => {
    const body = await getTry('/admin/quiz', 200, {}, await validToken());
    expect(body.quizzes).toHaveLength(1);
    expect(typeof body.quizzes[0].id).toBe('number');
    expect(typeof body.quizzes[0].createdAt).toBe('string');
    expect(body.quizzes[0].name).toBe('QUIZ');
    expect(body.quizzes[0].owner).toBe('hayden.smith@unsw.edu.au');
    expect(body.quizzes[0].active).toBe(null);
    expect(body.quizzes[0].thumbnail).toBe(null);
    expect(body.quizzes[0].oldSessions).toMatchObject([]);
  });

  test('Create a second quiz', async () => {
    const body = await postTry('/admin/quiz/new', 200, {
      name: 'QUIZ2',
    }, await validToken());
  });

  test('That there is now two quizzes', async () => {
    const body = await getTry('/admin/quiz', 200, {}, await validToken());
    expect(body.quizzes).toHaveLength(2);
  });

  test('Try and delete a quiz with invalid token', async () => {
    const { quizzes } = await getTry('/admin/quiz', 200, {}, await validToken());
    const quizid = quizzes[1].id;
    const body = await deleteTry(`/admin/quiz/${quizid}`, 403, {});
  });

  test('Try and delete a quiz with invalid quizid', async () => {
    const body = await deleteTry(`/admin/quiz/${99999999999999}`, 400, {}, await validToken());
  });

  test('Try and delete a quiz', async () => {
    const { quizzes } = await getTry('/admin/quiz', 200, {}, await validToken());
    const quizid = quizzes[1].id;
    const body = await deleteTry(`/admin/quiz/${quizid}`, 200, {}, await validToken());
  });

  test('That there is now one quiz again', async () => {
    const body = await getTry('/admin/quiz', 200, {}, await validToken());
    expect(body.quizzes).toHaveLength(1);
  });

  test('Update quiz thumbnail and name', async () => {
    const quizid = await singleQuizId();
    const body = await putTry(`/admin/quiz/${quizid}`, 200, {
      name: 'QUIZDIFF',
      thumbnail: THUMBNAIL,
      questions: QUESTIONS,
    }, await validToken());
  });

  test('Check that thumbnail and name updated', async () => {
    const quizid = await singleQuizId();
    const quiz = await getTry(`/admin/quiz/${quizid}`, 200, {}, await validToken());
    expect(quiz.name).toBe('QUIZDIFF');
    expect(quiz.thumbnail).toBe(THUMBNAIL);
    expect(quiz.questions).toMatchObject(QUESTIONS);
  });

  /***************************************************************
                       Admin Running a Session
  ***************************************************************/

  test('Can\'t start a session with invalid token', async () => {
    const body = await postTry('/admin/quiz/123/start', 403, {});
  });

  test('Can\'t advance a session with invalid token', async () => {
    const body = await postTry('/admin/quiz/123/advance', 403, {});
  });

  test('Can\'t end a session with invalid token', async () => {
    const body = await postTry('/admin/quiz/123/end', 403, {});
  });

  test('Can\'t get session status with invalid token', async () => {
    const body = await getTry('/admin/session/123/status', 403, {});
  });

  test('Can\'t get session results with invalid token', async () => {
    const body = await getTry('/admin/session/123/results', 403, {});
  });

  test('Ensure a session cant be ended when hasn\'t started', async () => {
    const quizid = await singleQuizId();
    await postTry(`/admin/quiz/${quizid}/end`, 400, {}, await validToken());
  });

  test('Ensure a session cant be advanced when hasn\'t started', async () => {
    const quizid = await singleQuizId();
    await postTry(`/admin/quiz/${quizid}/advance`, 400, {}, await validToken());
  });

  test('Can\'t start a quiz with invalid quizid', async () => {
    const body = await postTry('/admin/quiz/99999999999/start', 403, await validToken());
  });

  test('Ensure a quiz can be started', async () => {
    const quizid = await singleQuizId();
    await postTry(`/admin/quiz/${quizid}/start`, 200, {}, await validToken());
  });

  test('A session now exists for the quiz', async () => {
    const quizid = await singleQuizId();
    const body = await getTry(`/admin/quiz/${quizid}`, 200, {}, await validToken());
    expect(typeof body.active).toBe('number');
  });

  test('A has right initial props', async () => {
    const status = await singleSessionStatus();
    expect(status.active).toBe(true);
    expect(status.answerAvailable).toBe(false);
    expect(status.isoTimeLastQuestionStarted).toBe(null);
    expect(status.position).toBe(-1);
    expect(status.questions).toMatchObject(QUESTIONS);
    expect(status.players).toMatchObject([]);
  });

  /***************************************************************
                       Try Playing
  ***************************************************************/

  test('Test player can\'t join without a name', async () => {
    const sessionId = await singleSessionId();
    await postTry(`/play/join/${sessionId}`, 400, {});
  });

  test('Test player can\'t join without a valid session ID', async () => {
    await postTry(`/play/join/${9999999999999}`, 400, {
      name: 'HAYDEN',
    });
  });

  for (const player of PLAYERS) {
    test(`Player ${player} Joins`, async () => {
      const sessionId = await singleSessionId();
      const payload = {
        name: player,
      };
      const body = await postTry(`/play/join/${sessionId}`, 200, payload);
      expect(typeof body.playerId).toBe('number');
      PLAYER_IDS.push(body.playerId);
    });
  }

  test('All players are in the session status', async () => {
    const status = await singleSessionStatus();
    expect(status.players.sort()).toMatchObject(PLAYERS.sort());
  });

  test('Players cant get questions when session hasnt started', async () => {
    for (const playerId of PLAYER_IDS) {
      await getTry(`/play/${playerId}/question`, 400, {});
    }
  });

  test('Players cant get questions answers when session hasnt started', async () => {
    for (const playerId of PLAYER_IDS) {
      await getTry(`/play/${playerId}/answer`, 400, {});
    }
  });

  test('Players cant answer questions when session hasnt started', async () => {
    for (const playerId of PLAYER_IDS) {
      await putTry(`/play/${playerId}/answer`, 400, {});
    }
  });

  test('Players cant get results when session hasnt started', async () => {
    for (const playerId of PLAYER_IDS) {
      await getTry(`/play/${playerId}/results`, 400, {});
    }
  });

  for (const questionPosition in QUESTIONS) {
    test('Try to advance the quiz', async () => {
      const quizid = await singleQuizId();
      await postTry(`/admin/quiz/${quizid}/advance`, 200, {}, await validToken());
    });

    test('Session position has increased', async () => {
      const status = await singleSessionStatus();
      expect(status.position).toBe(parseInt(questionPosition, 10));
      expect(status.active).toBe(true);
      expect(status.answerAvailable).toBe(false);
      expect(typeof status.isoTimeLastQuestionStarted).toBe('string');
    });

    test(`Players fail to submit no answers`, async () => {
      for (const playerId of PLAYER_IDS) {
        await putTry(`/play/${playerId}/answer`, 400, { answerIds: [], });
        await putTry(`/play/${playerId}/answer`, 400, {});
      }
    });

    test(`Players attempt to submit answer`, async () => {
      for (const playerId of PLAYER_IDS) {
        const payload = {
          answerIds: [ 0, 1, 2 ],
        };
        const body = await putTry(`/play/${playerId}/answer`, 200, payload);
        expect(body).toMatchObject({});
      }
    });

    test('Should be unable to start the quiz', async () => {
      const quizid = await singleQuizId();
      await postTry(`/admin/quiz/${quizid}/start`, 400, {}, await validToken());
    });

    test(`Players should not be able to get their results`, async () => {
      for (const playerId of PLAYER_IDS) {
        const body = await getTry(`/play/${playerId}/results`, 400);
      }
    });
  }

  test('Try to advance the quiz. ensure session has ended', async () => {
    const sessionId = await singleSessionId();
    const quizid = await singleQuizId();
    await postTry(`/admin/quiz/${quizid}/advance`, 200, {}, await validToken());
    const { results } = await getTry(`/admin/session/${sessionId}/status`, 200, {}, await validToken());
    expect(results.position).toBe(QUESTIONS.length);
    expect(results.active).toBe(false);
    expect(results.answerAvailable).toBe(false);
    expect(typeof results.isoTimeLastQuestionStarted).toBe('string');
  });

  test('Ensure that the session appears in old sessions', async () => {
    const quizid = await singleQuizId();
    const { oldSessions } = await getTry(`/admin/quiz/${quizid}`, 200, {}, await validToken());
    expect(oldSessions).toHaveLength(1);
  });

  test('Should be unable to advance the quiz', async () => {
    const quizid = await singleQuizId();
    await postTry(`/admin/quiz/${quizid}/advance`, 400, {}, await validToken());
  });

  test('Should be unable to end the quiz', async () => {
    const quizid = await singleQuizId();
    await postTry(`/admin/quiz/${quizid}/end`, 400, {}, await validToken());
  });

  test(`Players should be able to get their results`, async () => {
    for (const playerId of PLAYER_IDS) {
      const body = await getTry(`/play/${playerId}/results`, 200);
      expect(body).toMatchObject(QUESTIONS.map(q => ({ answerIds: [ 0, 1, 2 ], correct: false })));
    }
  });

  test('Admins can get the session results', async () => {
    const quizid = await singleQuizId();
    const { oldSessions } = await getTry(`/admin/quiz/${quizid}`, 200, {}, await validToken());
    const body = await getTry(`/admin/session/${oldSessions[0]}/results`, 200, {}, await validToken());
  });

});