From 5f40ac6b570b4b5bd86f0122740923177513d804 Mon Sep 17 00:00:00 2001 From: "Xunnamius (Romulus)" Date: Sun, 31 May 2020 06:27:38 -0500 Subject: [PATCH] all tests defined --- src/__test__/election.test.ts | 135 +++++++++++++++++++++++++++++++-- src/__test__/elections.test.ts | 6 +- src/__test__/voters.test.ts | 131 +++++++++++++++++++++++++++++--- 3 files changed, 254 insertions(+), 18 deletions(-) diff --git a/src/__test__/election.test.ts b/src/__test__/election.test.ts index 8ba15df..db19660 100644 --- a/src/__test__/election.test.ts +++ b/src/__test__/election.test.ts @@ -4,6 +4,8 @@ import * as Election from 'universe/pages/api/v1/election/[id]' import { getEnv } from 'universe/backend/env' import type { PublicElection, InternalElection } from 'types/global' +import { getInternalElection, getPublicElection, doesElectionExist } from 'universe/backend' +import { ObjectId } from 'mongodb' const { getHydratedData } = setupJest(); @@ -49,7 +51,7 @@ const internalToPublic = (e: InternalElection[]) => { }); }; -describe('api/v1/election', () => { +describe('api/v1/election', async () => { it('requests without a key return 401', async () => { await testApiEndpoint({ next: electionEndpoint, @@ -96,19 +98,138 @@ describe('api/v1/election', () => { const { success, ...election } = await response.json(); expect(response.status).toBe(200); - expect(success).toBe(true); + expect(success).toBeTrue(); expect(containsOnlyPublicData(election)).toBeTrue(); } }); }); - test.todo('can use PUT to mutate an election'); + it('can use PUT to mutate an election', async () => { + const election_id = getHydratedData().elections[52].election_id; - test.todo('can use DELETE to delete an election'); + await testApiEndpoint({ + next: electionEndpoint, + params: { id: election_id }, + test: async ({ fetch }) => { + const mutation = { + election_id, + title: 'Flip mode!', + description: 'Flip mode family ties', + options: ['A', 'B', 'Z'], + closes: Date.now() + 10**8 + }; + + const response = await fetch({ + method: 'PUT', + headers: { KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify(mutation) + }); + + expect(response.status).toBe(200); + + expect(await getPublicElection({ + electionId: election_id, key: KEY + })).toContainEntries(Object.entries(mutation)); + } + }); + }); + + it('can use DELETE to delete an election', async () => { + const election_id = getHydratedData().elections[52].election_id; + + await testApiEndpoint({ + next: electionEndpoint, + params: { id: election_id }, + test: async ({ fetch }) => { + expect(await doesElectionExist(election_id)).toBeTrue(); - test.todo('returns a 400 error on invalid data during PUT'); + const response = await fetch({ method: 'DELETE', headers: { KEY }}); + + expect(response.status).toBe(200); + expect(await doesElectionExist(election_id)).toBeFalse(); + } + }); + }); - test.todo('returns a 403 error when trying to PUT or DELETE with an election_id owned by a different key'); + it('returns a 400 error on invalid data during PUT', async () => { + const election_id = getHydratedData().elections[52].election_id; + + const getInvalidData = function*() { + yield { data: 1 }; + yield { title: '', created: Date.now() }; + yield { title: 'test election', options: [{}, {}], opens: Date.now() + 10**4, closes: Date.now() + 10**5 }; + yield { title: 'my title', opens: Date.now() - 1000, closes: Date.now() + 10**5 }; + yield { title: 'my title #2', opens: Date.now() + 10**7, closes: Date.now() + 10**5 }; + yield { title: 'my title #3', opens: Date.now() + 10**5, closes: Date.now() + 10**7, description: 54 }; + yield { title: 'my title #4', opens: Date.now() + 10**5, closes: Date.now() + 10**7, options: [54] }; + yield { title: 'my title #5', opens: Date.now() + 10**5, closes: Infinity }; + yield { title: 'my title #6', opens: Date.now() + 10**5, closes: NaN }; + yield { title: 'my title #7', opens: undefined, closes: undefined }; + yield { title: 'my title #7', election_id: (new ObjectId()).toHexString() }; + yield {}; + }(); - test.todo('returns a 404 error if election_id does not exist'); + await testApiEndpoint({ + next: electionEndpoint, + params: { id: election_id }, + test: async ({ fetch }) => { + const responses = await Promise.all([...Array(12)].map(_ => fetch({ + method: 'PUT', + headers: { KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify(getInvalidData.next().value) + }).then(r => r.status))); + + expect(responses).toEqual([ + ...[...Array(12)].map(_ => 400) + ]); + } + }); + }); + + it('returns a 403 error when trying to PUT or DELETE with an election_id owned by a different key', async () => { + const election_id = getHydratedData().elections[0].election_id; + + await testApiEndpoint({ + next: electionEndpoint, + params: { id: election_id }, + test: async ({ fetch }) => { + expect(await doesElectionExist(election_id)).toBeTrue(); + + let response = await fetch({ method: 'DELETE', headers: { KEY }}); + + expect(response.status).toBe(403); + expect(await doesElectionExist(election_id)).toBeTrue(); + + response = await fetch({ + method: 'PUT', + headers: { KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify({ title: 'UPDATED TITLE SUPER COOL' }) + }); + + expect(response.status).toBe(403); + } + }); + }); + + it('returns a 404 error if election_id does not exist', async () => { + const election_id = (new ObjectId()).toHexString(); + + await testApiEndpoint({ + next: electionEndpoint, + params: { id: election_id }, + test: async ({ fetch }) => { + const responses = await Promise.all([ + fetch({ method: 'GET', headers: { KEY }}), + fetch({ method: 'DELETE', headers: { KEY }}), + fetch({ + method: 'PUT', + headers: { KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify({ title: 'UPDATED TITLE SUPER COOL' }) + }), + ].map(p => p.then(r => r.status))); + + expect(responses).toEqual([ 404, 404, 404 ]); + } + }); + }); }); diff --git a/src/__test__/elections.test.ts b/src/__test__/elections.test.ts index 693a00e..58e5043 100644 --- a/src/__test__/elections.test.ts +++ b/src/__test__/elections.test.ts @@ -310,19 +310,21 @@ describe('api/v1/elections', () => { yield { title: 'my title #5', opens: Date.now() + 10**5, closes: Infinity }; yield { title: 'my title #6', opens: Date.now() + 10**5, closes: NaN }; yield { title: 'my title #7', opens: undefined, closes: undefined }; + yield { title: 'my title #7', election_id: (new ObjectId()).toHexString() }; + yield {}; }(); await testApiEndpoint({ next: electionsEndpoint, test: async ({ fetch }) => { - const responses = await Promise.all([...Array(10)].map(_ => fetch({ + const responses = await Promise.all([...Array(12)].map(_ => fetch({ method: 'POST', headers: { KEY, 'Content-Type': 'application/json' }, body: JSON.stringify(getInvalidData.next().value) }).then(r => r.status))); expect(responses).toEqual([ - ...[...Array(10)].map(_ => 400) + ...[...Array(12)].map(_ => 400) ]); } }); diff --git a/src/__test__/voters.test.ts b/src/__test__/voters.test.ts index bc054d2..45201b1 100644 --- a/src/__test__/voters.test.ts +++ b/src/__test__/voters.test.ts @@ -2,6 +2,8 @@ import { setupJest } from 'universe/__test__/db' import { testApiEndpoint } from 'multiverse/test-api-endpoint' import * as Voters from 'universe/pages/api/v1/election/[id]/voters' import { getEnv } from 'universe/backend/env' +import { getRankings, upsertElection } from 'universe/backend'; +import { ObjectId } from 'mongodb'; const { getHydratedData } = setupJest(); @@ -54,28 +56,139 @@ describe('api/v1/election/voters', () => { }); it('returns only public voter and ranking data on election_id', async () => { + const election_id = getHydratedData().elections[22].election_id; + await testApiEndpoint({ next: votersEndpoint, + params: { id: election_id }, test: async ({ fetch }) => { const response = await fetch({ headers: { KEY } }); - const json = await response.json(); + const { success, votes, ...rest } = await response.json(); + + expect(response.status).toBe(200); + expect(success).toBeTrue(); + expect(Object.keys(rest).length).toBe(0); + expect(votes).toEqual((await getRankings(election_id))); + } + }); + }); - const elections = getHydratedData().elections; - void elections; + it('can use PUT to mutate election rankings', async () => { + const election_id = getHydratedData().elections[52].election_id; + + await testApiEndpoint({ + next: votersEndpoint, + params: { id: election_id }, + test: async ({ fetch }) => { + const mutation = [{ voter_id: 'X', ranking: ['Walking Dead'] }]; + + const response = await fetch({ + method: 'PUT', + headers: { KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify(mutation) + }); + + expect(response.status).toBe(200); + expect(await getRankings(election_id)).toEqual(mutation); + } + }); + }); + + it('returns an empty array when querying a brand new election_id', async () => { + const { election_id } = await upsertElection({ + key: KEY, + election: { + title: 'Mine!', + opens: Date.now() + 10**5, + closes: Date.now() + 10**6 + } + }); + + await testApiEndpoint({ + next: votersEndpoint, + params: { id: election_id }, + test: async ({ fetch }) => { + const response = await fetch({ headers: { KEY } }); + const { success, votes } = await response.json(); expect(response.status).toBe(200); - expect(json.success).toBe(true); + expect(success).toBeTrue(); + expect(votes).toEqual([]); } }); }); - test.todo('can use PUT to mutate election rankings'); + it('returns a 400 error on invalid data during PUT', async () => { + const election_id = getHydratedData().elections[52].election_id; + + const getInvalidData = function*() { + yield { data: 1 }; + yield { 1: '1', 2: '2' }; + yield [{ 1: '1', 2: '2' }]; + yield undefined; + yield null; + yield NaN; + yield [{}]; + yield [[]]; + yield [undefined]; + yield [{ vote: 1, rank: []}]; + yield [{ voter_id: 1, rankings: []}]; + yield [{ voter_id: '1', rankings: ['FAKER']}]; + }(); - test.todo('returns an empty array when querying a brand new election_id'); + await testApiEndpoint({ + next: votersEndpoint, + params: { id: election_id }, + test: async ({ fetch }) => { + const responses = await Promise.all([...Array(12)].map(_ => fetch({ + method: 'PUT', + headers: { KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify(getInvalidData.next().value) + }).then(r => r.status))); + + expect(responses).toEqual([ + ...[...Array(12)].map(_ => 400) + ]); + } + }); + }); - test.todo('returns a 400 error on invalid data during PUT'); + it('returns a 403 error when trying to mutate an unowned election_id', async () => { + const election_id = getHydratedData().elections[0].election_id; - test.todo('returns a 403 error when trying to mutate an unowned election_id'); + await testApiEndpoint({ + next: votersEndpoint, + params: { id: election_id }, + test: async ({ fetch }) => { + const response = await fetch({ + method: 'PUT', + headers: { KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify([]) + }); - test.todo('returns a 404 error if election_id does not exist'); + expect(response.status).toBe(403); + } + }); + }); + + it('returns a 404 error if election_id does not exist', async () => { + const election_id = (new ObjectId()).toHexString(); + + await testApiEndpoint({ + next: votersEndpoint, + params: { id: election_id }, + test: async ({ fetch }) => { + const responses = await Promise.all([ + fetch({ method: 'GET', headers: { KEY }}), + fetch({ + method: 'PUT', + headers: { KEY, 'Content-Type': 'application/json' }, + body: JSON.stringify([]) + }), + ].map(p => p.then(r => r.status))); + + expect(responses).toEqual([ 404, 404 ]); + } + }); + }); });