Skip to content

Commit

Permalink
feat: update to BDD Markdown v6 (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
coderbyheart authored Sep 11, 2023
1 parent 7c76431 commit ee7d15e
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 106 deletions.
5 changes: 5 additions & 0 deletions features/Webhook.feature.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
---
exampleContext:
webhookReceiver: https://example.com
---

# Demonstrate the Webhook Receiver

> As the author of a software component
Expand Down
4 changes: 2 additions & 2 deletions features/markdown-reporter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { markdownReporter } from '@nordicsemiconductor/bdd-markdown'

process.stdin.on('data', (data) => {
console.log(markdownReporter(JSON.parse(data.toString())))
process.stdin.on('data', async (data) => {
console.log(await markdownReporter(JSON.parse(data.toString())))
})
80 changes: 41 additions & 39 deletions features/steps/rest-steps.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,58 @@
import {
codeBlockOrThrow,
noMatch,
StepRunner,
StepRunnerArgs,
StepRunResult,
groupMatcher,
} from '@nordicsemiconductor/bdd-markdown'
import assert from 'assert/strict'
import fetch, { Response } from 'node-fetch'
import { World } from '../run-features.js'
import { Type } from '@sinclair/typebox'

export const steps = (): StepRunner<World>[] => {
let baseUrl: URL | undefined = undefined
let res: Response | undefined = undefined
return [
async ({ step }: StepRunnerArgs<World>): Promise<StepRunResult> => {
const match = /^the endpoint is `(?<endpoint>[^`]+)`$/.exec(step.title)
if (match === null) return noMatch
baseUrl = new URL(match.groups?.endpoint ?? '')
},
async ({
step,
log: {
step: { progress },
feature: { progress: featureProgress },
groupMatcher(
{
regExp: /^the endpoint is `(?<endpoint>[^`]+)`$/,
schema: Type.Object({ endpoint: Type.String() }),
},
}: StepRunnerArgs<World>): Promise<StepRunResult> => {
const match =
/^I (?<method>POST) to `(?<resource>[^`]+)` with this JSON$/.exec(
step.title,
)
if (match === null) return noMatch
const url = new URL(match.groups?.resource ?? '/', baseUrl).toString()
const method = match.groups?.method ?? 'GET'
progress(`${method} ${url}`)
const body = codeBlockOrThrow(step).code
progress(body)

res = await fetch(url, {
method,
body,
})
async ({ match: { endpoint } }) => {
baseUrl = new URL(endpoint)
},
),
groupMatcher(
{
regExp: /^I (?<method>POST) to `(?<resource>[^`]+)` with this JSON$/,
schema: Type.Object({ method: Type.String(), resource: Type.String() }),
},
async ({ match: { method, resource }, log: { progress }, step }) => {
const url = new URL(resource, baseUrl).toString()
progress(`${method} ${url}`)
const body = codeBlockOrThrow(step).code
progress(body)

progress(`${res.status} ${res.statusText}`)
featureProgress(`x-amzn-trace-id: ${res.headers.get('x-amzn-trace-id')}`)
},
async ({ step }: StepRunnerArgs<World>): Promise<StepRunResult> => {
const match = /^the response status code should be (?<code>[0-9]+)$/.exec(
step.title,
)
if (match === null) return noMatch
res = await fetch(url, {
method,
body,
})

assert.equal(res?.status, parseInt(match.groups?.code ?? '-1', 10))
},
progress(`${res.status} ${res.statusText}`)
progress(`x-amzn-trace-id: ${res.headers.get('x-amzn-trace-id')}`)
},
),
groupMatcher(
{
regExp: /^the response status code should be (?<code>[0-9]+)$/,
schema: Type.Object({ code: Type.Integer() }),
converters: {
code: (s) => parseInt(s, 10),
},

},
async ({ match: { code } }) => {
assert.equal(res?.status, code)
},
),
]
}
12 changes: 7 additions & 5 deletions features/steps/webhook-receiver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
ReceiveMessageCommand,
SQSClient,
} from '@aws-sdk/client-sqs'
import { Logger, Scenario } from '@nordicsemiconductor/bdd-markdown'
import { Logger } from '@nordicsemiconductor/bdd-markdown'

