* fix(dev-server): don't open localhost in a browser * tests: refactor model-example enzyme tests to be more isolated * tests: add failing sampleFromSchema tests for $$ref keys * tests: add additional test for user-created $$ref values * fix: create deeplyStripKey; use it to filter $$refs out of examples * tests: add cases for deeplyStripKeybubble
@@ -1,4 +1,4 @@ | |||
import { objectify, isFunc, normalizeArray } from "core/utils" | |||
import { objectify, isFunc, normalizeArray, deeplyStripKey } from "core/utils" | |||
import XML from "xml" | |||
import memoizee from "memoizee" | |||
@@ -29,13 +29,14 @@ export const sampleFromSchema = (schema, config={}) => { | |||
let { type, example, properties, additionalProperties, items } = objectify(schema) | |||
let { includeReadOnly, includeWriteOnly } = config | |||
if(example && example.$$ref) { | |||
delete example.$$ref | |||
if(example !== undefined) { | |||
return deeplyStripKey(example, "$$ref", (val) => { | |||
// do a couple of quick sanity tests to ensure the value | |||
// looks like a $$ref that swagger-client generates. | |||
return typeof val === "string" && val.indexOf("#") > -1 | |||
}) | |||
} | |||
if(example !== undefined) | |||
return example | |||
if(!type) { | |||
if(properties) { | |||
type = "object" | |||
@@ -712,3 +712,25 @@ export const createDeepLinkPath = (str) => typeof str == "string" || str instanc | |||
export const escapeDeepLinkPath = (str) => cssEscape( createDeepLinkPath(str) ) | |||
export const getExtensions = (defObj) => defObj.filter((v, k) => /^x-/.test(k)) | |||
// Deeply strips a specific key from an object. | |||
// | |||
// `predicate` can be used to discriminate the stripping further, | |||
// by preserving the key's place in the object based on its value. | |||
export function deeplyStripKey(input, keyToStrip, predicate = () => true) { | |||
if(typeof input !== "object" || Array.isArray(input) || !keyToStrip) { | |||
return input | |||
} | |||
const obj = Object.assign({}, input) | |||
Object.keys(obj).forEach(k => { | |||
if(k === keyToStrip && predicate(obj[k], k)) { | |||
delete obj[k] | |||
return | |||
} | |||
obj[k] = deeplyStripKey(obj[k], keyToStrip, predicate) | |||
}) | |||
return obj | |||
} |
@@ -6,23 +6,8 @@ import ModelExample from "components/model-example" | |||
import ModelComponent from "components/model-wrapper" | |||
describe("<ModelExample/>", function(){ | |||
// Given | |||
let components = { | |||
ModelWrapper: ModelComponent | |||
} | |||
let props = { | |||
getComponent: (c) => { | |||
return components[c] | |||
}, | |||
specSelectors: {}, | |||
schema: {}, | |||
example: "{\"example\": \"value\"}", | |||
isExecute: false, | |||
getConfigs: () => ({ | |||
defaultModelRendering: "model", | |||
defaultModelExpandDepth: 1 | |||
}) | |||
} | |||
let components, props | |||
let exampleSelectedTestInputs = [ | |||
{ defaultModelRendering: "model", isExecute: true }, | |||
{ defaultModelRendering: "example", isExecute: true }, | |||
@@ -30,10 +15,31 @@ describe("<ModelExample/>", function(){ | |||
{ defaultModelRendering: "othervalue", isExecute: true }, | |||
{ defaultModelRendering: "othervalue", isExecute: false } | |||
] | |||
let modelSelectedTestInputs = [ | |||
{ defaultModelRendering: "model", isExecute: false } | |||
] | |||
beforeEach(() => { | |||
components = { | |||
ModelWrapper: ModelComponent | |||
} | |||
props = { | |||
getComponent: (c) => { | |||
return components[c] | |||
}, | |||
specSelectors: {}, | |||
schema: {}, | |||
example: "{\"example\": \"value\"}", | |||
isExecute: false, | |||
getConfigs: () => ({ | |||
defaultModelRendering: "model", | |||
defaultModelExpandDepth: 1 | |||
}) | |||
} | |||
}) | |||
it("renders model and example tabs", function(){ | |||
// When | |||
@@ -100,6 +100,92 @@ describe("sampleFromSchema", function() { | |||
expect(sampleFromSchema(definition, { includeWriteOnly: true })).toEqual(expected) | |||
}) | |||
it("returns object without any $$ref fields at the root schema level", function () { | |||
var definition = { | |||
type: "object", | |||
properties: { | |||
message: { | |||
type: "string" | |||
} | |||
}, | |||
example: { | |||
value: { | |||
message: "Hello, World!" | |||
}, | |||
$$ref: "#/components/examples/WelcomeExample" | |||
}, | |||
$$ref: "#/components/schemas/Welcome" | |||
} | |||
var expected = { | |||
"value": { | |||
"message": "Hello, World!" | |||
} | |||
} | |||
expect(sampleFromSchema(definition, { includeWriteOnly: true })).toEqual(expected) | |||
}) | |||
it("returns object without any $$ref fields at nested schema levels", function () { | |||
var definition = { | |||
type: "object", | |||
properties: { | |||
message: { | |||
type: "string" | |||
} | |||
}, | |||
example: { | |||
a: { | |||
value: { | |||
message: "Hello, World!" | |||
}, | |||
$$ref: "#/components/examples/WelcomeExample" | |||
} | |||
}, | |||
$$ref: "#/components/schemas/Welcome" | |||
} | |||
var expected = { | |||
a: { | |||
"value": { | |||
"message": "Hello, World!" | |||
} | |||
} | |||
} | |||
expect(sampleFromSchema(definition, { includeWriteOnly: true })).toEqual(expected) | |||
}) | |||
it("returns object with any $$ref fields that appear to be user-created", function () { | |||
var definition = { | |||
type: "object", | |||
properties: { | |||
message: { | |||
type: "string" | |||
} | |||
}, | |||
example: { | |||
$$ref: { | |||
value: { | |||
message: "Hello, World!" | |||
}, | |||
$$ref: "#/components/examples/WelcomeExample" | |||
} | |||
}, | |||
$$ref: "#/components/schemas/Welcome" | |||
} | |||
var expected = { | |||
$$ref: { | |||
"value": { | |||
"message": "Hello, World!" | |||
} | |||
} | |||
} | |||
expect(sampleFromSchema(definition, { includeWriteOnly: true })).toEqual(expected) | |||
}) | |||
describe("for array type", function() { | |||
it("returns array with sample of array type", function() { | |||
var definition = { | |||
@@ -108,12 +194,12 @@ describe("sampleFromSchema", function() { | |||
type: "integer" | |||
} | |||
} | |||
var expected = [ 0 ] | |||
expect(sampleFromSchema(definition)).toEqual(expected) | |||
}) | |||
it("returns array of examples for array that has example", function() { | |||
var definition = { | |||
type: "array", | |||
@@ -122,9 +208,9 @@ describe("sampleFromSchema", function() { | |||
}, | |||
example: "dog" | |||
} | |||
var expected = [ "dog" ] | |||
expect(sampleFromSchema(definition)).toEqual(expected) | |||
}) | |||
@@ -132,16 +218,16 @@ describe("sampleFromSchema", function() { | |||
var definition = { | |||
type: "array", | |||
items: { | |||
type: "string", | |||
type: "string", | |||
}, | |||
example: [ "dog", "cat" ] | |||
} | |||
var expected = [ "dog", "cat" ] | |||
expect(sampleFromSchema(definition)).toEqual(expected) | |||
}) | |||
it("returns array of samples for oneOf type", function() { | |||
var definition = { | |||
type: "array", | |||
@@ -154,9 +240,9 @@ describe("sampleFromSchema", function() { | |||
] | |||
} | |||
} | |||
var expected = [ 0 ] | |||
expect(sampleFromSchema(definition)).toEqual(expected) | |||
}) | |||
@@ -175,9 +261,9 @@ describe("sampleFromSchema", function() { | |||
] | |||
} | |||
} | |||
var expected = [ "string", 0 ] | |||
expect(sampleFromSchema(definition)).toEqual(expected) | |||
}) | |||
@@ -198,12 +284,12 @@ describe("sampleFromSchema", function() { | |||
] | |||
} | |||
} | |||
var expected = [ "dog", 1 ] | |||
expect(sampleFromSchema(definition)).toEqual(expected) | |||
}) | |||
it("returns array of samples for anyOf type", function() { | |||
var definition = { | |||
type: "array", | |||
@@ -216,9 +302,9 @@ describe("sampleFromSchema", function() { | |||
] | |||
} | |||
} | |||
var expected = [ 0 ] | |||
expect(sampleFromSchema(definition)).toEqual(expected) | |||
}) | |||
@@ -237,9 +323,9 @@ describe("sampleFromSchema", function() { | |||
] | |||
} | |||
} | |||
var expected = [ "string", 0 ] | |||
expect(sampleFromSchema(definition)).toEqual(expected) | |||
}) | |||
@@ -260,9 +346,9 @@ describe("sampleFromSchema", function() { | |||
] | |||
} | |||
} | |||
var expected = [ "dog", 1 ] | |||
expect(sampleFromSchema(definition)).toEqual(expected) | |||
}) | |||
}) | |||
@@ -21,7 +21,8 @@ import { | |||
createDeepLinkPath, | |||
escapeDeepLinkPath, | |||
sanitizeUrl, | |||
extractFileNameFromContentDispositionHeader | |||
extractFileNameFromContentDispositionHeader, | |||
deeplyStripKey | |||
} from "core/utils" | |||
import win from "core/window" | |||
@@ -942,6 +943,58 @@ describe("utils", function() { | |||
}) | |||
}) | |||
describe("deeplyStripKey", function() { | |||
it("should filter out a specified key", function() { | |||
const input = { | |||
$$ref: "#/this/is/my/ref", | |||
a: { | |||
$$ref: "#/this/is/my/other/ref", | |||
value: 12345 | |||
} | |||
} | |||
const result = deeplyStripKey(input, "$$ref") | |||
expect(result).toEqual({ | |||
a: { | |||
value: 12345 | |||
} | |||
}) | |||
}) | |||
it("should filter out a specified key by predicate", function() { | |||
const input = { | |||
$$ref: "#/this/is/my/ref", | |||
a: { | |||
$$ref: "#/keep/this/one", | |||
value: 12345 | |||
} | |||
} | |||
const result = deeplyStripKey(input, "$$ref", (v) => v !== "#/keep/this/one") | |||
expect(result).toEqual({ | |||
a: { | |||
value: 12345, | |||
$$ref: "#/keep/this/one" | |||
} | |||
}) | |||
}) | |||
it("should only call the predicate when the key matches", function() { | |||
const input = { | |||
$$ref: "#/this/is/my/ref", | |||
a: { | |||
$$ref: "#/this/is/my/other/ref", | |||
value: 12345 | |||
} | |||
} | |||
let count = 0 | |||
const result = deeplyStripKey(input, "$$ref", () => { | |||
count++ | |||
return true | |||
}) | |||
expect(count).toEqual(2) | |||
}) | |||
}) | |||
describe("parse and serialize search", function() { | |||
afterEach(function() { | |||
win.location.search = "" | |||