Add ability to specify query params in tests

This commit is contained in:
Jerko Steiner 2019-01-27 16:07:16 +01:00
parent 04b3a7ca90
commit 52dc876845
8 changed files with 92 additions and 41 deletions

View File

@ -0,0 +1,3 @@
export interface IRequestQuery {
[key: string]: string | number
}

View File

@ -1,5 +1,6 @@
import assert from 'assert' import assert from 'assert'
import {IRequestParams} from './IRequestParams' import {IRequestParams} from './IRequestParams'
import {IRequestQuery} from './IRequestQuery'
export interface IURLFormatterOptions { export interface IURLFormatterOptions {
readonly baseURL: string readonly baseURL: string
@ -12,7 +13,11 @@ export class URLFormatter {
regex: /:[a-zA-Z0-9-]+/g, regex: /:[a-zA-Z0-9-]+/g,
}) {} }) {}
format(url: string, params?: IRequestParams) { format(
url: string,
params?: IRequestParams,
query?: IRequestQuery,
) {
if (!params) { if (!params) {
return url return url
} }
@ -21,6 +26,13 @@ export class URLFormatter {
assert(params.hasOwnProperty(key)) assert(params.hasOwnProperty(key))
return String(params![key]) return String(params![key])
}) })
if (query) {
Object.keys(query).reduce((queryString, key) => {
return queryString +
encodeURIComponent(key) + '=' +
encodeURIComponent(String(query[key])) + '&'
}, '?')
}
return this.params.baseURL + formattedUrl return this.params.baseURL + formattedUrl
} }

View File

