From 2049534d902baab3862eb63851df2302784c93ac Mon Sep 17 00:00:00 2001 From: Maksim Stepanov <17935127+delatrie@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:09:20 +0700 Subject: [PATCH] feat(reader): cucumber json reader WIP (via #21) --- packages/reader/src/allure1/index.ts | 11 +- packages/reader/src/allure2/index.ts | 10 +- packages/reader/src/cucumberjson/index.ts | 443 ++++++ packages/reader/src/cucumberjson/model.ts | 71 + packages/reader/src/index.ts | 1 + packages/reader/src/junitxml/index.ts | 3 +- packages/reader/src/utils.ts | 46 + packages/reader/src/xml-utils.ts | 21 - packages/reader/test/cucumberjson.test.ts | 1297 +++++++++++++++++ .../behave/stepNames/noSpaceAfterKeyword.json | 28 + .../cucumberjvm/embeddings/nameInvalid.json | 31 + .../cucumberjvm/embeddings/named.json | 31 + .../reference/backgrounds/wellDefined.json | 41 + .../reference/dataTables/cellInvalid.json | 23 + .../reference/dataTables/cellsInvalid.json | 23 + .../reference/dataTables/cellsMissing.json | 23 + .../reference/dataTables/quotes.json | 23 + .../reference/dataTables/rowInvalid.json | 23 + .../reference/dataTables/rowsInvalid.json | 23 + .../reference/dataTables/wellDefined.json | 23 + .../reference/descriptions/invalid.json | 17 + .../reference/descriptions/valid.json | 17 + .../docstrings/emptyContentType.json | 29 + .../reference/docstrings/emptyValue.json | 28 + .../docstrings/explicitContentType.json | 29 + .../docstrings/missingContentType.json | 28 + .../reference/docstrings/missingValue.json | 26 + .../docstrings/whitespaceOnlyValue.json | 28 + .../reference/durations/allDefined.json | 34 + .../reference/durations/noneDefined.json | 39 + .../reference/durations/oneInvalid.json | 42 + .../reference/durations/oneMissing.json | 41 + .../reference/durations/roundDown.json | 26 + .../reference/durations/roundUp.json | 26 + .../reference/durations/strings.json | 34 + .../reference/embeddings/dataInvalid.json | 31 + .../embeddings/dataInvalidBase64.json | 31 + .../reference/embeddings/dataMissing.json | 30 + .../embeddings/embeddingsElementInvalid.json | 26 + .../embeddings/embeddingsInvalid.json | 26 + .../embeddings/mediaTypeInvalid.json | 31 + .../embeddings/mediaTypeMissing.json | 30 + .../reference/embeddings/twoEmbeddings.json | 35 + .../reference/embeddings/wellDefined.json | 31 + .../reference/names/featureNameEmpty.json | 16 + .../reference/names/featureNameInvalid.json | 16 + .../reference/names/featureNameMissing.json | 15 + .../reference/names/featureUriEmpty.json | 16 + .../reference/names/featureUriInvalid.json | 16 + .../reference/names/featureUriMissing.json | 15 + .../reference/names/featureUriNameEmpty.json | 16 + .../names/featureUriNameIdMissing.json | 13 + .../featureUriNameIdScenarioIdEmpty.json | 16 + .../names/featureUriNameMissing.json | 14 + .../names/featureUriNameMissingIdInvalid.json | 14 + .../featureUriNameScenarioNameMissing.json | 13 + .../names/featureUriScenarioNameMissing.json | 14 + .../reference/names/scenarioNameEmpty.json | 16 + .../names/scenarioNameIdInvalid.json | 15 + .../names/scenarioNameIdMissing.json | 14 + .../reference/names/scenarioNameInvalid.json | 16 + .../reference/names/scenarioNameMissing.json | 15 + .../reference/names/scenarioNameOnly.json | 12 + .../reference/names/wellDefined.json | 16 + .../reference/scenarioStatuses/ambiguous.json | 46 + .../reference/scenarioStatuses/failed.json | 53 + .../scenarioStatuses/invalidStepStatus.json | 39 + .../scenarioStatuses/noStepResult.json | 36 + .../scenarioStatuses/noStepStatus.json | 37 + .../reference/scenarioStatuses/noSteps.json | 16 + .../reference/scenarioStatuses/passed.json | 39 + .../reference/scenarioStatuses/pending.json | 39 + .../reference/scenarioStatuses/skipped.json | 39 + .../reference/scenarioStatuses/undefined.json | 46 + .../reference/scenarioStatuses/unknown.json | 39 + .../reference/stepNames/keywordInvalid.json | 25 + .../reference/stepNames/keywordMissing.json | 24 + .../reference/stepNames/nameInvalid.json | 25 + .../stepNames/nameKeywordMissing.json | 23 + .../stepNames/nameKeywordWithWhitespaces.json | 25 + .../reference/stepNames/nameMissing.json | 24 + .../reference/stepNames/wellDefined.json | 25 + .../reference/stepStatuses/ambiguous.json | 25 + .../reference/stepStatuses/failed.json | 25 + .../reference/stepStatuses/invalidStatus.json | 25 + .../reference/stepStatuses/missingResult.json | 22 + .../reference/stepStatuses/missingStatus.json | 23 + .../reference/stepStatuses/passed.json | 25 + .../reference/stepStatuses/pending.json | 25 + .../reference/stepStatuses/skipped.json | 25 + .../reference/stepStatuses/undefined.json | 25 + .../reference/stepStatuses/unknown.json | 25 + .../reference/tags/feature.json | 17 + .../reference/tags/featureTagNameInvalid.json | 21 + .../reference/tags/featureTagNameMissing.json | 17 + .../tags/featureTagsElementInvalid.json | 17 + .../reference/tags/featureTagsInvalid.json | 17 + .../reference/tags/scenario.json | 17 + .../tags/scenarioTagNameInvalid.json | 21 + .../tags/scenarioTagNameMissing.json | 17 + .../tags/scenarioTagsElementInvalid.json | 17 + .../reference/tags/scenarioTagsInvalid.json | 17 + .../reference/traces/failed.json | 26 + .../reference/traces/passed.json | 26 + 104 files changed, 4245 insertions(+), 38 deletions(-) create mode 100644 packages/reader/src/cucumberjson/index.ts create mode 100644 packages/reader/src/cucumberjson/model.ts create mode 100644 packages/reader/src/utils.ts create mode 100644 packages/reader/test/cucumberjson.test.ts create mode 100644 packages/reader/test/resources/cucumberjsondata/behave/stepNames/noSpaceAfterKeyword.json create mode 100644 packages/reader/test/resources/cucumberjsondata/cucumberjvm/embeddings/nameInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/cucumberjvm/embeddings/named.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/backgrounds/wellDefined.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellsInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellsMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/dataTables/quotes.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/dataTables/rowInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/dataTables/rowsInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/dataTables/wellDefined.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/descriptions/invalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/descriptions/valid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/docstrings/emptyContentType.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/docstrings/emptyValue.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/docstrings/explicitContentType.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/docstrings/missingContentType.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/docstrings/missingValue.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/docstrings/whitespaceOnlyValue.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/durations/allDefined.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/durations/noneDefined.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/durations/oneInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/durations/oneMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/durations/roundDown.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/durations/roundUp.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/durations/strings.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataInvalidBase64.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/embeddings/embeddingsElementInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/embeddings/embeddingsInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/embeddings/mediaTypeInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/embeddings/mediaTypeMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/embeddings/twoEmbeddings.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/embeddings/wellDefined.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureNameEmpty.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureNameInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureNameMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureUriEmpty.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureUriInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureUriMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameEmpty.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameIdMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameIdScenarioIdEmpty.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameMissingIdInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameScenarioNameMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/featureUriScenarioNameMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameEmpty.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameIdInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameIdMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameOnly.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/names/wellDefined.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/ambiguous.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/failed.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/invalidStepStatus.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noStepResult.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noStepStatus.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noSteps.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/passed.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/pending.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/skipped.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/undefined.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/unknown.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepNames/keywordInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepNames/keywordMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameKeywordMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameKeywordWithWhitespaces.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepNames/wellDefined.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/ambiguous.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/failed.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/invalidStatus.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/missingResult.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/missingStatus.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/passed.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/pending.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/skipped.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/undefined.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/unknown.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/tags/feature.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagNameInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagNameMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagsElementInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagsInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/tags/scenario.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagNameInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagNameMissing.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagsElementInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagsInvalid.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/traces/failed.json create mode 100644 packages/reader/test/resources/cucumberjsondata/reference/traces/passed.json diff --git a/packages/reader/src/allure1/index.ts b/packages/reader/src/allure1/index.ts index 11102f5..8b5d81d 100644 --- a/packages/reader/src/allure1/index.ts +++ b/packages/reader/src/allure1/index.ts @@ -7,13 +7,8 @@ import type { } from "@allurereport/reader-api"; import { XMLParser } from "fast-xml-parser"; import * as console from "node:console"; -import { - cleanBadXmlCharacters, - ensureInt, - ensureString, - isStringAnyRecord, - isStringAnyRecordArray, -} from "../xml-utils.js"; +import { ensureInt, ensureString } from "../utils.js"; +import { cleanBadXmlCharacters, isStringAnyRecord, isStringAnyRecordArray } from "../xml-utils.js"; const arrayTags: Set = new Set([ "test-suite.test-cases.test-case", @@ -143,7 +138,7 @@ const parseSteps = (element: unknown): RawTestStepResult[] | undefined => { const steps = parseSteps(stepsElement); return { - name: ensureString(title, ensureString(name)), + name: ensureString(title) ?? ensureString(name), status: convertStatus(ensureString(status)), start, stop, diff --git a/packages/reader/src/allure2/index.ts b/packages/reader/src/allure2/index.ts index 27a5a23..af3956e 100644 --- a/packages/reader/src/allure2/index.ts +++ b/packages/reader/src/allure2/index.ts @@ -16,14 +16,8 @@ import * as console from "node:console"; import { randomUUID } from "node:crypto"; import type { Category, ExecutorInfo } from "../model.js"; import { parseProperties } from "../properties.js"; -import { - cleanBadXmlCharacters, - ensureBoolean, - ensureInt, - ensureString, - isStringAnyRecord, - isStringAnyRecordArray, -} from "../xml-utils.js"; +import { ensureBoolean, ensureInt, ensureString } from "../utils.js"; +import { cleanBadXmlCharacters, isStringAnyRecord, isStringAnyRecordArray } from "../xml-utils.js"; import type { Attachment, FixtureResult, diff --git a/packages/reader/src/cucumberjson/index.ts b/packages/reader/src/cucumberjson/index.ts new file mode 100644 index 0000000..e631f26 --- /dev/null +++ b/packages/reader/src/cucumberjson/index.ts @@ -0,0 +1,443 @@ +import type { + RawTestAttachment, + RawTestLabel, + RawTestResult, + RawTestStatus, + RawTestStepResult, + ResultsReader, + ResultsVisitor, +} from "@allurereport/reader-api"; +import { BufferResultFile } from "@allurereport/reader-api"; +import { randomUUID } from "node:crypto"; +import { ensureArray, ensureInt, ensureString, isArray, isNonNullObject, isString } from "../utils.js"; +import type { + CucumberDatatableRow, + CucumberEmbedding, + CucumberFeature, + CucumberFeatureElement, + CucumberStep, + CucumberTag, +} from "./model.js"; +import { STEP_NAME_PLACEHOLDER, TEST_NAME_PLACEHOLDER } from "./model.js"; + +const NS_IN_MS = 1_000_000; + +const readerId = "cucumberjson"; + +const allureStepStatusPriorityOrder = { + failed: 0, + broken: 1, + unknown: 2, + skipped: 3, + passed: 4, +}; + +const cucumberStatusToAllureStatus: Record = { + unknown: "unknown", + passed: "passed", + skipped: "skipped", + pending: "skipped", + ["undefined"]: "broken", + ambiguous: "broken", + failed: "failed", +}; + +// The interpretation follows https://github.com/cucumber/messages/blob/2e33e6839bf3200eec1a5a7ec6dcb26d46dab410/elixir/messages.proto#L621 +const allureStepMessages: Record = { + unknown: "The result of the step is unknown", + passed: "The step passed", + skipped: "The step was skipped because the previous step hadn't passed", + pending: "The step signalled pending during execution", + ["undefined"]: "The step didn't match any definition", + ambiguous: "The step matched more than one definition", + failed: "The step failed", +}; + +type PreProcessedFeature = { + name: string | undefined; + uri: string | undefined; + id: string | undefined; + tags: string[]; +}; + +type PreProcessedScenario = { + id: string | undefined; + name: string | undefined; + description: string | undefined; + tags: string[]; + type: string | undefined; +}; + +type PreProcessedStep = { + keyword?: string; + name?: string; + status: string; + duration?: number; + errorMessage?: string; + attachments: RawTestAttachment[]; +}; + +type PostProcessedStep = { preProcessedStep: PreProcessedStep; allureStep: RawTestStepResult }; + +export const cucumberjson: ResultsReader = { + read: async (visitor, data) => { + const originalFileName = data.getOriginalFileName(); + try { + const parsed = await data.asJson(); + if (parsed) { + let oneOrMoreFeaturesParsed = false; + for (const feature of parsed) { + oneOrMoreFeaturesParsed ||= await processFeature(visitor, originalFileName, feature); + } + return oneOrMoreFeaturesParsed; + } + } catch (e) { + // eslint-disable-next-line no-console + console.error("error parsing", originalFileName, e); + return false; + } + + return false; + }, + + readerId: () => readerId, +}; + +const processFeature = async (visitor: ResultsVisitor, originalFileName: string, feature: CucumberFeature) => { + if (isCucumberFeature(feature)) { + const preProcessedFeature = preProcessFeature(feature); + for (const scenario of feature.elements) { + await processScenario(visitor, originalFileName, preProcessedFeature, scenario); + } + return true; + } + return false; +}; + +const processScenario = async ( + visitor: ResultsVisitor, + originalFileName: string, + feature: PreProcessedFeature, + scenario: CucumberFeatureElement, +) => { + const preProcessedScenario = preProcessScenario(scenario); + if (shouldProcessScenario(preProcessedScenario)) { + const preProcessedSteps = await preProcessSteps(visitor, scenario.steps ?? []); + await visitor.visitTestResult( + mapCucumberScenarioToAllureTestResult(feature, preProcessedScenario, preProcessedSteps), + { + readerId, + metadata: { originalFileName }, + }, + ); + } +}; + +const shouldProcessScenario = ({ type }: PreProcessedScenario) => type !== "background"; + +const preProcessSteps = async (visitor: ResultsVisitor, steps: readonly CucumberStep[]) => { + const preProcessedSteps: PreProcessedStep[] = []; + for (const step of steps) { + preProcessedSteps.push(await preProcessOneStep(visitor, step)); + } + return preProcessedSteps; +}; + +const preProcessOneStep = async (visitor: ResultsVisitor, step: CucumberStep): Promise => { + const { keyword, name, result } = step; + const { status, duration, error_message: errorMessage } = result ?? {}; + return { + name: ensureString(name)?.trim(), + keyword: ensureString(keyword)?.trim(), + status: status ?? "unknown", + duration: ensureInt(duration), + errorMessage, + attachments: await processStepAttachments(visitor, step), + }; +}; + +const processStepAttachments = async (visitor: ResultsVisitor, step: CucumberStep) => + [ + await processStepDocStringAttachment(visitor, step), + await processStepDataTableAttachment(visitor, step), + ...(await processStepEmbeddingAttachments(visitor, step)), + ].filter((s): s is RawTestAttachment => typeof s !== "undefined"); + +const processStepDocStringAttachment = async ( + visitor: ResultsVisitor, + { doc_string: docString }: CucumberStep, +): Promise => { + if (docString) { + const { value, content_type: contentType } = docString; + if (value && value.trim()) { + return await visitBufferAttachment(visitor, "Description", Buffer.from(value), contentType || "text/markdown"); + } + } +}; + +const processStepDataTableAttachment = async (visitor: ResultsVisitor, { rows }: CucumberStep) => { + if (isArray(rows)) { + const content = formatDataTable(rows); + return await visitBufferAttachment(visitor, "Data", Buffer.from(content), "text/csv"); + } +}; + +const processStepEmbeddingAttachments = async (visitor: ResultsVisitor, { embeddings }: CucumberStep) => { + const attachments: RawTestAttachment[] = []; + const checkedEmbeddings = ensureArray(embeddings) ?? []; + const getName = checkedEmbeddings.length > 1 ? (i: number) => `Embedding ${i}` : () => "Embedding"; + const embeddingsWithNames = checkedEmbeddings.map<[unknown, string]>((e, i) => [e, getName(i + 1)]); + for (const [embedding, fallbackName] of embeddingsWithNames) { + if (isNonNullObject(embedding)) { + attachments.push( + await visitBufferAttachment( + visitor, + ensureString(embedding.name, fallbackName), + Buffer.from(ensureString(embedding.data, ""), "base64"), + ensureString(embedding.mime_type, "application/octet-stream"), + ), + ); + } + } + return attachments; +}; + +const visitBufferAttachment = async ( + visitor: ResultsVisitor, + name: string, + content: Buffer, + contentType: string, +): Promise => { + const fileName = randomUUID(); + await visitor.visitAttachmentFile(new BufferResultFile(content, fileName), { readerId }); + return { + type: "attachment", + contentType, + originalFileName: fileName, + name, + }; +}; + +// CSV formatting follows the rules in https://www.ietf.org/rfc/rfc4180.txt +const formatDataTable = (rows: readonly unknown[]) => { + return rows + .filter(isNonNullObject) + .map(formatDataTableRow) + .filter(isString) + .join("\r\n"); +}; + +const formatDataTableRow = ({ cells }: CucumberDatatableRow) => { + const checkedCells = ensureArray(cells); + return checkedCells ? checkedCells.map(formatDataTableCell).join(",") : undefined; +}; + +const formatDataTableCell = (cell: string) => { + const escapedCell = ensureString(cell, "").replaceAll(String.raw`"`, String.raw`""`); + return `"${escapedCell}"`; +}; + +const isCucumberFeature = ({ keyword, elements }: CucumberFeature) => + typeof keyword === "string" && keyword.toLowerCase() === "feature" && Array.isArray(elements); + +const pairWithAllureSteps = (preProcessedCucumberSteps: readonly PreProcessedStep[]) => + preProcessedCucumberSteps.map((c) => { + return { + preProcessedStep: c, + allureStep: createAllureStepResult(c), + }; + }); + +const mapCucumberScenarioToAllureTestResult = ( + preProcessedFeature: PreProcessedFeature, + scenario: PreProcessedScenario, + preProcessedSteps: readonly PreProcessedStep[], +): RawTestResult => { + const postProcessedSteps = pairWithAllureSteps(preProcessedSteps); + return { + fullName: calculateFullName(preProcessedFeature, scenario), + name: scenario.name ?? TEST_NAME_PLACEHOLDER, + description: scenario.description, + duration: convertDuration(calculateTestDuration(postProcessedSteps)), + steps: postProcessedSteps.map(({ allureStep }) => allureStep), + labels: calculateTestLabels(preProcessedFeature, scenario), + ...resolveTestResultStatusProps(postProcessedSteps), + }; +}; + +const calculateTestLabels = ( + { name: featureName, tags: featureTags }: PreProcessedFeature, + { tags: scenarioTags }: PreProcessedScenario, +) => { + const labels: RawTestLabel[] = []; + if (featureName) { + labels.push({ name: "feature", value: featureName }); + } + labels.push( + ...featureTags.map((value) => ({ name: "tag", value })), + ...scenarioTags.map((value) => ({ name: "tag", value })), + ); + return labels; +}; + +const preProcessFeature = (feature: CucumberFeature): PreProcessedFeature => { + return { + id: ensureString(feature.id), + name: ensureString(feature.name), + uri: ensureString(feature.uri), + tags: parseTags(feature.tags), + }; +}; + +const parseTags = (tags: unknown) => { + return (ensureArray(tags) ?? []) + .filter(isNonNullObject) + .map(({ name }) => name) + .filter(isString); +}; + +const preProcessScenario = (scenario: CucumberFeatureElement): PreProcessedScenario => { + return { + id: ensureString(scenario.id), + name: ensureString(scenario.name), + description: ensureString(scenario.description), + tags: parseTags(scenario.tags), + type: scenario.type, + }; +}; + +const calculateFullName = ( + { uri: featureUri, name: featureName, id: featureId }: PreProcessedFeature, + { name: scenarioName, id: scenarioId }: PreProcessedScenario, +) => { + if (!scenarioName && !scenarioId) { + return randomUUID(); + } + + // featureUri may contain the feature file's path, hence, is more precise. + // featureName is the second best choice because it most probably won't have collisions. + const featurePart = featureUri || featureName || featureId; + if (featurePart) { + // scenarioId might have collisions: differenc names are translated into the same id. + // That's why we're prioritizing scenarioName if the feature part is proven to exist. + const scenarioPart = scenarioName || scenarioId; + return `${featurePart}#${scenarioPart!}`; + } + + // If no feature part found, we're prioritizing scenarioId because there can be the feature id in it. + return scenarioId || scenarioName; +}; + +const calculateTestDuration = (cucumberAllureStepData: readonly PostProcessedStep[]) => + cucumberAllureStepData.reduce( + (testDuration, { preProcessedStep: { duration } }) => + typeof testDuration === "undefined" ? duration : testDuration + (duration ?? 0), + undefined, + ); + +const resolveTestResultStatusProps = ( + cucumberAllureSteps: readonly PostProcessedStep[], +): { status: RawTestStatus; message?: string; trace?: string } => { + const stepsData = getCucumberAllureStepWithMaxPriorityStatus(cucumberAllureSteps); + return stepsData + ? resolveResultOfTestFromStepsData(stepsData) + : { + status: "unknown", + message: "Step results are missing", + }; +}; + +const resolveResultOfTestFromStepsData = ({ + preProcessedStep: { status: cucumberStatus, errorMessage }, + allureStep: { name, status }, +}: PostProcessedStep) => ({ + status: status ?? "unknown", + ...resolveTestMessageAndTrace(name!, cucumberStatus, errorMessage), +}); + +const resolveTestMessageAndTrace = (allureStepName: string, status: string, errorMessage: string | undefined) => + status !== "passed" + ? { + message: resolveTestMessage(status, allureStepName), + trace: errorMessage, + } + : {}; + +const resolveTestMessage = (cucumberStepStatus: string | undefined, allureStepName: string) => { + switch (cucumberStepStatus) { + case "failed": + return `The step '${allureStepName}' failed`; + case "skipped": + return "One or more steps of the scenario were skipped"; + case "pending": + return `The step '${allureStepName}' signalled pending during execution`; + case "undefined": + return `The step '${allureStepName}' didn't match any definition`; + case "ambiguous": + return `The step '${allureStepName}' matched more than one definition`; + case "unknown": + default: + return `The result of the step '${allureStepName}' is unknown`; + } +}; + +const getCucumberAllureStepWithMaxPriorityStatus = (cucumberAllureSteps: readonly PostProcessedStep[]) => { + switch (cucumberAllureSteps.length) { + case 0: + return undefined; + case 1: + return cucumberAllureSteps[0]; + default: + return cucumberAllureSteps.reduce(statusPriorityReducingFn); + } +}; + +const statusPriorityReducingFn = (testDefiningStep: PostProcessedStep, currentStep: PostProcessedStep) => + allureStepStatusPriorityOrder[testDefiningStep.allureStep.status!] <= + allureStepStatusPriorityOrder[currentStep.allureStep.status!] + ? testDefiningStep + : currentStep; + +const createAllureStepResult = ({ + keyword, + name, + status, + duration, + errorMessage, + attachments, +}: PreProcessedStep): RawTestStepResult => ({ + type: "step", + name: getAllureStepName(keyword, name), + steps: attachments, + ...mapCucumberStepResultToStepProps(status, duration, errorMessage), +}); + +const getAllureStepName = (keyword: string | undefined, name: string | undefined) => { + if (!name) { + return keyword ? `${keyword} <${STEP_NAME_PLACEHOLDER.toLowerCase()}>` : STEP_NAME_PLACEHOLDER; + } + return keyword ? `${keyword} ${name}` : name; +}; + +const mapCucumberStepResultToStepProps = ( + status: string, + duration: number | undefined, + errorMessage: string | undefined, +) => ({ + status: cucumberStatusToAllureStatus[status ?? "unknown"] ?? "unknown", + duration: convertDuration(duration), + ...resolveStepMessageAndTrace(status, errorMessage), +}); + +const resolveStepMessageAndTrace = (status: string, errorMessage: string | undefined) => + status !== "passed" || errorMessage + ? { + message: allureStepMessages[status ?? "unknown"] ?? allureStepMessages.unknown, + trace: errorMessage, + } + : {}; + +const convertDuration = (duration: number | undefined) => + typeof duration !== "undefined" ? nsToMs(duration) : undefined; + +const nsToMs = (ns: number) => Math.round(ns / NS_IN_MS); diff --git a/packages/reader/src/cucumberjson/model.ts b/packages/reader/src/cucumberjson/model.ts new file mode 100644 index 0000000..e47299b --- /dev/null +++ b/packages/reader/src/cucumberjson/model.ts @@ -0,0 +1,71 @@ +export const TEST_NAME_PLACEHOLDER = "The scenario's name is not defined"; +export const STEP_NAME_PLACEHOLDER = "The step's name is not defined"; + +// TODO: fix known/unknown typings + +export type CucumberFeature = { + description: string; + elements: CucumberFeatureElement[]; + id: string; + keyword: string; + line: number; + name: string; + tags?: unknown; // CucumberTag[] + uri: string; +}; + +export type CucumberFeatureElement = { + after?: CucumberStep[]; + before?: CucumberStep[]; + description: string; + id?: string; + keyword: string; + line: number; + name: string; + steps?: CucumberStep[]; + tags?: unknown; // CucumberTag[] + type: string; +}; + +export type CucumberStep = { + doc_string?: CucumberDocString; + embeddings?: unknown; // CucumberEmbedding[] + keyword?: string; + line?: number; + match?: CucumberStepMatch; + name?: string; + output?: string[]; + result: CucumberStepResult; + rows?: unknown; // CucumberDatatableRow[] +}; + +export type CucumberDocString = { + content_type?: string; + line?: number; + value?: string; +}; + +export type CucumberDatatableRow = { + cells: unknown; // string[] +}; + +export type CucumberStepResult = { + duration?: number; + error_message?: string; + status: string; +}; + +export type CucumberStepMatch = { + location: string; +}; + +export type CucumberTag = { + line: number; + name: unknown; // string +}; + +export type CucumberEmbedding = { + data: unknown; // string + mime_type: unknown; // string + name?: unknown; // string; Cucumber-JVM: https://github.com/cucumber/cucumber-jvm/pull/1693 +}; diff --git a/packages/reader/src/index.ts b/packages/reader/src/index.ts index f4c9b9c..ba2208b 100644 --- a/packages/reader/src/index.ts +++ b/packages/reader/src/index.ts @@ -1,5 +1,6 @@ export * from "./allure1/index.js"; export * from "./allure2/index.js"; +export * from "./cucumberjson/index.js"; export * from "./junitxml/index.js"; export * from "./attachments/index.js"; export type * from "./model.js"; diff --git a/packages/reader/src/junitxml/index.ts b/packages/reader/src/junitxml/index.ts index 7c7533c..4870fcc 100644 --- a/packages/reader/src/junitxml/index.ts +++ b/packages/reader/src/junitxml/index.ts @@ -1,7 +1,8 @@ import type { RawTestStatus, ResultsReader, ResultsVisitor } from "@allurereport/reader-api"; import { XMLParser } from "fast-xml-parser"; import * as console from "node:console"; -import { ensureString, isEmptyElement, isStringAnyRecord, isStringAnyRecordArray } from "../xml-utils.js"; +import { ensureString } from "../utils.js"; +import { isEmptyElement, isStringAnyRecord, isStringAnyRecordArray } from "../xml-utils.js"; const arrayTags: Set = new Set(["testsuite.testcase", "testsuites.testsuite", "testsuites.testsuite.testcase"]); diff --git a/packages/reader/src/utils.ts b/packages/reader/src/utils.ts new file mode 100644 index 0000000..548055b --- /dev/null +++ b/packages/reader/src/utils.ts @@ -0,0 +1,46 @@ +export const isBoolean = (value: unknown): value is boolean => typeof value === "boolean"; +export const isString = (value: unknown): value is string => typeof value === "string"; +export const isArray = (value: unknown): value is T[] => Array.isArray(value); +export const isNonNullObject = (value: unknown): value is T => + typeof value === "object" && value !== null; + +export function ensureBoolean(value: unknown): boolean | undefined; +export function ensureBoolean(value: unknown, fallback: boolean): boolean; +// eslint-disable-next-line prefer-arrow/prefer-arrow-functions +export function ensureBoolean(value: unknown, fallback?: boolean) { + return isBoolean(value) ? value : fallback; +} + +export const ensureInt = (obj: unknown): number | undefined => { + if (typeof obj === "number") { + return obj; + } + const stringValue = ensureString(obj); + if (!stringValue) { + return undefined; + } + + const parsed = parseInt(stringValue, 10); + return isNaN(parsed) ? undefined : parsed; +}; + +export function ensureString(value: unknown): string | undefined; +export function ensureString(value: unknown, fallback: string): string; +// eslint-disable-next-line prefer-arrow/prefer-arrow-functions +export function ensureString(value: unknown, fallback?: string) { + return isString(value) ? value : fallback; +} + +export function ensureArray(value: unknown): T[] | undefined; +export function ensureArray(value: unknown, fallback: T[]): T[]; +// eslint-disable-next-line prefer-arrow/prefer-arrow-functions +export function ensureArray(value: unknown, fallback?: T[]) { + return isArray(value) ? value : fallback; +} + +export function ensureObject(value: unknown): T | undefined; +export function ensureObject(value: unknown, fallback: T): T; +// eslint-disable-next-line prefer-arrow/prefer-arrow-functions +export function ensureObject(value: unknown, fallback?: T) { + return isNonNullObject(value) ? value : fallback; +} diff --git a/packages/reader/src/xml-utils.ts b/packages/reader/src/xml-utils.ts index 22fcd00..a8022b5 100644 --- a/packages/reader/src/xml-utils.ts +++ b/packages/reader/src/xml-utils.ts @@ -3,27 +3,6 @@ export const isEmptyElement = (obj: unknown): obj is "" => { return obj === ""; }; -export const ensureBoolean = (obj: unknown, fallback?: boolean) => { - return typeof obj === "boolean" ? obj : fallback; -}; - -export const ensureString = (obj: unknown, fallback?: string) => { - return typeof obj === "string" ? obj : fallback; -}; - -export const ensureInt = (obj: unknown): number | undefined => { - if (typeof obj === "number") { - return obj; - } - const stringValue = ensureString(obj); - if (!stringValue) { - return undefined; - } - - const parsed = parseInt(stringValue, 10); - return isNaN(parsed) ? undefined : parsed; -}; - export const isStringAnyRecord = (obj: unknown): obj is Record => { if (typeof obj !== "object") { return false; diff --git a/packages/reader/test/cucumberjson.test.ts b/packages/reader/test/cucumberjson.test.ts new file mode 100644 index 0000000..53b6623 --- /dev/null +++ b/packages/reader/test/cucumberjson.test.ts @@ -0,0 +1,1297 @@ +/* eslint @typescript-eslint/unbound-method: 0, max-lines: 0 */ +import { describe, expect, it } from "vitest"; +import { cucumberjson } from "../src/index.js"; +import { readResults } from "./utils.js"; + +const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; + +describe("cucumberjson reader", () => { + // As implemented in https://github.com/cucumber/cucumber-ruby or https://github.com/cucumber/json-formatter (which + // uses cucumber-ruby as the reference for its tests). + describe("reference", () => { + describe("names", () => { + it("should parse names", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/wellDefined.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + name: "Passed test", + fullName: "features/foo.feature#Passed test", + labels: [{ name: "feature", value: "Foo" }], + }); + }); + + it("should handle missing scenario name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/scenarioNameMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + name: "The scenario's name is not defined", + fullName: "features/foo.feature#foo;passed-test", + }); + }); + + it("should handle an ill-formed scenario name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/scenarioNameInvalid.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + name: "The scenario's name is not defined", + fullName: "features/foo.feature#foo;passed-test", + }); + }); + + it("should generate random fullName if scenario name and id are missing", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/scenarioNameIdMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + name: "The scenario's name is not defined", + fullName: expect.stringMatching(UUID_PATTERN), + }); + }); + + it("should generate random fullName if scenario name and id are ill-formed", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/scenarioNameIdInvalid.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + name: "The scenario's name is not defined", + fullName: expect.stringMatching(UUID_PATTERN), + }); + }); + + it("should not add a feature label if the feature's name is missing", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureNameMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + labels: [], + }); + }); + + it("should not add a feature label if the feature's name is ill-formed", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureNameInvalid.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + labels: [], + }); + }); + + it("should not add a feature label if the feature's name is empty", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureNameEmpty.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + labels: [], + }); + }); + + it("should use feature name if the uri is missing", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureUriMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "Foo#Passed test", + }); + }); + + it("should use feature name if the uri is ill-formed", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureUriInvalid.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "Foo#Passed test", + }); + }); + + it("should handle missing feature uri and scenario name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureUriScenarioNameMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "Foo#foo;passed-test", + }); + }); + + it("should use feature id if uri and name are missing", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureUriNameMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "foo#Passed test", + }); + }); + + it("should handle missing feature uri and name, and scenario name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureUriNameScenarioNameMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "foo#foo;passed-test", + }); + }); + + it("should set fullName to scenario id if feature uri, name, and id are missing", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureUriNameIdMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "foo;passed-test", + }); + }); + + it("should set fullName to scenario id if feature uri and name are missing and id is ill-formed", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureUriNameMissingIdInvalid.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "foo;passed-test", + }); + }); + + it("should set fullName to scenario name if no other id exists", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/scenarioNameOnly.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "Passed test", + }); + }); + + it("should handle empty feature uri", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureUriEmpty.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "Foo#Passed test", + }); + }); + + it("should handle empty feature uri and name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureUriNameEmpty.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "foo#Passed test", + }); + }); + + it("should handle empty scenario name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/scenarioNameEmpty.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "features/foo.feature#foo;passed-test", + }); + }); + + it("should handle empty feature uri, name, and id and empty scenario id", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/names/featureUriNameIdScenarioIdEmpty.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + fullName: "Passed test", + }); + }); + }); + + describe("step names", () => { + it("should join the keyword with the name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepNames/wellDefined.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [{ name: "Then pass" }], + }); + }); + + it("should ignore a missing keyword", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepNames/keywordMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [{ name: "pass" }], + }); + }); + + it("should ignore the ill-formed keyword", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepNames/keywordInvalid.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [{ name: "pass" }], + }); + }); + + it("should use a placeholder if the name is missing", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepNames/nameMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [{ name: "Then " }], + }); + }); + + it("should use a placeholder if the name is ill-formed", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepNames/nameInvalid.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [{ name: "Then " }], + }); + }); + + it("should use a placeholder if both the name and the keyword are missing", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepNames/nameKeywordMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [{ name: "The step's name is not defined" }], + }); + }); + + it("should trim the name and the keyword", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepNames/nameKeywordWithWhitespaces.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [{ name: "Then pass" }], + }); + }); + }); + + describe("step statuses", () => { + it("should parse a passed step", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepStatuses/passed.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [ + { + status: "passed", + }, + ], + }); + }); + + it("should parse a failed step", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepStatuses/failed.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [ + { + status: "failed", + message: "The step failed", + }, + ], + }); + }); + + it("should parse an unknown step", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepStatuses/unknown.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [ + { + status: "unknown", + message: "The result of the step is unknown", + }, + ], + }); + }); + + it("should parse a skipped step", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepStatuses/skipped.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [ + { + status: "skipped", + message: "The step was skipped because the previous step hadn't passed", + }, + ], + }); + }); + + it("should parse a pending step", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepStatuses/pending.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [ + { + status: "skipped", + message: "The step signalled pending during execution", + }, + ], + }); + }); + + it("should parse an undefined step", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepStatuses/undefined.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [ + { + status: "broken", + message: "The step didn't match any definition", + }, + ], + }); + }); + + it("should parse an ambiguous step", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepStatuses/ambiguous.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [ + { + status: "broken", + message: "The step matched more than one definition", + }, + ], + }); + }); + + it("should treat a step with a missing result as unknown", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepStatuses/missingResult.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [ + { + status: "unknown", + message: "The result of the step is unknown", + }, + ], + }); + }); + + it("should treat a step with a missing status as unknown", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepStatuses/missingStatus.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [ + { + status: "unknown", + message: "The result of the step is unknown", + }, + ], + }); + }); + + it("should treat an invalid step status as unknown", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/stepStatuses/invalidStatus.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [ + { + status: "unknown", + message: "The result of the step is unknown", + }, + ], + }); + }); + }); + + describe("test statuses", () => { + it("should parse a scenario with no steps", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/noSteps.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + status: "unknown", + message: "Step results are missing", + }); + }); + + it("should parse a failed scenario with multiple steps", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/failed.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + status: "failed", + message: "The step 'Then fail' failed", + }); + }); + + it("should parse an undefined scenario with multiple steps", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/undefined.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + status: "broken", + message: "The step 'Then undefined' didn't match any definition", + }); + }); + + it("should parse an ambiguous scenario with multiple steps", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/ambiguous.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + status: "broken", + message: "The step 'Then ambiguous' matched more than one definition", + }); + }); + + it("should parse an unknown scenario with multiple steps", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/unknown.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + status: "unknown", + message: "The result of the step 'Then unknown' is unknown", + }); + }); + + it("should parse a pending scenario with multiple steps", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/pending.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + status: "skipped", + message: "The step 'Then pend' signalled pending during execution", + }); + }); + + it("should parse a skipped scenario with multiple steps", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/skipped.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + status: "skipped", + message: "One or more steps of the scenario were skipped", + }); + }); + + it("should parse a passed scenario with multiple steps", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/passed.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test.message).toBeUndefined(); + expect(test).toMatchObject({ + status: "passed", + }); + }); + + it("should parse a scenario with a step that has no result", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/noStepResult.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + status: "unknown", + message: "The result of the step 'Then unknown' is unknown", + }); + }); + + it("should parse a scenario with a step that has no status", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/noStepStatus.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + status: "unknown", + message: "The result of the step 'Then unknown' is unknown", + }); + }); + + it("should parse a scenario with a step that has an invalid status", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/scenarioStatuses/invalidStepStatus.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + status: "unknown", + message: "The result of the step 'Then unknown' is unknown", + }); + }); + }); + + describe("traces", () => { + it("should set trace from error_message", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/traces/failed.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + message: "The step 'Then fail' failed", + trace: "Lorem Ipsum", + steps: [ + { + message: "The step failed", + trace: "Lorem Ipsum", + }, + ], + }); + }); + + it("should not set passed step trace at test level", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/traces/passed.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + message: "The step passed", + trace: "Lorem Ipsum", + }, + ], + }); + expect(test).not.toHaveProperty("message"); + expect(test).not.toHaveProperty("trace"); + }); + }); + + // The reference implementation sets durations in ns + describe("durations", () => { + it("should round down a remainder less than 0.5 ms", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/durations/roundDown.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + duration: 12, + }, + ], + }); + }); + + it("should round up a remainder greater than or equal to 0.5 ms", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/durations/roundUp.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + duration: 13, + }, + ], + }); + }); + + it("should sum durations of steps at the test level", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/durations/allDefined.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + duration: 25, + }); + }); + + it("should convert durations from strings", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/durations/strings.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + duration: 25, + steps: [{ duration: 12 }, { duration: 12 }], + }); + }); + + it("should ignore steps with no durations when calculating the test's duration", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/durations/oneMissing.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + duration: 25, + }); + }); + + it("should ignore steps with ill-formed durations when calculating the test's duration", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/durations/oneInvalid.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + duration: 25, + }); + }); + + it("should leave durations undefined if they aren't present", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/durations/noneDefined.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test.duration).toBeUndefined(); + expect(test).toMatchObject({ + steps: [ + expect.not.objectContaining({ duration: expect.anything() }), + expect.not.objectContaining({ duration: expect.anything() }), + expect.not.objectContaining({ duration: expect.anything() }), + ], + }); + }); + }); + + describe("descriptions", () => { + it("should parse a scenario's description", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/descriptions/valid.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test.description).toEqual("Lorem Ipsum"); + }); + + it("should ignore an invalid description of a scenario", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/descriptions/invalid.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test.description).toBeUndefined(); + }); + }); + + describe("step arguments", () => { + describe("doc strings", () => { + it("should parse a step's doc string", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/docstrings/missingContentType.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const test = visitor.visitTestResult.mock.calls[0][0]; + const content = await attachment.asUtf8String(); + expect(content).toEqual("Lorem Ipsum"); + expect(test).toMatchObject({ + steps: [ + { + steps: [ + { + type: "attachment", + name: "Description", + contentType: "text/markdown", // it's markdown by default + originalFileName: attachment.getOriginalFileName(), + }, + ], + }, + ], + }); + }); + + it("should ignore a step's doc string with a missing value", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/docstrings/missingValue.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(0); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + steps: [], + }, + ], + }); + }); + + it("should ignore a step's empty doc string", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/docstrings/emptyValue.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(0); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + steps: [], + }, + ], + }); + }); + + it("should ignore a step's whitespace-only doc string", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/docstrings/whitespaceOnlyValue.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(0); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + steps: [], + }, + ], + }); + }); + + it("should parse a step's doc string with an empty content type", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/docstrings/emptyContentType.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const test = visitor.visitTestResult.mock.calls[0][0]; + const content = await attachment.asUtf8String(); + expect(content).toEqual("Lorem Ipsum"); + expect(test).toMatchObject({ + steps: [ + { + steps: [ + { + type: "attachment", + name: "Description", + contentType: "text/markdown", // fallback to markdown + originalFileName: attachment.getOriginalFileName(), + }, + ], + }, + ], + }); + }); + + it("should parse a step's doc string with a content type", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/docstrings/explicitContentType.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const test = visitor.visitTestResult.mock.calls[0][0]; + const content = await attachment.asUtf8String(); + expect(content).toEqual('"Lorem Ipsum"'); + expect(test).toMatchObject({ + steps: [ + { + steps: [ + { + type: "attachment", + name: "Description", + contentType: "application/json", + originalFileName: attachment.getOriginalFileName(), + }, + ], + }, + ], + }); + }); + }); + + describe("data tables", () => { + it("should parse a step's data table", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/dataTables/wellDefined.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const test = visitor.visitTestResult.mock.calls[0][0]; + const content = await attachment.asUtf8String(); + expect(content).toEqual('"col1","col2"\r\n"val1","val2"'); + expect(test).toMatchObject({ + steps: [ + { + steps: [ + { + type: "attachment", + name: "Data", + contentType: "text/csv", + originalFileName: attachment.getOriginalFileName(), + }, + ], + }, + ], + }); + }); + + it("should escape quotes", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/dataTables/quotes.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const content = await attachment.asUtf8String(); + expect(content).toEqual('"col1","col2"\r\n"va""l1","""val2"""'); + }); + + it("should ignore the ill-formed rows property", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/dataTables/rowsInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).not.toHaveBeenCalled(); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + steps: [], + }, + ], + }); + }); + + it("should ignore an ill-formed row", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/dataTables/rowInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const content = await attachment.asUtf8String(); + expect(content).toEqual('"col1","col2"'); + }); + + it("should ignore a row with no cells property", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/dataTables/cellsMissing.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const content = await attachment.asUtf8String(); + expect(content).toEqual('"col1","col2"'); + }); + + it("should ignore a row with the ill-formed cells property", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/dataTables/cellsInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const content = await attachment.asUtf8String(); + expect(content).toEqual('"col1","col2"'); + }); + + it("should treat an ill-formed cell as an empty string", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/dataTables/cellInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const content = await attachment.asUtf8String(); + expect(content).toEqual('"col1","col2"\r\n"val1",""'); + }); + }); + }); + + describe("embeddings", () => { + it("should parse an embedding", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/embeddings/wellDefined.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const test = visitor.visitTestResult.mock.calls[0][0]; + const content = await attachment.asUtf8String(); + expect(content).toEqual("Hello!"); + expect(test).toMatchObject({ + steps: [ + { + steps: [ + { + type: "attachment", + name: "Embedding", + contentType: "text/plain", + originalFileName: attachment.getOriginalFileName(), + }, + ], + }, + ], + }); + }); + + it("should ignore the ill-formed embeddings property", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/embeddings/embeddingsInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).not.toHaveBeenCalled(); + }); + + it("should ignore an ill-formed embeddings element", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/embeddings/embeddingsElementInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).not.toHaveBeenCalled(); + }); + + it("should use application/octet-stream if no mime_type specified", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/embeddings/mediaTypeMissing.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + steps: [ + { + contentType: "application/octet-stream", + }, + ], + }, + ], + }); + }); + + it("should use application/octet-stream if the mime_type is ill-formed", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/embeddings/mediaTypeInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + steps: [ + { + contentType: "application/octet-stream", + }, + ], + }, + ], + }); + }); + + it("should attach an empty file if no data is specified", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/embeddings/dataMissing.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const content = await attachment.asBuffer(); + expect(content).toHaveLength(0); + }); + + it("should attach an empty file if the data is ill-formed", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/embeddings/dataInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const content = await attachment.asBuffer(); + expect(content).toHaveLength(0); + }); + + it("should attach an empty file if the data is an ill-formed base64 string", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/embeddings/dataInvalidBase64.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const attachment = visitor.visitAttachmentFile.mock.calls[0][0]; + const content = await attachment.asBuffer(); + expect(content).toHaveLength(0); + }); + + it("should include an embedding's number if more than one", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/embeddings/twoEmbeddings.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(2); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + steps: [{ name: "Embedding 1" }, { name: "Embedding 2" }], + }, + ], + }); + }); + }); + + describe("tags", () => { + it("should parse feature tags", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/tags/feature.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + labels: expect.arrayContaining([ + { name: "tag", value: "tag1" }, + { name: "tag", value: "tag2" }, + ]), + }); + }); + + it("should parse scenario tags", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/tags/scenario.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + labels: expect.arrayContaining([ + { name: "tag", value: "tag1" }, + { name: "tag", value: "tag2" }, + ]), + }); + }); + + it("should ignore the ill-formed feature tags property", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/tags/featureTagsInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + labels: expect.not.arrayContaining([{ name: "tag" }]), + }); + }); + + it("should ignore the ill-formed feature tag element", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/tags/featureTagsElementInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + labels: expect.not.arrayContaining([{ name: "tag" }]), + }); + }); + + it("should ignore a feature tag with a missing name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/tags/featureTagNameMissing.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + labels: expect.not.arrayContaining([{ name: "tag" }]), + }); + }); + + it("should ignore a feature tag with the ill-formed name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/tags/featureTagNameInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + labels: expect.not.arrayContaining([{ name: "tag" }]), + }); + }); + + it("should ignore the ill-formed scenario tags property", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/tags/scenarioTagsInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + labels: expect.not.arrayContaining([{ name: "tag" }]), + }); + }); + + it("should ignore the ill-formed scenario tag element", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/tags/scenarioTagsElementInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + labels: expect.not.arrayContaining([{ name: "tag" }]), + }); + }); + + it("should ignore a scenario tag with a missing name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/tags/scenarioTagNameMissing.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + labels: expect.not.arrayContaining([{ name: "tag" }]), + }); + }); + + it("should ignore a scenario tag with the ill-formed name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/tags/scenarioTagNameInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + labels: expect.not.arrayContaining([{ name: "tag" }]), + }); + }); + }); + + describe("backgrounds", () => { + // TODO: implement background-to-fixture conversion + it("should ignore backgrounds", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/reference/backgrounds/wellDefined.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + name: "Baz", + }); + }); + }); + }); + + describe("cucumber-jvm", () => { + describe("embeddings", () => { + it("should use the embedding's name as the attachment name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/cucumberjvm/embeddings/named.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + steps: [{ name: "Foo" }], + }, + ], + }); + }); + + it("should ignore the ill-formed name", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/cucumberjvm/embeddings/nameInvalid.json": "cucumber.json", + }); + + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitAttachmentFile).toHaveBeenCalledTimes(1); + const test = visitor.visitTestResult.mock.calls[0][0]; + expect(test).toMatchObject({ + steps: [ + { + steps: [{ name: "Embedding" }], + }, + ], + }); + }); + }); + }); + + describe("behave", () => { + describe("stepNames", () => { + it("should join the keyword and the name with a whitespace", async () => { + const visitor = await readResults(cucumberjson, { + "cucumberjsondata/behave/stepNames/noSpaceAfterKeyword.json": "cucumber.json", + }); + expect(visitor.visitTestResult).toHaveBeenCalledTimes(1); + expect(visitor.visitTestResult.mock.calls[0][0]).toMatchObject({ + steps: [{ name: "Then pass" }], + }); + }); + }); + }); +}); diff --git a/packages/reader/test/resources/cucumberjsondata/behave/stepNames/noSpaceAfterKeyword.json b/packages/reader/test/resources/cucumberjsondata/behave/stepNames/noSpaceAfterKeyword.json new file mode 100644 index 0000000..8e725b4 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/behave/stepNames/noSpaceAfterKeyword.json @@ -0,0 +1,28 @@ +[ + { + "keyword": "Feature", + "name": "foo", + "tags": [], + "location": "features/foo.feature:1", + "status": "passed", + "elements": [ + { + "type": "scenario", + "keyword": "Scenario", + "name": "Bar", + "tags": [], + "location": "features/foo.feature:2", + "steps": [ + { + "keyword": "Then", + "step_type": "then", + "name": "pass", + "location": "features/foo.feature:3", + "result": { "status": "passed" } + } + ], + "status": "failed" + } + ] + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/cucumberjvm/embeddings/nameInvalid.json b/packages/reader/test/resources/cucumberjsondata/cucumberjvm/embeddings/nameInvalid.json new file mode 100644 index 0000000..fe0288a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/cucumberjvm/embeddings/nameInvalid.json @@ -0,0 +1,31 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": [ + { + "data": "SGVsbG8h", + "name": { "foo": "bar" } + } + ] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/cucumberjvm/embeddings/named.json b/packages/reader/test/resources/cucumberjsondata/cucumberjvm/embeddings/named.json new file mode 100644 index 0000000..e72c025 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/cucumberjvm/embeddings/named.json @@ -0,0 +1,31 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": [ + { + "data": "SGVsbG8h", + "name": "Foo" + } + ] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/backgrounds/wellDefined.json b/packages/reader/test/resources/cucumberjsondata/reference/backgrounds/wellDefined.json new file mode 100644 index 0000000..bc4e81a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/backgrounds/wellDefined.json @@ -0,0 +1,41 @@ +[ + { + "id": "foo", + "uri": "features/foo.feature", + "keyword": "Feature", + "name": "Foo", + "elements": [ + { + "keyword": "Background", + "name": "Bar", + "type": "background", + "steps": [ + { + "keyword": "Given ", + "name": "pass", + "result": { + "status": "passed", + "duration": 10000 + } + } + ] + }, + { + "id": "foo;baz", + "keyword": "Scenario", + "name": "Baz", + "type": "scenario", + "steps": [ + { + "keyword": "Given ", + "name": "pass", + "result": { + "status": "passed", + "duration": 12000 + } + } + ] + } + ] + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellInvalid.json new file mode 100644 index 0000000..7193366 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellInvalid.json @@ -0,0 +1,23 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "rows": [{ "cells": ["col1", "col2"] }, { "cells": ["val1", { "foo": "bar" }] }] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellsInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellsInvalid.json new file mode 100644 index 0000000..6a4b96b --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellsInvalid.json @@ -0,0 +1,23 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "rows": [{ "cells": ["col1", "col2"] }, { "cells": { "foo": "bar" } }] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellsMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellsMissing.json new file mode 100644 index 0000000..09a6918 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/cellsMissing.json @@ -0,0 +1,23 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "rows": [{ "cells": ["col1", "col2"] }, {}] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/dataTables/quotes.json b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/quotes.json new file mode 100644 index 0000000..bce65c0 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/quotes.json @@ -0,0 +1,23 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "rows": [{ "cells": ["col1", "col2"] }, { "cells": ["va\"l1", "\"val2\""] }] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/dataTables/rowInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/rowInvalid.json new file mode 100644 index 0000000..b58ab0d --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/rowInvalid.json @@ -0,0 +1,23 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "rows": [{ "cells": ["col1", "col2"] }, null] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/dataTables/rowsInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/rowsInvalid.json new file mode 100644 index 0000000..195ac83 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/rowsInvalid.json @@ -0,0 +1,23 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "rows": "foo" + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/dataTables/wellDefined.json b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/wellDefined.json new file mode 100644 index 0000000..a5b24be --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/dataTables/wellDefined.json @@ -0,0 +1,23 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "rows": [{ "cells": ["col1", "col2"] }, { "cells": ["val1", "val2"] }] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/descriptions/invalid.json b/packages/reader/test/resources/cucumberjsondata/reference/descriptions/invalid.json new file mode 100644 index 0000000..a4f62b4 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/descriptions/invalid.json @@ -0,0 +1,17 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "description": { "foo": "bar" }, + "keyword": "Scenario", + "name": "Bar", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/descriptions/valid.json b/packages/reader/test/resources/cucumberjsondata/reference/descriptions/valid.json new file mode 100644 index 0000000..68aa0b5 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/descriptions/valid.json @@ -0,0 +1,17 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "description": "Lorem Ipsum", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/docstrings/emptyContentType.json b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/emptyContentType.json new file mode 100644 index 0000000..7bb77f5 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/emptyContentType.json @@ -0,0 +1,29 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "doc_string": { + "value": "Lorem Ipsum", + "content_type": "" + }, + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/docstrings/emptyValue.json b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/emptyValue.json new file mode 100644 index 0000000..6c84cd4 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/emptyValue.json @@ -0,0 +1,28 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "doc_string": { + "value": "" + }, + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/docstrings/explicitContentType.json b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/explicitContentType.json new file mode 100644 index 0000000..f9588eb --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/explicitContentType.json @@ -0,0 +1,29 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "doc_string": { + "value": "\"Lorem Ipsum\"", + "content_type": "application/json" + }, + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/docstrings/missingContentType.json b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/missingContentType.json new file mode 100644 index 0000000..cda6777 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/missingContentType.json @@ -0,0 +1,28 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "doc_string": { + "value": "Lorem Ipsum" + }, + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/docstrings/missingValue.json b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/missingValue.json new file mode 100644 index 0000000..b2f0dd1 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/missingValue.json @@ -0,0 +1,26 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "doc_string": {}, + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/docstrings/whitespaceOnlyValue.json b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/whitespaceOnlyValue.json new file mode 100644 index 0000000..b049f65 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/docstrings/whitespaceOnlyValue.json @@ -0,0 +1,28 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "doc_string": { + "value": " " + }, + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/durations/allDefined.json b/packages/reader/test/resources/cucumberjsondata/reference/durations/allDefined.json new file mode 100644 index 0000000..ac5e469 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/durations/allDefined.json @@ -0,0 +1,34 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "foo", + "result": { + "status": "passed", + "duration": 12499999 + } + }, + { + "keyword": "Then ", + "name": "bar", + "result": { + "status": "passed", + "duration": 12499999 + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/durations/noneDefined.json b/packages/reader/test/resources/cucumberjsondata/reference/durations/noneDefined.json new file mode 100644 index 0000000..aa96a6d --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/durations/noneDefined.json @@ -0,0 +1,39 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "foo", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "bar", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "baz", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/durations/oneInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/durations/oneInvalid.json new file mode 100644 index 0000000..8450da5 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/durations/oneInvalid.json @@ -0,0 +1,42 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "foo", + "result": { + "status": "passed", + "duration": 12499999 + } + }, + { + "keyword": "Then ", + "name": "bar", + "result": { + "status": "passed", + "duration": { "foo": "bar" } + } + }, + { + "keyword": "Then ", + "name": "baz", + "result": { + "status": "passed", + "duration": 12499999 + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/durations/oneMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/durations/oneMissing.json new file mode 100644 index 0000000..1941f1e --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/durations/oneMissing.json @@ -0,0 +1,41 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "foo", + "result": { + "status": "passed", + "duration": 12499999 + } + }, + { + "keyword": "Then ", + "name": "bar", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "baz", + "result": { + "status": "passed", + "duration": 12499999 + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/durations/roundDown.json b/packages/reader/test/resources/cucumberjsondata/reference/durations/roundDown.json new file mode 100644 index 0000000..c9f70e1 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/durations/roundDown.json @@ -0,0 +1,26 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed", + "duration": 12499999 + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/durations/roundUp.json b/packages/reader/test/resources/cucumberjsondata/reference/durations/roundUp.json new file mode 100644 index 0000000..a01d1ed --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/durations/roundUp.json @@ -0,0 +1,26 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed", + "duration": 12500000 + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/durations/strings.json b/packages/reader/test/resources/cucumberjsondata/reference/durations/strings.json new file mode 100644 index 0000000..46a59d1 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/durations/strings.json @@ -0,0 +1,34 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "foo", + "result": { + "status": "passed", + "duration": "12499999" + } + }, + { + "keyword": "Then ", + "name": "bar", + "result": { + "status": "passed", + "duration": "12499999" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataInvalid.json new file mode 100644 index 0000000..9c2a513 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataInvalid.json @@ -0,0 +1,31 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": [ + { + "data": { "foo": "bar" }, + "mime_type": "text/plain" + } + ] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataInvalidBase64.json b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataInvalidBase64.json new file mode 100644 index 0000000..6736fe7 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataInvalidBase64.json @@ -0,0 +1,31 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": [ + { + "data": "???", + "mime_type": "text/plain" + } + ] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataMissing.json new file mode 100644 index 0000000..d3b4706 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/dataMissing.json @@ -0,0 +1,30 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": [ + { + "mime_type": "text/plain" + } + ] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/embeddings/embeddingsElementInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/embeddingsElementInvalid.json new file mode 100644 index 0000000..f294fcc --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/embeddingsElementInvalid.json @@ -0,0 +1,26 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": [null] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/embeddings/embeddingsInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/embeddingsInvalid.json new file mode 100644 index 0000000..318e7b5 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/embeddingsInvalid.json @@ -0,0 +1,26 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": { "foo": "bar" } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/embeddings/mediaTypeInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/mediaTypeInvalid.json new file mode 100644 index 0000000..98362bd --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/mediaTypeInvalid.json @@ -0,0 +1,31 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": [ + { + "data": "SGVsbG8h", + "mime_type": { "foo": "bar" } + } + ] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/embeddings/mediaTypeMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/mediaTypeMissing.json new file mode 100644 index 0000000..61d8090 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/mediaTypeMissing.json @@ -0,0 +1,30 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": [ + { + "data": "SGVsbG8h" + } + ] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/embeddings/twoEmbeddings.json b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/twoEmbeddings.json new file mode 100644 index 0000000..ae87368 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/twoEmbeddings.json @@ -0,0 +1,35 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": [ + { + "data": "SGVsbG8h", + "mime_type": "text/plain" + }, + { + "data": "V29ybGQh", + "mime_type": "text/plain" + } + ] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/embeddings/wellDefined.json b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/wellDefined.json new file mode 100644 index 0000000..3215f3a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/embeddings/wellDefined.json @@ -0,0 +1,31 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + }, + "embeddings": [ + { + "data": "SGVsbG8h", + "mime_type": "text/plain" + } + ] + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureNameEmpty.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureNameEmpty.json new file mode 100644 index 0000000..e8cccd4 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureNameEmpty.json @@ -0,0 +1,16 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureNameInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureNameInvalid.json new file mode 100644 index 0000000..63a0535 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureNameInvalid.json @@ -0,0 +1,16 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": { "foo": "bar" }, + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureNameMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureNameMissing.json new file mode 100644 index 0000000..5a47f7e --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureNameMissing.json @@ -0,0 +1,15 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriEmpty.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriEmpty.json new file mode 100644 index 0000000..918fd3a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriEmpty.json @@ -0,0 +1,16 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriInvalid.json new file mode 100644 index 0000000..f7204db --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriInvalid.json @@ -0,0 +1,16 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": { "foo": "bar" } + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriMissing.json new file mode 100644 index 0000000..002483d --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriMissing.json @@ -0,0 +1,15 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameEmpty.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameEmpty.json new file mode 100644 index 0000000..d127a65 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameEmpty.json @@ -0,0 +1,16 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "id": "foo", + "name": "", + "keyword": "Feature", + "uri": "" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameIdMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameIdMissing.json new file mode 100644 index 0000000..4ce934a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameIdMissing.json @@ -0,0 +1,13 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "keyword": "Feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameIdScenarioIdEmpty.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameIdScenarioIdEmpty.json new file mode 100644 index 0000000..2c918c3 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameIdScenarioIdEmpty.json @@ -0,0 +1,16 @@ +[ + { + "elements": [ + { + "id": "", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "keyword": "Feature", + "id": "", + "name": "", + "uri": "" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameMissing.json new file mode 100644 index 0000000..0e6477a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameMissing.json @@ -0,0 +1,14 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameMissingIdInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameMissingIdInvalid.json new file mode 100644 index 0000000..01e11c4 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameMissingIdInvalid.json @@ -0,0 +1,14 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "keyword": "Feature", + "id": { "foo": "bar" } + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameScenarioNameMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameScenarioNameMissing.json new file mode 100644 index 0000000..ceae59c --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriNameScenarioNameMissing.json @@ -0,0 +1,13 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriScenarioNameMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriScenarioNameMissing.json new file mode 100644 index 0000000..77fc725 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/featureUriScenarioNameMissing.json @@ -0,0 +1,14 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameEmpty.json b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameEmpty.json new file mode 100644 index 0000000..e03e533 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameEmpty.json @@ -0,0 +1,16 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameIdInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameIdInvalid.json new file mode 100644 index 0000000..9916ab2 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameIdInvalid.json @@ -0,0 +1,15 @@ +[ + { + "elements": [ + { + "keyword": "Scenario", + "type": "scenario", + "id": { "foo": "bar" } + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameIdMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameIdMissing.json new file mode 100644 index 0000000..389b343 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameIdMissing.json @@ -0,0 +1,14 @@ +[ + { + "elements": [ + { + "keyword": "Scenario", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameInvalid.json new file mode 100644 index 0000000..1c65888 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameInvalid.json @@ -0,0 +1,16 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": { "value": "Lorem Ipsum" }, + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameMissing.json new file mode 100644 index 0000000..4363b34 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameMissing.json @@ -0,0 +1,15 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameOnly.json b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameOnly.json new file mode 100644 index 0000000..7d3093f --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/scenarioNameOnly.json @@ -0,0 +1,12 @@ +[ + { + "elements": [ + { + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "keyword": "Feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/names/wellDefined.json b/packages/reader/test/resources/cucumberjsondata/reference/names/wellDefined.json new file mode 100644 index 0000000..1a7d325 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/names/wellDefined.json @@ -0,0 +1,16 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/ambiguous.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/ambiguous.json new file mode 100644 index 0000000..d02a463 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/ambiguous.json @@ -0,0 +1,46 @@ +[ + { + "elements": [ + { + "id": "foo;ambiguous-test", + "keyword": "Scenario", + "name": "Ambiguous test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "skip", + "result": { + "status": "skipped" + } + }, + { + "keyword": "Then ", + "name": "ambiguous", + "result": { + "status": "ambiguous" + } + }, + { + "keyword": "Then ", + "name": "unknown", + "result": { + "status": "unknown" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/failed.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/failed.json new file mode 100644 index 0000000..8b50a62 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/failed.json @@ -0,0 +1,53 @@ +[ + { + "elements": [ + { + "id": "foo;failed-test", + "keyword": "Scenario", + "name": "Failed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "fail", + "result": { + "status": "failed" + } + }, + { + "keyword": "Then ", + "name": "skip", + "result": { + "status": "skipped" + } + }, + { + "keyword": "Then ", + "name": "undefined", + "result": { + "status": "undefined" + } + }, + { + "keyword": "Then ", + "name": "unknown", + "result": { + "status": "unknown" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/invalidStepStatus.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/invalidStepStatus.json new file mode 100644 index 0000000..3723684 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/invalidStepStatus.json @@ -0,0 +1,39 @@ +[ + { + "elements": [ + { + "id": "foo;unknown-test", + "keyword": "Scenario", + "name": "Unknown test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "unknown", + "result": { + "status": "bar" + } + }, + { + "keyword": "Then ", + "name": "skip", + "result": { + "status": "skipped" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noStepResult.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noStepResult.json new file mode 100644 index 0000000..51a5110 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noStepResult.json @@ -0,0 +1,36 @@ +[ + { + "elements": [ + { + "id": "foo;unknown-test", + "keyword": "Scenario", + "name": "Unknown test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "unknown" + }, + { + "keyword": "Then ", + "name": "skip", + "result": { + "status": "skipped" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noStepStatus.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noStepStatus.json new file mode 100644 index 0000000..bc98c45 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noStepStatus.json @@ -0,0 +1,37 @@ +[ + { + "elements": [ + { + "id": "foo;unknown-test", + "keyword": "Scenario", + "name": "Unknown test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "unknown", + "result": {} + }, + { + "keyword": "Then ", + "name": "skip", + "result": { + "status": "skipped" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noSteps.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noSteps.json new file mode 100644 index 0000000..45fac89 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/noSteps.json @@ -0,0 +1,16 @@ +[ + { + "elements": [ + { + "id": "foo;missing-status-test", + "keyword": "Scenario", + "name": "Missing steps test", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/passed.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/passed.json new file mode 100644 index 0000000..ebca627 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/passed.json @@ -0,0 +1,39 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Given ", + "name": "pass 1", + "result": { + "status": "passed" + } + }, + { + "keyword": "When ", + "name": "pass 2", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "pass 3", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/pending.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/pending.json new file mode 100644 index 0000000..771118a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/pending.json @@ -0,0 +1,39 @@ +[ + { + "elements": [ + { + "id": "foo;pending-test", + "keyword": "Scenario", + "name": "Pending test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "pend", + "result": { + "status": "pending" + } + }, + { + "keyword": "Then ", + "name": "skip", + "result": { + "status": "skipped" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/skipped.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/skipped.json new file mode 100644 index 0000000..405409a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/skipped.json @@ -0,0 +1,39 @@ +[ + { + "elements": [ + { + "id": "foo;skipped-test", + "keyword": "Scenario", + "name": "Skipped test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "pend", + "result": { + "status": "skipped" + } + }, + { + "keyword": "Then ", + "name": "skip", + "result": { + "status": "skipped" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/undefined.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/undefined.json new file mode 100644 index 0000000..f2f759f --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/undefined.json @@ -0,0 +1,46 @@ +[ + { + "elements": [ + { + "id": "foo;undefined-test", + "keyword": "Scenario", + "name": "Undefined test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "skip", + "result": { + "status": "skipped" + } + }, + { + "keyword": "Then ", + "name": "undefined", + "result": { + "status": "undefined" + } + }, + { + "keyword": "Then ", + "name": "unknown", + "result": { + "status": "unknown" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/unknown.json b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/unknown.json new file mode 100644 index 0000000..d9c2efe --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/scenarioStatuses/unknown.json @@ -0,0 +1,39 @@ +[ + { + "elements": [ + { + "id": "foo;unknown-test", + "keyword": "Scenario", + "name": "Unknown test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + }, + { + "keyword": "Then ", + "name": "unknown", + "result": { + "status": "unknown" + } + }, + { + "keyword": "Then ", + "name": "skip", + "result": { + "status": "skipped" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepNames/keywordInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/keywordInvalid.json new file mode 100644 index 0000000..3203bd2 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/keywordInvalid.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": { "foo": "bar" }, + "name": "pass", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepNames/keywordMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/keywordMissing.json new file mode 100644 index 0000000..93c006f --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/keywordMissing.json @@ -0,0 +1,24 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "name": "pass", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameInvalid.json new file mode 100644 index 0000000..48307bf --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameInvalid.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": "Then ", + "name": { "foo": "bar" }, + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameKeywordMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameKeywordMissing.json new file mode 100644 index 0000000..9f1ed6a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameKeywordMissing.json @@ -0,0 +1,23 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameKeywordWithWhitespaces.json b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameKeywordWithWhitespaces.json new file mode 100644 index 0000000..38e7ceb --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameKeywordWithWhitespaces.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": " Then ", + "name": " pass ", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameMissing.json new file mode 100644 index 0000000..6301b2d --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/nameMissing.json @@ -0,0 +1,24 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": "Then ", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepNames/wellDefined.json b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/wellDefined.json new file mode 100644 index 0000000..95fc124 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepNames/wellDefined.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/ambiguous.json b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/ambiguous.json new file mode 100644 index 0000000..5e4e297 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/ambiguous.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;ambiguous-test", + "keyword": "Scenario", + "name": "Ambiguous test", + "steps": [ + { + "keyword": "Then ", + "name": "multiple", + "result": { + "status": "ambiguous" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/failed.json b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/failed.json new file mode 100644 index 0000000..06bca65 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/failed.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;failed-test", + "keyword": "Scenario", + "name": "Failed test", + "steps": [ + { + "keyword": "Then ", + "name": "fail", + "result": { + "status": "failed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/invalidStatus.json b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/invalidStatus.json new file mode 100644 index 0000000..9823d90 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/invalidStatus.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;failed-test", + "keyword": "Scenario", + "name": "Failed test", + "steps": [ + { + "keyword": "Then ", + "name": "fail", + "result": { + "status": "bar" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/missingResult.json b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/missingResult.json new file mode 100644 index 0000000..8cb2ff3 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/missingResult.json @@ -0,0 +1,22 @@ +[ + { + "elements": [ + { + "id": "foo;missing-status-test", + "keyword": "Scenario", + "name": "Missing status test", + "steps": [ + { + "keyword": "Then ", + "name": "unknown" + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/missingStatus.json b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/missingStatus.json new file mode 100644 index 0000000..b9a30fa --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/missingStatus.json @@ -0,0 +1,23 @@ +[ + { + "elements": [ + { + "id": "foo;unknown-test", + "keyword": "Scenario", + "name": "Unknown test", + "steps": [ + { + "keyword": "Then ", + "name": "nothing", + "result": {} + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/passed.json b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/passed.json new file mode 100644 index 0000000..f1ff371 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/passed.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "the step passes", + "result": { + "status": "passed" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/pending.json b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/pending.json new file mode 100644 index 0000000..770181b --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/pending.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;pending-test", + "keyword": "Scenario", + "name": "Pending test", + "steps": [ + { + "keyword": "Then ", + "name": "signal pending", + "result": { + "status": "pending" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/skipped.json b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/skipped.json new file mode 100644 index 0000000..271935e --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/skipped.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;skipped-test", + "keyword": "Scenario", + "name": "Skipped test", + "steps": [ + { + "keyword": "Then ", + "name": "skip", + "result": { + "status": "skipped" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/undefined.json b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/undefined.json new file mode 100644 index 0000000..f2a0e5a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/undefined.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;undefined-test", + "keyword": "Scenario", + "name": "Undefined test", + "steps": [ + { + "keyword": "Then ", + "name": "undefined", + "result": { + "status": "undefined" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/unknown.json b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/unknown.json new file mode 100644 index 0000000..4ba33f8 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/stepStatuses/unknown.json @@ -0,0 +1,25 @@ +[ + { + "elements": [ + { + "id": "foo;unknown-test", + "keyword": "Scenario", + "name": "Unknown test", + "steps": [ + { + "keyword": "Then ", + "name": "nothing", + "result": { + "status": "unknown" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/tags/feature.json b/packages/reader/test/resources/cucumberjsondata/reference/tags/feature.json new file mode 100644 index 0000000..c2ab026 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/tags/feature.json @@ -0,0 +1,17 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature", + "tags": [{ "name": "tag1" }, { "name": "tag2" }] + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagNameInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagNameInvalid.json new file mode 100644 index 0000000..1ba90f7 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagNameInvalid.json @@ -0,0 +1,21 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature", + "tags": [ + { + "name": { "foo": "bar" } + } + ] + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagNameMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagNameMissing.json new file mode 100644 index 0000000..0f62423 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagNameMissing.json @@ -0,0 +1,17 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature", + "tags": [{}] + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagsElementInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagsElementInvalid.json new file mode 100644 index 0000000..46401fd --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagsElementInvalid.json @@ -0,0 +1,17 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature", + "tags": [null] + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagsInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagsInvalid.json new file mode 100644 index 0000000..48662cb --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/tags/featureTagsInvalid.json @@ -0,0 +1,17 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature", + "tags": { "foo": "bar" } + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/tags/scenario.json b/packages/reader/test/resources/cucumberjsondata/reference/tags/scenario.json new file mode 100644 index 0000000..166990d --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/tags/scenario.json @@ -0,0 +1,17 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario", + "tags": [{ "name": "tag1" }, { "name": "tag2" }] + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagNameInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagNameInvalid.json new file mode 100644 index 0000000..3d0e685 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagNameInvalid.json @@ -0,0 +1,21 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario", + "tags": [ + { + "name": { "foo": "bar" } + } + ] + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagNameMissing.json b/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagNameMissing.json new file mode 100644 index 0000000..1667ddb --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagNameMissing.json @@ -0,0 +1,17 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario", + "tags": [{}] + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagsElementInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagsElementInvalid.json new file mode 100644 index 0000000..0e38d23 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagsElementInvalid.json @@ -0,0 +1,17 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario", + "tags": [null] + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagsInvalid.json b/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagsInvalid.json new file mode 100644 index 0000000..cd7b092 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/tags/scenarioTagsInvalid.json @@ -0,0 +1,17 @@ +[ + { + "elements": [ + { + "id": "foo;bar", + "keyword": "Scenario", + "name": "Bar", + "type": "scenario", + "tags": { "foo": "bar" } + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/traces/failed.json b/packages/reader/test/resources/cucumberjsondata/reference/traces/failed.json new file mode 100644 index 0000000..80f421a --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/traces/failed.json @@ -0,0 +1,26 @@ +[ + { + "elements": [ + { + "id": "foo;failed-test", + "keyword": "Scenario", + "name": "Failed test", + "steps": [ + { + "keyword": "Then ", + "name": "fail", + "result": { + "status": "failed", + "error_message": "Lorem Ipsum" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +] diff --git a/packages/reader/test/resources/cucumberjsondata/reference/traces/passed.json b/packages/reader/test/resources/cucumberjsondata/reference/traces/passed.json new file mode 100644 index 0000000..797b3b9 --- /dev/null +++ b/packages/reader/test/resources/cucumberjsondata/reference/traces/passed.json @@ -0,0 +1,26 @@ +[ + { + "elements": [ + { + "id": "foo;passed-test", + "keyword": "Scenario", + "name": "Passed test", + "steps": [ + { + "keyword": "Then ", + "name": "pass", + "result": { + "status": "passed", + "error_message": "Lorem Ipsum" + } + } + ], + "type": "scenario" + } + ], + "id": "foo", + "keyword": "Feature", + "name": "Foo", + "uri": "features/foo.feature" + } +]