type WebhookRequest = {
headers: { [key: string]: string }
Expand Down Expand Up @@ -34,7 +34,7 @@ export class WebhookReceiver {
*/
async receiveWebhookRequest(
MessageGroupId: string,
log: Logger<Scenario>,
log: Logger,
): Promise<WebhookRequest> {
const { Messages } = await this.sqs.send(
new ReceiveMessageCommand({
Expand All @@ -46,10 +46,12 @@ export class WebhookReceiver {
}),
)

if (Messages === undefined || !Messages.length) {
const msg = Messages?.[0]

if (msg === undefined) {
throw new Error('No webhook request received!')
}
const { Body, MessageAttributes, ReceiptHandle, Attributes } = Messages[0]
const { Body, MessageAttributes, ReceiptHandle, Attributes } = msg
await this.sqs.send(
new DeleteMessageCommand({
QueueUrl: this.queueUrl,
Expand All @@ -59,7 +61,7 @@ export class WebhookReceiver {

if (Attributes === undefined || MessageAttributes === undefined)
throw new Error(
`No attributes defined in Message "${JSON.stringify(Messages[0])}"!`,
`No attributes defined in Message "${JSON.stringify(msg)}"!`,
)

const attrs = MessageAttributes
Expand Down
63 changes: 27 additions & 36 deletions features/steps/webhook-steps.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,44 @@
import {
codeBlockOrThrow,
noMatch,
groupMatcher,
StepRunner,
StepRunnerArgs,
StepRunResult,
} from '@nordicsemiconductor/bdd-markdown'
import assert from 'assert/strict'
import { World } from '../run-features.js'
import { WebhookReceiver } from './webhook-receiver.js'
import { Type } from '@sinclair/typebox'

export const steps = (): StepRunner<World>[] => {
let r: WebhookReceiver

return [
async ({
step,
log: { step: log },
context: { webhookQueue },
}: StepRunnerArgs<World>): Promise<StepRunResult> => {
if (!/^I have a Webhook Receiver$/.test(step.title)) return noMatch
log.progress(`Webhook queue: ${webhookQueue}`)
r = new WebhookReceiver({ queueUrl: webhookQueue })
await r.clearQueue()
{
match: (title) => /^I have a Webhook Receiver$/.test(title),
run: async ({ log, context: { webhookQueue } }) => {
log.progress(`Webhook queue: ${webhookQueue}`)
r = new WebhookReceiver({ queueUrl: webhookQueue })
await r.clearQueue()
},
},
async ({
step,
log: { scenario: log },
}: StepRunnerArgs<World>): Promise<StepRunResult> => {
const match =
/^the Webhook Receiver `(?<MessageGroupId>[^"]+)` should be called$/.exec(
step.title,
groupMatcher(
{
regExp:
/^the Webhook Receiver `(?<MessageGroupId>[^"]+)` should be called$/,
schema: Type.Object({ MessageGroupId: Type.String() }),
},
async ({ match: { MessageGroupId }, log }) => {
await r.receiveWebhookRequest(MessageGroupId, log)
},
),
{
match: (title) =>
/^the webhook request body should equal this JSON$/.test(title),
run: async ({ step }) => {
assert.deepEqual(
JSON.parse(codeBlockOrThrow(step).code),
r.latestWebhookRequest?.body,
)
if (match === null) return noMatch

const request = await r.receiveWebhookRequest(
match.groups?.MessageGroupId as string,
log,
)

return { result: request.body }
},
async ({ step }: StepRunnerArgs<World>): Promise<StepRunResult> => {
if (!/^the webhook request body should equal this JSON$/.test(step.title))
return noMatch

assert.deepEqual(
JSON.parse(codeBlockOrThrow(step).code),
r.latestWebhookRequest?.body,
)
},
},
]
}
25 changes: 15 additions & 10 deletions features/traceToMermaid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,21 @@ const suiteResult = await new Promise<SuiteResult>((resolve) =>
}),
)

for await (const [f, result] of suiteResult.results) {
const traceIds = result.logs
.filter(
({ level, message }) =>
level === LogLevel.PROGRESS &&
message.find((m) => m.startsWith('x-amzn-trace-id')),
)
.map(({ message }) => message)
.flat()
.map((s) => s.split(' ')[1].split(';')[0].split('=')[1])
for (const [f, featureResult] of suiteResult.results) {
const traceIds = featureResult.results.flatMap(([, scenarioResult]) =>
scenarioResult.results.flatMap(([, { logs }]) =>
logs
.filter(
({ level, message }) =>
level === LogLevel.PROGRESS &&
message.find((m) => m.startsWith('x-amzn-trace-id')),
)
.map(({ message }) => message)
.flat()
.map((s) => s.split(' ')[1].split(';')[0].split('=')[1]),
),
)

if (traceIds.length === 0) continue

const trace = await xray.send(
Expand Down
27 changes: 14 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@
"@aws-sdk/client-sqs": "3.409.0",
"@aws-sdk/client-xray": "3.409.0",
"@nordicsemiconductor/asset-tracker-cloud-code-style": "12.0.85",
"@nordicsemiconductor/bdd-markdown": "5.6.19",
"@nordicsemiconductor/bdd-markdown": "6.0.0",
"@nordicsemiconductor/cloudformation-helpers": "8.0.0",
"@sinclair/typebox": "0.31.14",
"@swc/core": "1.3.83",
"@swc/jest": "0.2.29",
"@types/aws-lambda": "8.10.119",
Expand Down

0 comments on commit ee7d15e

Please sign in to comment.