@ -40,7 +40,11 @@ describe('team', () => {
it('results with 403 when user does not have team access ', async () => { it('results with 403 when user does not have team access ', async () => {
await t await t
.post('/teams/:teamId/sites', {teamId: team.id}) .post('/teams/:teamId/sites', {
params: {
teamId: team.id,
},
})
.send({ .send({
domain: 'test.example.com', domain: 'test.example.com',
name: 'test', name: 'test',
@ -55,8 +59,10 @@ describe('team', () => {
it('fetches a site belonging to a team', async () => { it('fetches a site belonging to a team', async () => {
const site = await createSite(t, 'test.example.com') const site = await createSite(t, 'test.example.com')
const response = await t.get('/teams/:teamId/sites/:id', { const response = await t.get('/teams/:teamId/sites/:id', {
teamId: site.teamId, params: {
id: site.id, teamId: site.teamId,
id: site.id,
},
}) })
.expect(200) .expect(200)
expect(response.body!.id).toEqual(site.id) expect(response.body!.id).toEqual(site.id)
@ -67,7 +73,9 @@ describe('team', () => {
it('fetches all sites belonging to a team', async () => { it('fetches all sites belonging to a team', async () => {
const site = await createSite(t, 'test.example.com') const site = await createSite(t, 'test.example.com')
const response = await t.get('/teams/:teamId/sites', { const response = await t.get('/teams/:teamId/sites', {
teamId: site.teamId, params: {
teamId: site.teamId,
},
}) })
expect(response.body.map(s => s.id)).toContain(site.id) expect(response.body.map(s => s.id)).toContain(site.id)
}) })

View File

@ -5,6 +5,8 @@ import {Site} from '../entities/Site'
export class SiteService extends BaseService implements ISiteService { export class SiteService extends BaseService implements ISiteService {
async create(params: ISiteCreateParams) { async create(params: ISiteCreateParams) {
// TODO validate params.domain
// TODO check site limit per user // TODO check site limit per user
return this.getRepository(Site).save(params) return this.getRepository(Site).save(params)
} }

View File

@ -6,7 +6,9 @@ export async function createSite(t: RequestTester<IAPIDef>, domain: string) {
const team = await createTeam(t, 'test') const team = await createTeam(t, 'test')
const response = await t const response = await t
.post('/teams/:teamId/sites', { .post('/teams/:teamId/sites', {
teamId: team.id, params: {
teamId: team.id,
},
}) })
.send({ .send({
domain, domain,

View File

@ -1,40 +1,48 @@
// import {ISite, IStory} from '@rondo/common' import {ISite/*, IStory*/} from '@rondo/common'
// import {createTeam} from '../team/TeamTestUtils' import {createSite} from '../site/SiteTestUtils'
// import {test} from '../test' import {test} from '../test'
// describe('team', () => { describe('story', () => {
// test.withDatabase() test.withDatabase()
// const t = test.request('/api') const t = test.request('/api')
// let cookie!: string let cookie!: string
// let token!: string let token!: string
// let team!: ITeam let team!: ISite
// beforeEach(async () => { beforeEach(async () => {
// const session = await test.registerAccount() const session = await test.registerAccount()
// cookie = session.cookie cookie = session.cookie
// token = session.token token = session.token
// t.setHeaders({ cookie, 'x-csrf-token': token }) t.setHeaders({ cookie, 'x-csrf-token': token })
// team = await createTeam(t, 'test') team = await createSite(t, 'test.example.com')
// }) })
// describe('/stories/by-url', () => { const invalidUrl = 'https://invalid.example.com/test'
// it('returns undefined when a site is not configured', async () => { // const validUrl = 'https://test.example.com/test'
// }) describe('/stories/by-url', () => {
it('returns undefined when a site is not configured', async () => {
const response = await t
.get('/stories/by-url', {
query: { url: invalidUrl },
})
.expect(200)
expect(response.body).toEqual('')
})
// it('creates a story when it does not exist', async () => { it('creates a story when it does not exist', async () => {
// }) })
// it('retrieves existing story after it is created', async () => { it('retrieves existing story after it is created', async () => {
// }) })
// it('prevents unique exceptions', async () => { it('prevents unique exceptions', async () => {
// }) })
// }) })
// }) })

View File

@ -27,7 +27,9 @@ describe('team', () => {
const team = await createTeam(t, 'test') const team = await createTeam(t, 'test')
const response = await t const response = await t
.get('/teams/:id', { .get('/teams/:id', {
id: team.id, params: {
id: team.id,
},
}) })
.expect(200) .expect(200)
expect(response.body).toEqual(team) expect(response.body).toEqual(team)

View File

@ -1,7 +1,6 @@
import supertest from 'supertest' import supertest from 'supertest'
import { import {
IMethod, IMethod,
IRequestParams,
IRoutes, IRoutes,
URLFormatter, URLFormatter,
} from '@rondo/common' } from '@rondo/common'
@ -35,6 +34,15 @@ interface IRequest<
// type definition // type definition
} }
interface IRequestOptions<
R extends IRoutes,
P extends keyof R,
M extends IMethod,
> {
params?: R[P][M]['params'],
query?: R[P][M]['query'],
}
export interface IHeaders { export interface IHeaders {
[key: string]: string [key: string]: string
} }
@ -55,10 +63,10 @@ export class RequestTester<R extends IRoutes> {
} }
request<M extends IMethod, P extends keyof R & string>( request<M extends IMethod, P extends keyof R & string>(
method: M, path: P, params?: IRequestParams, method: M, path: P, options: IRequestOptions<R, P, 'post'> = {},
) )
: IRequest<R, P, M> { : IRequest<R, P, M> {
const url = this.formatter.format(path, params) const url = this.formatter.format(path, options.params, options.query)
const test = supertest(this.app)[method](`${this.baseUrl}${url}`) const test = supertest(this.app)[method](`${this.baseUrl}${url}`)
Object.keys(this.headers).forEach(key => { Object.keys(this.headers).forEach(key => {
test.set(key, this.headers[key]) test.set(key, this.headers[key])
@ -66,11 +74,17 @@ export class RequestTester<R extends IRoutes> {
return test return test
} }
get<P extends keyof R & string>(path: P, params?: IRequestParams) { get<P extends keyof R & string>(
return this.request('get', path, params) path: P,
options?: IRequestOptions<R, P, 'get'>,
) {
return this.request('get', path, options)
} }
post<P extends keyof R & string>(path: P, params?: IRequestParams) { post<P extends keyof R & string>(
return this.request('post', path, params) path: P,
options?: IRequestOptions<R, P, 'post'>,
) {
return this.request('post', path, options)
} }
} }