mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-12 23:35:52 +00:00
fix: Re-enable webfinger feature
Ok, so here is the plan. Let's give both our cucumber features and your cypress tests a prominent place to live. That would be the root level folder of our application. Second, let's revive formerly dead code step by step. Ie. move code from the former location `backend/features/` to `features/` when it is ready. All edge cases should be tested with unit tests in `backend/`, see my `webfinger.spec.js` as an example.
This commit is contained in:
parent
35c3219460
commit
7c6d5b5129
@ -8,13 +8,13 @@ addons:
|
|||||||
- docker
|
- docker
|
||||||
- chromium
|
- chromium
|
||||||
|
|
||||||
before_install:
|
install:
|
||||||
- yarn global add wait-on
|
- yarn global add wait-on
|
||||||
# Install Codecov
|
# Install Codecov
|
||||||
- yarn install
|
- yarn install
|
||||||
- cp cypress.env.template.json cypress.env.json
|
- cp cypress.env.template.json cypress.env.json
|
||||||
|
|
||||||
install:
|
before_script:
|
||||||
- docker-compose -f docker-compose.yml build --parallel
|
- docker-compose -f docker-compose.yml build --parallel
|
||||||
- docker-compose -f docker-compose.yml -f docker-compose.build-and-test.yml build # just tagging, just be quite fast
|
- docker-compose -f docker-compose.yml -f docker-compose.build-and-test.yml build # just tagging, just be quite fast
|
||||||
- docker-compose -f docker-compose.yml -f docker-compose.build-and-test.yml up -d
|
- docker-compose -f docker-compose.yml -f docker-compose.build-and-test.yml up -d
|
||||||
@ -30,10 +30,6 @@ script:
|
|||||||
- docker-compose exec backend yarn run test --ci --verbose=false --coverage
|
- docker-compose exec backend yarn run test --ci --verbose=false --coverage
|
||||||
- docker-compose exec backend yarn run db:seed
|
- docker-compose exec backend yarn run db:seed
|
||||||
- docker-compose exec backend yarn run db:reset
|
- docker-compose exec backend yarn run db:reset
|
||||||
# ActivityPub cucumber testing temporarily disabled because it's too buggy
|
|
||||||
# - docker-compose exec backend yarn run test:cucumber --tags "not @wip"
|
|
||||||
# - docker-compose exec backend yarn run db:reset
|
|
||||||
# - docker-compose exec backend yarn run db:seed
|
|
||||||
# Frontend
|
# Frontend
|
||||||
- docker-compose exec webapp yarn run lint
|
- docker-compose exec webapp yarn run lint
|
||||||
- docker-compose exec webapp yarn run test --ci --verbose=false --coverage
|
- docker-compose exec webapp yarn run test --ci --verbose=false --coverage
|
||||||
@ -42,6 +38,7 @@ script:
|
|||||||
- docker-compose -f docker-compose.yml up -d
|
- docker-compose -f docker-compose.yml up -d
|
||||||
- wait-on http://localhost:7474
|
- wait-on http://localhost:7474
|
||||||
- yarn run cypress:run --record
|
- yarn run cypress:run --record
|
||||||
|
- yarn run cucumber
|
||||||
# Coverage
|
# Coverage
|
||||||
- yarn run codecov
|
- yarn run codecov
|
||||||
|
|
||||||
|
|||||||
12
babel.config.json
Normal file
12
babel.config.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
[
|
||||||
|
"@babel/preset-env",
|
||||||
|
{
|
||||||
|
"targets": {
|
||||||
|
"node": "10"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -10,8 +10,6 @@
|
|||||||
"dev:debug": "nodemon --exec babel-node --inspect=0.0.0.0:9229 src/index.js -e js,gql",
|
"dev:debug": "nodemon --exec babel-node --inspect=0.0.0.0:9229 src/index.js -e js,gql",
|
||||||
"lint": "eslint src --config .eslintrc.js",
|
"lint": "eslint src --config .eslintrc.js",
|
||||||
"test": "jest --forceExit --detectOpenHandles --runInBand",
|
"test": "jest --forceExit --detectOpenHandles --runInBand",
|
||||||
"test:cucumber:cmd": "wait-on tcp:4001 tcp:4123 && cucumber-js --require-module @babel/register --exit test/",
|
|
||||||
"test:cucumber": " cross-env CLIENT_URI=http://localhost:4123 run-p --race test:before:* 'test:cucumber:cmd {@}' --",
|
|
||||||
"db:reset": "babel-node src/seed/reset-db.js",
|
"db:reset": "babel-node src/seed/reset-db.js",
|
||||||
"db:seed": "babel-node src/seed/seed-db.js"
|
"db:seed": "babel-node src/seed/seed-db.js"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,27 +1,29 @@
|
|||||||
import user from './user'
|
import user from './user'
|
||||||
import inbox from './inbox'
|
import inbox from './inbox'
|
||||||
import webFinger from './webFinger'
|
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import cors from 'cors'
|
import cors from 'cors'
|
||||||
import verify from './verify'
|
import verify from './verify'
|
||||||
|
|
||||||
const router = express.Router()
|
export default function() {
|
||||||
|
const router = express.Router()
|
||||||
router.use('/.well-known/webFinger', cors(), express.urlencoded({ extended: true }), webFinger)
|
router.use(
|
||||||
router.use(
|
'/activitypub/users',
|
||||||
'/activitypub/users',
|
cors(),
|
||||||
cors(),
|
express.json({
|
||||||
express.json({ type: ['application/activity+json', 'application/ld+json', 'application/json'] }),
|
type: ['application/activity+json', 'application/ld+json', 'application/json'],
|
||||||
express.urlencoded({ extended: true }),
|
}),
|
||||||
user,
|
express.urlencoded({ extended: true }),
|
||||||
)
|
user,
|
||||||
router.use(
|
)
|
||||||
'/activitypub/inbox',
|
router.use(
|
||||||
cors(),
|
'/activitypub/inbox',
|
||||||
express.json({ type: ['application/activity+json', 'application/ld+json', 'application/json'] }),
|
cors(),
|
||||||
express.urlencoded({ extended: true }),
|
express.json({
|
||||||
verify,
|
type: ['application/activity+json', 'application/ld+json', 'application/json'],
|
||||||
inbox,
|
}),
|
||||||
)
|
express.urlencoded({ extended: true }),
|
||||||
|
verify,
|
||||||
export default router
|
inbox,
|
||||||
|
)
|
||||||
|
return router
|
||||||
|
}
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
import express from 'express'
|
|
||||||
import { createWebFinger } from '../utils/actor'
|
|
||||||
import gql from 'graphql-tag'
|
|
||||||
|
|
||||||
const router = express.Router()
|
|
||||||
|
|
||||||
router.get('/', async function(req, res) {
|
|
||||||
const resource = req.query.resource
|
|
||||||
if (!resource || !resource.includes('acct:')) {
|
|
||||||
return res
|
|
||||||
.status(400)
|
|
||||||
.send(
|
|
||||||
'Bad request. Please make sure "acct:USER@DOMAIN" is what you are sending as the "resource" query parameter.',
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
const nameAndDomain = resource.replace('acct:', '')
|
|
||||||
const name = nameAndDomain.split('@')[0]
|
|
||||||
|
|
||||||
let result
|
|
||||||
try {
|
|
||||||
result = await req.app.get('ap').dataSource.client.query({
|
|
||||||
query: gql`
|
|
||||||
query {
|
|
||||||
User(slug: "${name}") {
|
|
||||||
slug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
return res.status(500).json({ error })
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.data && result.data.User.length > 0) {
|
|
||||||
const webFinger = createWebFinger(name)
|
|
||||||
return res.contentType('application/jrd+json').json(webFinger)
|
|
||||||
} else {
|
|
||||||
return res.status(404).json({ error: `No record found for ${nameAndDomain}.` })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default router
|
|
||||||
59
backend/src/activitypub/routes/webfinger.js
Normal file
59
backend/src/activitypub/routes/webfinger.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import express from 'express'
|
||||||
|
import CONFIG from '../../config/'
|
||||||
|
import cors from 'cors'
|
||||||
|
|
||||||
|
const debug = require('debug')('ea:webfinger')
|
||||||
|
const regex = /acct:([a-z0-9_-]*)@([a-z0-9_-]*)/
|
||||||
|
|
||||||
|
const createWebFinger = name => {
|
||||||
|
const { host } = new URL(CONFIG.CLIENT_URI)
|
||||||
|
return {
|
||||||
|
subject: `acct:${name}@${host}`,
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
rel: 'self',
|
||||||
|
type: 'application/activity+json',
|
||||||
|
href: `${CONFIG.CLIENT_URI}/activitypub/users/${name}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function handler(req, res) {
|
||||||
|
const { resource = '' } = req.query
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
const [_, name, domain] = resource.match(regex) || []
|
||||||
|
if (!(name && domain))
|
||||||
|
return res.status(400).json({
|
||||||
|
error: 'Query parameter "?resource=acct:<USER>@<DOMAIN>" is missing.',
|
||||||
|
})
|
||||||
|
|
||||||
|
const session = req.app.get('driver').session()
|
||||||
|
try {
|
||||||
|
const [slug] = await session.readTransaction(async t => {
|
||||||
|
const result = await t.run('MATCH (u:User {slug: $slug}) RETURN u.slug AS slug', {
|
||||||
|
slug: name,
|
||||||
|
})
|
||||||
|
return result.records.map(record => record.get('slug'))
|
||||||
|
})
|
||||||
|
if (!slug)
|
||||||
|
return res.status(404).json({
|
||||||
|
error: `No record found for "${name}@${domain}".`,
|
||||||
|
})
|
||||||
|
const webFinger = createWebFinger(name)
|
||||||
|
return res.contentType('application/jrd+json').json(webFinger)
|
||||||
|
} catch (error) {
|
||||||
|
debug(error)
|
||||||
|
return res.status(500).json({
|
||||||
|
error: 'Something went terribly wrong. Please contact support@human-connection.org',
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
session.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function() {
|
||||||
|
const router = express.Router()
|
||||||
|
router.use('/webfinger', cors(), express.urlencoded({ extended: true }), handler)
|
||||||
|
return router
|
||||||
|
}
|
||||||
117
backend/src/activitypub/routes/webfinger.spec.js
Normal file
117
backend/src/activitypub/routes/webfinger.spec.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import { handler } from './webfinger'
|
||||||
|
import Factory from '../../seed/factories'
|
||||||
|
import { getDriver } from '../../bootstrap/neo4j'
|
||||||
|
|
||||||
|
let resource
|
||||||
|
let res
|
||||||
|
let json
|
||||||
|
let status
|
||||||
|
let contentType
|
||||||
|
|
||||||
|
const factory = Factory()
|
||||||
|
const driver = getDriver()
|
||||||
|
|
||||||
|
const request = () => {
|
||||||
|
json = jest.fn()
|
||||||
|
status = jest.fn(() => ({ json }))
|
||||||
|
contentType = jest.fn(() => ({ json }))
|
||||||
|
res = { status, contentType }
|
||||||
|
const req = {
|
||||||
|
app: {
|
||||||
|
get: key => {
|
||||||
|
return {
|
||||||
|
driver,
|
||||||
|
}[key]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
resource,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return handler(req, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await factory.cleanDatabase()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('webfinger', () => {
|
||||||
|
describe('no ressource', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
resource = undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sends HTTP 400', async () => {
|
||||||
|
await request()
|
||||||
|
expect(status).toHaveBeenCalledWith(400)
|
||||||
|
expect(json).toHaveBeenCalledWith({
|
||||||
|
error: 'Query parameter "?resource=acct:<USER>@<DOMAIN>" is missing.',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('?ressource query param', () => {
|
||||||
|
describe('is missing acct:', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
resource = 'some-user@domain'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sends HTTP 400', async () => {
|
||||||
|
await request()
|
||||||
|
expect(status).toHaveBeenCalledWith(400)
|
||||||
|
expect(json).toHaveBeenCalledWith({
|
||||||
|
error: 'Query parameter "?resource=acct:<USER>@<DOMAIN>" is missing.',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('has no domain', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
resource = 'acct:some-user@'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sends HTTP 400', async () => {
|
||||||
|
await request()
|
||||||
|
expect(status).toHaveBeenCalledWith(400)
|
||||||
|
expect(json).toHaveBeenCalledWith({
|
||||||
|
error: 'Query parameter "?resource=acct:<USER>@<DOMAIN>" is missing.',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with acct:', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
resource = 'acct:some-user@domain'
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns empty json', async () => {
|
||||||
|
await request()
|
||||||
|
expect(status).toHaveBeenCalledWith(404)
|
||||||
|
expect(json).toHaveBeenCalledWith({
|
||||||
|
error: 'No record found for "some-user@domain".',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('given a user for acct', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await factory.create('User', { slug: 'some-user' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns user object', async () => {
|
||||||
|
await request()
|
||||||
|
expect(contentType).toHaveBeenCalledWith('application/jrd+json')
|
||||||
|
expect(json).toHaveBeenCalledWith({
|
||||||
|
links: [
|
||||||
|
{
|
||||||
|
href: 'http://localhost:3000/activitypub/users/some-user',
|
||||||
|
rel: 'self',
|
||||||
|
type: 'application/activity+json',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
subject: 'acct:some-user@localhost:3000',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -22,17 +22,3 @@ export function createActor(name, pubkey) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createWebFinger(name) {
|
|
||||||
const { host } = new URL(activityPub.endpoint)
|
|
||||||
return {
|
|
||||||
subject: `acct:${name}@${host}`,
|
|
||||||
links: [
|
|
||||||
{
|
|
||||||
rel: 'self',
|
|
||||||
type: 'application/activity+json',
|
|
||||||
href: `${activityPub.endpoint}/activitypub/users/${name}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import dotenv from 'dotenv'
|
import dotenv from 'dotenv'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
dotenv.config()
|
dotenv.config({ path: path.resolve(__dirname, '../../.env') })
|
||||||
|
|
||||||
const {
|
const {
|
||||||
MAPBOX_TOKEN,
|
MAPBOX_TOKEN,
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import middleware from './middleware'
|
|||||||
import { neode as getNeode, getDriver } from './bootstrap/neo4j'
|
import { neode as getNeode, getDriver } from './bootstrap/neo4j'
|
||||||
import decode from './jwt/decode'
|
import decode from './jwt/decode'
|
||||||
import schema from './schema'
|
import schema from './schema'
|
||||||
|
import webfinger from './activitypub/routes/webfinger'
|
||||||
|
|
||||||
// check required configs and throw error
|
// check required configs and throw error
|
||||||
// TODO check this directly in config file - currently not possible due to testsetup
|
// TODO check this directly in config file - currently not possible due to testsetup
|
||||||
@ -41,7 +42,10 @@ const createServer = options => {
|
|||||||
const server = new ApolloServer(Object.assign({}, defaults, options))
|
const server = new ApolloServer(Object.assign({}, defaults, options))
|
||||||
|
|
||||||
const app = express()
|
const app = express()
|
||||||
|
|
||||||
|
app.set('driver', driver)
|
||||||
app.use(helmet())
|
app.use(helmet())
|
||||||
|
app.use('/.well-known/', webfinger())
|
||||||
app.use(express.static('public'))
|
app.use(express.static('public'))
|
||||||
server.applyMiddleware({ app, path: '/' })
|
server.applyMiddleware({ app, path: '/' })
|
||||||
|
|
||||||
|
|||||||
@ -9,32 +9,6 @@ Feature: Webfinger discovery
|
|||||||
| Slug |
|
| Slug |
|
||||||
| peter-lustiger |
|
| peter-lustiger |
|
||||||
|
|
||||||
Scenario: Search
|
|
||||||
When I send a GET request to "/.well-known/webfinger?resource=acct:peter-lustiger@localhost"
|
|
||||||
Then I receive the following json:
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"subject": "acct:peter-lustiger@localhost:4123",
|
|
||||||
"links": [
|
|
||||||
{
|
|
||||||
"rel": "self",
|
|
||||||
"type": "application/activity+json",
|
|
||||||
"href": "http://localhost:4123/activitypub/users/peter-lustiger"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
And I expect the Content-Type to be "application/jrd+json; charset=utf-8"
|
|
||||||
|
|
||||||
Scenario: User does not exist
|
|
||||||
When I send a GET request to "/.well-known/webfinger?resource=acct:nonexisting@localhost"
|
|
||||||
Then I receive the following json:
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"error": "No record found for nonexisting@localhost."
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Receiving an actor object
|
Scenario: Receiving an actor object
|
||||||
When I send a GET request to "/activitypub/users/peter-lustiger"
|
When I send a GET request to "/activitypub/users/peter-lustiger"
|
||||||
Then I receive the following json:
|
Then I receive the following json:
|
||||||
|
|||||||
@ -9,7 +9,7 @@ open your minikube dashboard:
|
|||||||
$ minikube dashboard
|
$ minikube dashboard
|
||||||
```
|
```
|
||||||
|
|
||||||
This will give you an overview. Some of the steps below need some timing to make ressources available to other dependent deployments. Keeping an eye on the dashboard is a great way to check that.
|
This will give you an overview. Some of the steps below need some timing to make resources available to other dependent deployments. Keeping an eye on the dashboard is a great way to check that.
|
||||||
|
|
||||||
Follow the installation instruction for [Human Connection](../human-connection/README.md).
|
Follow the installation instruction for [Human Connection](../human-connection/README.md).
|
||||||
If all the pods and services have settled and everything looks green in your
|
If all the pods and services have settled and everything looks green in your
|
||||||
|
|||||||
45
features/support/steps.js
Normal file
45
features/support/steps.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// features/support/steps.js
|
||||||
|
import { Given, When, Then, After, AfterAll } from 'cucumber'
|
||||||
|
import Factory from '../../backend/src/seed/factories'
|
||||||
|
import dotenv from 'dotenv'
|
||||||
|
import expect from 'expect'
|
||||||
|
|
||||||
|
const debug = require('debug')('ea:test:steps')
|
||||||
|
const factory = Factory()
|
||||||
|
|
||||||
|
|
||||||
|
After(async () => {
|
||||||
|
await factory.cleanDatabase()
|
||||||
|
})
|
||||||
|
|
||||||
|
Given('our CLIENT_URI is {string}', function (string) {
|
||||||
|
expect(process.env.CLIENT_URI).toEqual(string)
|
||||||
|
});
|
||||||
|
|
||||||
|
Given('we have the following users in our database:', function (dataTable) {
|
||||||
|
return Promise.all(dataTable.hashes().map(({ slug, name }) => {
|
||||||
|
return factory.create('User', {
|
||||||
|
name,
|
||||||
|
slug,
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
When('I send a GET request to {string}', async function (pathname) {
|
||||||
|
const response = await this.get(pathname)
|
||||||
|
this.lastContentType = response.lastContentType
|
||||||
|
|
||||||
|
this.lastResponses.push(response.lastResponse)
|
||||||
|
this.statusCode = response.statusCode
|
||||||
|
})
|
||||||
|
|
||||||
|
Then('the server responds with a HTTP Status {int} and the following json:', function (statusCode, docString) {
|
||||||
|
expect(this.statusCode).toEqual(statusCode)
|
||||||
|
const [ lastResponse ] = this.lastResponses
|
||||||
|
expect(JSON.parse(lastResponse)).toMatchObject(JSON.parse(docString))
|
||||||
|
})
|
||||||
|
|
||||||
|
Then('the Content-Type is {string}', function (contentType) {
|
||||||
|
expect(this.lastContentType).toEqual(contentType)
|
||||||
|
})
|
||||||
|
|
||||||
36
features/webfinger.feature
Normal file
36
features/webfinger.feature
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
Feature: Webfinger discovery
|
||||||
|
From an external server, e.g. Mastodon
|
||||||
|
I want to search for an actor alias
|
||||||
|
In order to follow the actor
|
||||||
|
|
||||||
|
Background:
|
||||||
|
Given our CLIENT_URI is "http://localhost:3000"
|
||||||
|
And we have the following users in our database:
|
||||||
|
| name | slug |
|
||||||
|
| Peter Lustiger | peter-lustiger |
|
||||||
|
|
||||||
|
Scenario: Search a user
|
||||||
|
When I send a GET request to "/.well-known/webfinger?resource=acct:peter-lustiger@localhost"
|
||||||
|
Then the server responds with a HTTP Status 200 and the following json:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"subject": "acct:peter-lustiger@localhost:3000",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"rel": "self",
|
||||||
|
"type": "application/activity+json",
|
||||||
|
"href": "http://localhost:3000/activitypub/users/peter-lustiger"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
And the Content-Type is "application/jrd+json; charset=utf-8"
|
||||||
|
|
||||||
|
Scenario: Search without result
|
||||||
|
When I send a GET request to "/.well-known/webfinger?resource=acct:nonexisting@localhost"
|
||||||
|
Then the server responds with a HTTP Status 404 and the following json:
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"error": "No record found for \"nonexisting@localhost\"."
|
||||||
|
}
|
||||||
|
"""
|
||||||
38
features/world.js
Normal file
38
features/world.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { setWorldConstructor } from 'cucumber'
|
||||||
|
import request from 'request'
|
||||||
|
|
||||||
|
class CustomWorld {
|
||||||
|
constructor () {
|
||||||
|
// webFinger.feature
|
||||||
|
this.lastResponses = []
|
||||||
|
this.lastContentType = null
|
||||||
|
this.lastInboxUrl = null
|
||||||
|
this.lastActivity = null
|
||||||
|
// object-article.feature
|
||||||
|
this.statusCode = null
|
||||||
|
}
|
||||||
|
get (pathname) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
request(`http://localhost:4000/${this.replaceSlashes(pathname)}`, {
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/activity+json'
|
||||||
|
}}, (error, response, body) => {
|
||||||
|
if (!error) {
|
||||||
|
resolve({
|
||||||
|
lastResponse: body,
|
||||||
|
lastContentType: response.headers['content-type'],
|
||||||
|
statusCode: response.statusCode
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
reject(error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
replaceSlashes (pathname) {
|
||||||
|
return pathname.replace(/^\/+/, '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setWorldConstructor(CustomWorld)
|
||||||
11
package.json
11
package.json
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "nitro-cypress",
|
"name": "human-connection",
|
||||||
"version": "0.1.11",
|
"version": "0.1.11",
|
||||||
"description": "Fullstack tests with cypress for Human Connection",
|
"description": "Fullstack and API tests with cypress and cucumber for Human Connection",
|
||||||
"author": "Human Connection gGmbh",
|
"author": "Human Connection gGmbh",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"cypress-cucumber-preprocessor": {
|
"cypress-cucumber-preprocessor": {
|
||||||
@ -16,19 +16,26 @@
|
|||||||
"cypress:setup": "run-p cypress:backend cypress:webapp",
|
"cypress:setup": "run-p cypress:backend cypress:webapp",
|
||||||
"cypress:run": "cross-env cypress run --browser chromium",
|
"cypress:run": "cross-env cypress run --browser chromium",
|
||||||
"cypress:open": "cross-env cypress open --browser chromium",
|
"cypress:open": "cross-env cypress open --browser chromium",
|
||||||
|
"cucumber:setup": "cd backend && yarn run dev",
|
||||||
|
"cucumber": "wait-on tcp:4000 && cucumber-js --require-module @babel/register --exit",
|
||||||
"version": "auto-changelog -p"
|
"version": "auto-changelog -p"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.7.2",
|
||||||
|
"@babel/preset-env": "^7.7.4",
|
||||||
|
"@babel/register": "^7.7.4",
|
||||||
"auto-changelog": "^1.16.2",
|
"auto-changelog": "^1.16.2",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"codecov": "^3.6.1",
|
"codecov": "^3.6.1",
|
||||||
"cross-env": "^6.0.3",
|
"cross-env": "^6.0.3",
|
||||||
|
"cucumber": "^6.0.5",
|
||||||
"cypress": "^3.7.0",
|
"cypress": "^3.7.0",
|
||||||
"cypress-cucumber-preprocessor": "^1.17.0",
|
"cypress-cucumber-preprocessor": "^1.17.0",
|
||||||
"cypress-file-upload": "^3.5.0",
|
"cypress-file-upload": "^3.5.0",
|
||||||
"cypress-plugin-retries": "^1.5.0",
|
"cypress-plugin-retries": "^1.5.0",
|
||||||
"date-fns": "^2.8.1",
|
"date-fns": "^2.8.1",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
|
"expect": "^24.9.0",
|
||||||
"faker": "Marak/faker.js#master",
|
"faker": "Marak/faker.js#master",
|
||||||
"graphql-request": "^1.8.2",
|
"graphql-request": "^1.8.2",
|
||||||
"neo4j-driver": "^1.7.6",
|
"neo4j-driver": "^1.7.6",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user