Skip to content

Commit

Permalink
feat(cli): Generate full client test suite and improve typed client (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
daffl authored Oct 12, 2022
1 parent f3ddab6 commit 57119b6
Show file tree
Hide file tree
Showing 25 changed files with 27,395 additions and 11,081 deletions.
38,088 changes: 27,156 additions & 10,932 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions packages/authentication/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"access": "public"
},
"dependencies": {
"@feathersjs/hooks": "^0.7.5",
"@feathersjs/commons": "^5.0.0-pre.30",
"@feathersjs/errors": "^5.0.0-pre.30",
"@feathersjs/feathers": "^5.0.0-pre.30",
Expand Down
24 changes: 13 additions & 11 deletions packages/authentication/src/service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import merge from 'lodash/merge'
import { NotAuthenticated } from '@feathersjs/errors'
import { AuthenticationBase, AuthenticationResult, AuthenticationRequest, AuthenticationParams } from './core'
import { connection, event } from './hooks'
import '@feathersjs/transport-commons'
import { createDebug } from '@feathersjs/commons'
import { ServiceMethods, ServiceAddons } from '@feathersjs/feathers'
import { resolveDispatch } from '@feathersjs/schema'
import jsonwebtoken from 'jsonwebtoken'
import { hooks } from '@feathersjs/hooks'

import { AuthenticationBase, AuthenticationResult, AuthenticationRequest, AuthenticationParams } from './core'
import { connection, event } from './hooks'

const debug = createDebug('@feathersjs/authentication/service')

Expand Down Expand Up @@ -39,6 +41,15 @@ export class AuthenticationService
constructor(app: any, configKey = 'authentication', options = {}) {
super(app, configKey, options)

hooks(this, {
create: [resolveDispatch(), connection('login'), event('login')],
remove: [resolveDispatch(), connection('logout'), event('logout')]
})

this.app.on('disconnect', async (connection) => {
await this.handleConnection('disconnect', connection)
})

if (typeof app.defaultAuthentication !== 'function') {
app.defaultAuthentication = function (location?: string) {
const configKey = app.get('defaultAuthentication')
Expand Down Expand Up @@ -185,15 +196,6 @@ export class AuthenticationService
}
}

this.hooks({
create: [resolveDispatch(), connection('login'), event('login')],
remove: [resolveDispatch(), connection('logout'), event('logout')]
} as any)

this.app.on('disconnect', async (connection) => {
await this.handleConnection('disconnect', connection)
})

if (typeof this.publish === 'function') {
this.publish(() => null)
}
Expand Down
4 changes: 2 additions & 2 deletions packages/authentication/test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ export class Strategy1 extends AuthenticationBaseStrategy {

async authenticate(authentication: AuthenticationRequest) {
if (authentication.username === 'David' || authentication.both) {
return Strategy1.result
return { ...Strategy1.result }
}

throw new NotAuthenticated('Invalid Dave')
}

async parse(req: MockRequest) {
if (req.isDave) {
return Strategy1.result
return { ...Strategy1.result }
}

return null
Expand Down
29 changes: 15 additions & 14 deletions packages/authentication/test/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,20 +212,21 @@ describe('authentication/service', () => {
assert.deepStrictEqual(authResult, Strategy1.result)
})

it('passes when id is set and does not match accessToken', async () => {
try {
await app.service('authentication').remove('test', {
authentication: {
strategy: 'first',
username: 'David',
accessToken: 'testing'
}
})
assert.fail('Should never get here')
} catch (error: any) {
assert.strictEqual(error.name, 'NotAuthenticated')
assert.strictEqual(error.message, 'Invalid access token')
}
it('fails when id is set and does not match accessToken', async () => {
await assert.rejects(
() =>
app.service('authentication').remove('test', {
authentication: {
strategy: 'first',
username: 'David',
accessToken: 'testing'
}
}),
{
name: 'NotAuthenticated',
message: 'Invalid access token'
}
)
})

it('errors when trying to remove with nothing', async () => {
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,14 @@
"@feathersjs/authentication": "^5.0.0-pre.30",
"@feathersjs/authentication-local": "^5.0.0-pre.30",
"@feathersjs/authentication-oauth": "^5.0.0-pre.30",
"@feathersjs/authentication-client": "^5.0.0-pre.30",
"@feathersjs/configuration": "^5.0.0-pre.30",
"@feathersjs/errors": "^5.0.0-pre.30",
"@feathersjs/express": "^5.0.0-pre.30",
"@feathersjs/feathers": "^5.0.0-pre.30",
"@feathersjs/knex": "^5.0.0-pre.30",
"@feathersjs/koa": "^5.0.0-pre.30",
"@feathersjs/rest-client": "^5.0.0-pre.30",
"@feathersjs/mongodb": "^5.0.0-pre.30",
"@feathersjs/schema": "^5.0.0-pre.30",
"@feathersjs/socketio": "^5.0.0-pre.30",
Expand Down
11 changes: 10 additions & 1 deletion packages/cli/src/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,16 @@ export const generate = (ctx: AppGeneratorArguments) =>
.then(
install<AppGeneratorContext>(
({ language, framework, devDependencies, dependencyVersions }) => {
devDependencies.push('nodemon', 'axios', 'mocha', 'cross-env', 'prettier', '@feathersjs/cli')
devDependencies.push(
'nodemon',
'axios',
'mocha',
'cross-env',
'prettier',
'@feathersjs/cli',
'@feathersjs/rest-client',
'@feathersjs/authentication-client'
)

if (language === 'ts') {
devDependencies.push(
Expand Down
26 changes: 26 additions & 0 deletions packages/cli/src/app/templates/client.test.tpl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { generator, toFile } from '@feathershq/pinion'
import { renderSource } from '../../commons'
import { AppGeneratorContext } from '../index'

const template = ({ lib }: AppGeneratorContext) => /* ts */ `import assert from 'assert'
import axios from 'axios'
import type { Server } from 'http'
import { app } from '../${lib}/app'
import { createClient } from '../${lib}/client'
import rest from '@feathersjs/rest-client'
const port = app.get('port')
const appUrl = \`http://\${app.get('host')}:\${port}\`
describe('client tests', () => {
const client = createClient(rest(appUrl).axios(axios))
it('initialized the client', () => {
assert.ok(client)
})
})
`

export const generate = (ctx: AppGeneratorContext) =>
generator(ctx).then(renderSource(template, toFile('test', 'client.test')))
2 changes: 1 addition & 1 deletion packages/cli/src/app/templates/client.tpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { renderSource } from '../../commons'
import { AppGeneratorContext } from '../index'

const template = ({}: AppGeneratorContext) => /* ts */ `import { feathers } from '@feathersjs/feathers'
import type { Paginated, ClientService, TransportConnection, Params } from '@feathersjs/feathers'
import type { TransportConnection, Params } from '@feathersjs/feathers'
export interface ServiceTypes {
//
Expand Down
80 changes: 80 additions & 0 deletions packages/cli/src/authentication/templates/client.test.tpl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { generator, toFile } from '@feathershq/pinion'
import { renderSource } from '../../commons'
import { AuthenticationGeneratorContext } from '../index'

const template = ({
authStrategies,
upperName,
type,
lib
}: AuthenticationGeneratorContext) => /* ts */ `import assert from 'assert'
import axios from 'axios'
import rest from '@feathersjs/rest-client'
${
authStrategies.includes('local')
? `import authenticationClient from '@feathersjs/authentication-client'`
: ''
}
import { app } from '../${lib}/app'
import { createClient } from '../${lib}/client'
${authStrategies.includes('local') ? `import type { ${upperName}Data } from '../${lib}/client'` : ''}
const port = app.get('port')
const appUrl = \`http://\${app.get('host')}:\${port}\`
describe('application client tests', () => {
const client = createClient(rest(appUrl).axios(axios))
client.configure(authenticationClient())
before(async () => {
await app.listen(port)
})
after(async () => {
await app.teardown()
})
it('initialized the client', () => {
assert.ok(client)
})
${
authStrategies.includes('local')
? `
it('creates and authenticates a user with email and password', async () => {
const userData: ${upperName}Data = {
email: 'someone@example.com',
password: 'supersecret'
}
await client.service('users').create(userData)
const { user, accessToken } = await client.authenticate({
strategy: 'local',
...userData
})
assert.ok(accessToken, 'Created access token for user')
assert.ok(user, 'Includes user in authentication data')
assert.strictEqual(user.password, undefined, 'Password is hidden to clients')
await client.logout()
// Remove the test user on the server
await app.service('users').remove(user.${type === 'mongodb' ? '_id' : 'id'})
})`
: ''
}
})
`

export const generate = (ctx: AuthenticationGeneratorContext) =>
generator(ctx).then(
renderSource(
template,
toFile<AuthenticationGeneratorContext>(({ test }) => test, 'client.test'),
{ force: true }
)
)
19 changes: 19 additions & 0 deletions packages/cli/src/authentication/templates/client.tpl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { generator, toFile, after, when } from '@feathershq/pinion'
import { injectSource } from '../../commons'
import { ServiceGeneratorContext } from '../../service'

const importTemplate = /* ts */ `import type { AuthenticationService } from '@feathersjs/authentication'
`
const declarationTemplate = ` authentication: Pick<AuthenticationService, 'create' | 'remove'>`

const toClientFile = toFile<ServiceGeneratorContext>(({ lib }) => [lib, 'client'])

export const generate = async (ctx: ServiceGeneratorContext) =>
generator(ctx)
.then(injectSource(importTemplate, after("from '@feathersjs/feathers'"), toClientFile))
.then(
when(
({ language }) => language === 'ts',
injectSource(declarationTemplate, after('export interface ServiceTypes'), toClientFile)
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const importTemplate = ({
fileName
}: AuthenticationGeneratorContext) => /* ts */ `import { ${upperName} } from './services/${folder.join(
'/'
)}/${fileName}.schema'
)}/${fileName}'
`

const paramsTemplate = ({
Expand Down
53 changes: 0 additions & 53 deletions packages/cli/src/authentication/templates/test.tpl.ts

This file was deleted.

Loading

0 comments on commit 57119b6

Please # to comment.